diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 15:05:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:33:47 +0000 |
commit | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch) | |
tree | d55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/chrome/browser/resources/welcome | |
parent | 2b94bfe47ccb6c08047959d1c26e392919550e86 (diff) | |
download | qtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz |
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/chrome/browser/resources/welcome')
83 files changed, 2811 insertions, 668 deletions
diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/BUILD.gn b/chromium/chrome/browser/resources/welcome/onboarding_welcome/BUILD.gn new file mode 100644 index 00000000000..01c8a3b7cde --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/BUILD.gn @@ -0,0 +1,95 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +group("closure_compile") { + deps = [ + ":welcome_files", + "./email:closure_compile", + "./google_apps:closure_compile", + "./set_as_default:closure_compile", + ] +} + +js_type_check("welcome_files") { + deps = [ + ":email_interstitial", + ":landing_view", + ":signin_view", + ":welcome_app", + ] +} + +js_library("email_interstitial") { + deps = [ + ":email_interstitial_proxy", + ":welcome_browser_proxy", + "./email/:nux_email_proxy", + ] +} + +js_library("email_interstitial_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/metrics_private.js" ] +} + +js_library("landing_view") { + deps = [ + ":landing_view_proxy", + ":navigation_behavior", + ":welcome_browser_proxy", + ] +} + +js_library("landing_view_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/metrics_private.js" ] +} + +js_library("signin_view") { + deps = [ + ":navigation_behavior", + ":signin_view_proxy", + ":welcome_browser_proxy", + "./email/:nux_email_proxy", + ] +} + +js_library("signin_view_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/metrics_private.js" ] +} + +js_library("navigation_behavior") { + deps = [ + "//ui/webui/resources/js:cr", + ] +} + +js_library("welcome_app") { + deps = [ + ":navigation_behavior", + ":welcome_browser_proxy", + "./set_as_default/:nux_set_as_default_proxy", + "./shared:bookmark_proxy", + "./shared:nux_types", + "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:promise_resolver", + ] +} + +js_library("welcome_browser_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/chrome_send.js" ] +} diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/BUILD.gn b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/BUILD.gn index 957d2071f3a..cb447f40fd0 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/BUILD.gn +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/BUILD.gn @@ -6,10 +6,42 @@ import("//third_party/closure_compiler/compile_js.gni") js_type_check("closure_compile") { deps = [ + ":email_chooser", ":nux_email", ] } js_library("nux_email") { - deps = [] + deps = [ + ":email_chooser", + "../:navigation_behavior", + "../shared:nux_types", + ] +} + +js_library("email_chooser") { + deps = [ + ":nux_email_proxy", + "../:navigation_behavior", + "../shared:bookmark_proxy", + "../shared:module_metrics_proxy", + "../shared:nux_types", + "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", + "//ui/webui/resources/js:load_time_data", + ] +} + +js_library("nux_email_proxy") { + deps = [ + "../shared:nux_types", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:load_time_data", + ] + externs_list = [ + "$externs_path/chrome_extensions.js", + "$externs_path/chrome_send.js", + "$externs_path/metrics_private.js", + ] } diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.html index 6b65f425ded..dac1105c7a9 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.html @@ -1,51 +1,56 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> -<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://welcome/email/nux_email_proxy.html"> -<link rel="import" href="chrome://welcome/shared/chooser_shared_css.html"> +<link rel="import" href="../navigation_behavior.html"> +<link rel="import" href="../shared/bookmark_proxy.html"> +<link rel="import" href="../shared/chooser_shared_css.html"> +<link rel="import" href="../shared/step_indicator.html"> +<link rel="import" href="nux_email_proxy.html"> <dom-module id="email-chooser"> <template> <style include="chooser-shared-css paper-button-style"> .gmail { background-image: -webkit-image-set( - url(chrome://welcome/email/gmail_1x.png) 1x, - url(chrome://welcome/email/gmail_2x.png) 2x); + url(chrome://welcome/images/gmail_1x.png) 1x, + url(chrome://welcome/images/gmail_2x.png) 2x); } .yahoo { background-image: -webkit-image-set( - url(chrome://welcome/email/yahoo_1x.png) 1x, - url(chrome://welcome/email/yahoo_2x.png) 2x); + url(chrome://welcome/images/yahoo_1x.png) 1x, + url(chrome://welcome/images/yahoo_2x.png) 2x); } .aol { background-image: -webkit-image-set( - url(chrome://welcome/email/aol_1x.png) 1x, - url(chrome://welcome/email/aol_2x.png) 2x); + url(chrome://welcome/images/aol_1x.png) 1x, + url(chrome://welcome/images/aol_2x.png) 2x); } .icloud { background-image: -webkit-image-set( - url(chrome://welcome/email/icloud_1x.png) 1x, - url(chrome://welcome/email/icloud_2x.png) 2x); + url(chrome://welcome/images/icloud_1x.png) 1x, + url(chrome://welcome/images/icloud_2x.png) 2x); } .outlook { background-image: -webkit-image-set( - url(chrome://welcome/email/outlook_1x.png) 1x, - url(chrome://welcome/email/outlook_2x.png) 2x); + url(chrome://welcome/images/outlook_1x.png) 1x, + url(chrome://welcome/images/outlook_2x.png) 2x); } </style> - <template is="dom-repeat" items="[[emailList]]"> + <template is="dom-repeat" items="[[emailList_]]"> <button active$="[[getSelected_(item, selectedEmailProvider_)]]" + aria-pressed$="[[getAriaPressed_(item, selectedEmailProvider_)]]" on-click="onEmailClick_" on-pointerdown="onEmailPointerDown_" on-keyup="onEmailKeyUp_" class="option"> <div class="option-icon-shadow"> @@ -57,13 +62,15 @@ </template> <div class="button-bar"> - <paper-button on-click="onNoThanksClicked_"> - $i18n{noThanks} + <paper-button on-click="onNoThanksClicked_" id="noThanksButton"> + $i18n{skip} </paper-button> + <step-indicator model="[[indicatorModel]]"></step-indicator> <div on-click="onActionButtonClicked_"> <paper-button class="action-button" on-click="onGetStartedClicked_" disabled="[[!selectedEmailProvider_]]"> - $i18n{getStarted} + $i18n{next} + <iron-icon icon="cr:chevron-right"></iron-icon> </paper-button> </div> </div> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.js index 1bbe6d39909..3d4199e1479 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/email_chooser.js @@ -2,17 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** - * @const - */ -var nuxEmail = nuxEmail || {}; +cr.exportPath('nuxEmail'); /** - * @typedef {?{ - * name: string, - * icon: string, - * url: string, - * bookmarkId: (string|undefined), + * @typedef {{ + * id: number, + * name: string, + * icon: string, + * url: string, + * bookmarkId: (string|undefined|null), * }} */ nuxEmail.EmailProviderModel; @@ -23,27 +21,42 @@ Polymer({ behaviors: [I18nBehavior], properties: { - emailList: Array, - - /** @private */ - bookmarkBarWasShown_: { - type: Boolean, - value: loadTimeData.getBoolean('bookmark_bar_shown'), - }, + /** + * @type {!Array<!nux.BookmarkListItem>} + * @private + */ + emailList_: Array, /** @private */ finalized_: Boolean, - /** @private {nuxEmail.EmailProviderModel} */ + /** @type {nux.stepIndicatorModel} */ + indicatorModel: Object, + + /** @private {?nuxEmail.EmailProviderModel} */ selectedEmailProvider_: { type: Object, - value: () => null, observer: 'onSelectedEmailProviderChange_', }, }, /** @private {nux.NuxEmailProxy} */ - browserProxy_: null, + emailProxy_: null, + + /** @private {nux.BookmarkProxy} */ + bookmarkProxy_: null, + + /** @private {nux.BookmarkBarManager} */ + bookmarkBarManager_: null, + + /** @private {boolean} */ + wasBookmarkBarShownOnInit_: false, + + /** @private {Promise} */ + listInitialized_: null, + + /** @private {?nux.ModuleMetricsManager} */ + metricsManager_: null, /** @override */ attached: function() { @@ -54,25 +67,63 @@ Polymer({ /** @override */ ready: function() { - this.browserProxy_ = nux.NuxEmailProxyImpl.getInstance(); - this.browserProxy_.recordPageInitialized(); + this.emailProxy_ = nux.NuxEmailProxyImpl.getInstance(); + this.bookmarkProxy_ = nux.BookmarkProxyImpl.getInstance(); + this.bookmarkBarManager_ = nux.BookmarkBarManager.getInstance(); + this.metricsManager_ = + new nux.ModuleMetricsManager(nux.EmailMetricsProxyImpl.getInstance()); - this.emailList = this.browserProxy_.getEmailList(); + this.listInitialized_ = this.emailProxy_.getEmailList().then(list => { + this.emailList_ = list; + }); + }, - window.addEventListener('beforeunload', () => { - // Only need to clean up if user didn't interact with the buttons. - if (this.finalized_) - return; + onRouteEnter: function() { + this.wasBookmarkBarShownOnInit_ = this.bookmarkBarManager_.getShown(); + this.metricsManager_.recordPageInitialized(); + this.finalized_ = false; - if (this.selectedEmailProvider_) { - this.browserProxy_.recordProviderSelected( - this.selectedEmailProvider_.id); + assert(this.listInitialized_); + this.listInitialized_.then(() => { + // If selectedEmailProvider_ was never initialized, and not explicitly + // cancelled by the user at some point (in which case it would be null), + // then default to the first option. + if (this.selectedEmailProvider_ === undefined) { + this.selectedEmailProvider_ = this.emailList_[0]; } - this.browserProxy_.recordFinalize(); + if (this.selectedEmailProvider_) { + this.addBookmark_(this.selectedEmailProvider_); + } }); }, + onRouteExit: function() { + if (this.finalized_) + return; + this.cleanUp_(); + this.metricsManager_.recordBrowserBackOrForward(); + }, + + onRouteUnload: function() { + if (this.finalized_) + return; + this.cleanUp_(); + this.metricsManager_.recordNavigatedAway(); + }, + + /** + * Removes any bookarks and hides the bookmark bar when finalizing. + * @private + */ + cleanUp_: function() { + this.finalized_ = true; + if (this.selectedEmailProvider_) { + this.revertBookmark_(); + this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_); + } + }, + /** * Handle toggling the email selected. * @param {!{model: {item: !nuxEmail.EmailProviderModel}}} e @@ -84,7 +135,7 @@ Polymer({ else this.selectedEmailProvider_ = e.model.item; - this.browserProxy_.recordClickedOption(); + this.metricsManager_.recordClickedOption(); }, /** @@ -103,21 +154,52 @@ Polymer({ e.currentTarget.classList.add('keyboard-focused'); }, - /** @private */ + /** + * Returns whether |item| is selected or not. + * @param {!nuxEmail.EmailProviderModel} item + * @return boolean + * @private + */ getSelected_: function(item) { return this.selectedEmailProvider_ && item.name === this.selectedEmailProvider_.name; }, /** - * @param {nuxEmail.EmailProviderModel=} emailProvider + * @param {nuxEmail.EmailProviderModel} emailProvider + * @private + */ + addBookmark_: function(emailProvider) { + if (emailProvider.bookmarkId) + return; + + // Indicates that the emailProvider is being added as a bookmark. + emailProvider.bookmarkId = 'pending'; + + this.emailProxy_.cacheBookmarkIcon(emailProvider.id); + this.bookmarkBarManager_.setShown(true); + this.bookmarkProxy_.addBookmark( + { + title: emailProvider.name, + url: emailProvider.url, + parentId: '1', + }, + results => { + this.selectedEmailProvider_.bookmarkId = results.id; + }); + }, + + /** + * @param {nuxEmail.EmailProviderModel=} opt_emailProvider * @private */ - revertBookmark_: function(emailProvider) { - emailProvider = emailProvider || this.selectedEmailProvider_; + revertBookmark_: function(opt_emailProvider) { + const emailProvider = opt_emailProvider || this.selectedEmailProvider_; - if (emailProvider && emailProvider.bookmarkId) - this.browserProxy_.removeBookmark(emailProvider.bookmarkId); + if (emailProvider && emailProvider.bookmarkId) { + this.bookmarkProxy_.removeBookmark(emailProvider.bookmarkId); + emailProvider.bookmarkId = null; + } }, /** @@ -126,7 +208,7 @@ Polymer({ * @private */ onSelectedEmailProviderChange_: function(newEmail, prevEmail) { - if (!this.browserProxy_) + if (!this.emailProxy_ || !this.bookmarkProxy_) return; if (prevEmail) { @@ -135,20 +217,10 @@ Polymer({ this.revertBookmark_(prevEmail); } - if (newEmail) { - this.browserProxy_.toggleBookmarkBar(true); - this.browserProxy_.addBookmark( - { - title: newEmail.name, - url: newEmail.url, - parentId: '1', - }, - newEmail.id, results => { - this.selectedEmailProvider_.bookmarkId = results.id; - }); - } else { - this.browserProxy_.toggleBookmarkBar(this.bookmarkBarWasShown_); - } + if (newEmail) + this.addBookmark_(newEmail); + else + this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_); // Announcements are mutually exclusive, so keeping separate. if (prevEmail && newEmail) { @@ -162,24 +234,33 @@ Polymer({ /** @private */ onNoThanksClicked_: function() { - this.finalized_ = true; - this.revertBookmark_(); - this.browserProxy_.toggleBookmarkBar(this.bookmarkBarWasShown_); - this.browserProxy_.recordNoThanks(); - window.location.replace('chrome://newtab'); + this.cleanUp_(); + this.metricsManager_.recordNoThanks(); + welcome.navigateToNextStep(); }, /** @private */ onGetStartedClicked_: function() { this.finalized_ = true; - this.browserProxy_.recordProviderSelected(this.selectedEmailProvider_.id); - this.browserProxy_.recordGetStarted(); - window.location.replace(this.selectedEmailProvider_.url); + this.emailProxy_.recordProviderSelected( + this.selectedEmailProvider_.id, this.emailList_.length); + this.metricsManager_.recordGetStarted(); + welcome.navigateToNextStep(); }, /** @private */ onActionButtonClicked_: function() { if (this.$$('.action-button').disabled) - this.browserProxy_.recordClickedDisabledButton(); + this.metricsManager_.recordClickedDisabledButton(); }, -});
\ No newline at end of file + + /** + * Converts a boolean to a string because aria-pressed needs a string value. + * @param {!nuxEmail.EmailProviderModel} item + * @return {string} + * @private + */ + getAriaPressed_: function(item) { + return this.getSelected_(item) ? 'true' : 'false'; + } +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html index 40789091171..743d00668af 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html @@ -1,76 +1,41 @@ -<!DOCTYPE html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> -<head> - <meta charset="utf-8"> - <title>$i18n{headerText}</title> - <link rel="import" href="chrome://resources/html/polymer.html"> - <link rel="import" href="chrome://welcome/email/email_chooser.html"> - <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> - <style> - body { - margin: 0; - } - </style> +<link rel="import" href="chrome://resources/html/polymer.html"> - <dom-module id="nux-email"> - <template> - <style> - :host { - align-items: center; - display: flex; - height: fit-content; - margin: auto; - min-height: 100vh; - width: fit-content; - } +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="../navigation_behavior.html"> +<link rel="import" href="email_chooser.html"> - .email-ask { - text-align: center; - } +<dom-module id="nux-email"> + <template> + <style> + .email-ask { + text-align: center; + } - .email-logo { - content: -webkit-image-set( - url('chrome://welcome/logo.png') 1x, - url('chrome://welcome/logo2x.png') 2x); - height: 48px; - margin: auto; - margin-bottom: 16px; - width: 48px; - } + .email-logo { + content: -webkit-image-set( + url(../images/email_provider_1x.png) 1x, + url(../images/email_provider_2x.png) 2x); + height: 38px; + margin: auto; + margin-bottom: 16px; + width: 42px; + } - h1 { - color: #202124; - font-weight: 500; - font-size: 1.5rem; - line-height: 2.5rem; - margin: 0; - } - - h2 { - color: #202124; - font-weight: unset; - font-size: 1.125rem; - line-height: 2rem; - margin: 0; - margin-bottom: 48px; - } - - #emailChooser { - color: #202124; - margin-bottom: 48px; - } - </style> - <div class="email-ask"> - <div class="email-logo" alt=""></div> - <h1>$i18n{welcomeTitle}</h1> - <h2>$i18n{emailPrompt}</h2> - <email-chooser id="emailChooser"></email-chooser> - </div> - </template> - <script src="email/nux_email.js"></script> - </dom-module> -</head> -<body> - <nux-email></nux-email> -</body> -</html>
\ No newline at end of file + h1 { + color: var(--google-grey-900); + font-size: 1.5rem; + font-weight: 500; + margin: 0; + margin-bottom: 48px; + outline: none; + } + </style> + <div class="email-ask"> + <div class="email-logo" alt=""></div> + <h1 tabindex="-1">$i18n{emailProviderTitle}</h1> + <email-chooser id="emailChooser" indicator-model="[[indicatorModel]]"> + </email-chooser> + </div> + </template> + <script src="nux_email.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.js index 51d0a434c9d..5dc72237614 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.js @@ -4,4 +4,23 @@ Polymer({ is: 'nux-email', + + behaviors: [welcome.NavigationBehavior], + + properties: { + /** @type {nux.stepIndicatorModel} */ + indicatorModel: Object, + }, + + onRouteEnter: function() { + this.$.emailChooser.onRouteEnter(); + }, + + onRouteExit: function() { + this.$.emailChooser.onRouteExit(); + }, + + onRouteUnload: function() { + this.$.emailChooser.onRouteUnload(); + }, }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html index b9d49f9208c..ee626043fb5 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html @@ -1,3 +1,4 @@ <link rel="import" href="chrome://resources/html/cr.html"> -<link rel="import" href="../shared/i18n_setup.html"> -<script src="nux_email_proxy.js"></script>
\ No newline at end of file +<link rel="import" href="chrome://welcome/shared/i18n_setup.html"> +<link rel="import" href="chrome://welcome/shared/module_metrics_proxy.html"> +<script src="nux_email_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.js index 907d3c70f97..ec7ba194e73 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.js @@ -3,180 +3,64 @@ // found in the LICENSE file. cr.define('nux', function() { - // The metrics name corresponding to Nux EmailProvidersInteraction histogram. - const INTERACTION_METRIC_NAME = - 'FirstRun.NewUserExperience.EmailProvidersInteraction'; - - const SELECTION_METRIC_NAME = + const EMAIL_SELECTION_METRIC_NAME = 'FirstRun.NewUserExperience.EmailProvidersSelection'; - /** - * NuxEmailProvidersInteractions enum. - * These values are persisted to logs and should not be renumbered or re-used. - * See tools/metrics/histograms/enums.xml. - * @enum {number} - */ - const NuxEmailProvidersInteractions = { - PageShown: 0, - DidNothingAndNavigatedAway: 1, - DidNothingAndChoseSkip: 2, - ChoseAnOptionAndNavigatedAway: 3, - ChoseAnOptionAndChoseSkip: 4, - ChoseAnOptionAndChoseNext: 5, - ClickedDisabledNextButtonAndNavigatedAway: 6, - ClickedDisabledNextButtonAndChoseSkip: 7, - ClickedDisabledNextButtonAndChoseNext: 8, - }; - - /** - * The number of enum values in NuxEmailProvidersInteractions. This should - * be kept in sync with the enum count in tools/metrics/histograms/enums.xml. - * @type {number} - */ - const INTERACTION_METRIC_COUNT = - Object.keys(NuxEmailProvidersInteractions).length; - - /** - * @typedef {{ - * parentId: string, - * title: string, - * url: string, - * }} - */ - let bookmarkData; - /** @interface */ class NuxEmailProxy { - /** @param {string} id ID provided by callback when bookmark was added. */ - removeBookmark(id) {} - /** - * @param {!bookmarkData} data + * Email provider IDs are local to the list of email providers, so their + * icon must be cached by the handler that provided the IDs. * @param {number} emailProviderId - * @param {!Function} callback */ - addBookmark(data, emailProviderId, callback) {} - - /** @param {boolean} show */ - toggleBookmarkBar(show) {} + cacheBookmarkIcon(emailProviderId) {} - /** @return {!Array<Object>} Array of email providers. */ + /** + * Returns a promise for an array of email providers. + * @return {!Promise<!Array<!nux.BookmarkListItem>>} + */ getEmailList() {} - recordPageInitialized() {} - - recordClickedOption() {} - - recordClickedDisabledButton() {} + /** @return {number} */ + getSavedProvider() {} /** * @param {number} providerId This should match one of the histogram enum * value for NuxEmailProvidersSelections. + * @param {number} length */ - recordProviderSelected(providerId) {} - - recordNoThanks() {} - - recordGetStarted() {} - - recordFinalize() {} + recordProviderSelected(providerId, length) {} } /** @implements {nux.NuxEmailProxy} */ class NuxEmailProxyImpl { constructor() { - /** @private {string} */ - this.firstPart = ''; - - /** @private {string} */ - this.lastPart = ''; + /** @private {number} */ + this.savedProvider_; } /** @override */ - removeBookmark(id) { - chrome.bookmarks.remove(id); - } - - /** @override */ - addBookmark(data, emailProviderId, callback) { - chrome.bookmarks.create(data, callback); + cacheBookmarkIcon(emailProviderId) { chrome.send('cacheEmailIcon', [emailProviderId]); } /** @override */ - toggleBookmarkBar(show) { - chrome.send('toggleBookmarkBar', [show]); - } - - /** @override */ getEmailList() { - let emailCount = loadTimeData.getInteger('email_count'); - let emailList = []; - for (let i = 0; i < emailCount; ++i) { - emailList.push({ - id: loadTimeData.getValue(`email_id_${i}`), - name: loadTimeData.getString(`email_name_${i}`), - icon: loadTimeData.getString(`email_name_${i}`).toLowerCase(), - url: loadTimeData.getString(`email_url_${i}`) - }); - } - return emailList; - } - - /** @override */ - recordPageInitialized() { - chrome.metricsPrivate.recordEnumerationValue( - INTERACTION_METRIC_NAME, NuxEmailProvidersInteractions.PageShown, - INTERACTION_METRIC_COUNT); - - // These two flags are used at the end to determine what to record in - // metrics. Their values should map to first or last half of an enum - // name within NuxEmailProvidersInteractions. - this.firstPart = 'DidNothing'; - this.lastPart = 'AndNavigatedAway'; - } - - /** @override */ - recordClickedOption() { - // Only overwrite this.firstPart if it's not overwritten already - if (this.firstPart == 'DidNothing') - this.firstPart = 'ChoseAnOption'; - } - - /** @override */ - recordClickedDisabledButton() { - // Only overwrite this.firstPart if it's not overwritten already - if (this.firstPart == 'DidNothing') - this.firstPart = 'ClickedDisabledNextButton'; - } - - /** @override */ - recordProviderSelected(providerId) { - chrome.metricsPrivate.recordEnumerationValue( - SELECTION_METRIC_NAME, providerId, - loadTimeData.getInteger('email_count')); + return cr.sendWithPromise('getEmailList'); } /** @override */ - recordNoThanks() { - this.lastPart = 'AndChoseSkip'; - this.recordFinalize(); + getSavedProvider() { + return this.savedProvider_; } /** @override */ - recordGetStarted() { - this.lastPart = 'AndChoseNext'; - this.recordFinalize(); - } - - /** @override */ - recordFinalize() { - let finalValue = this.firstPart + this.lastPart; - + recordProviderSelected(providerId, length) { + this.savedProvider_ = providerId; chrome.metricsPrivate.recordEnumerationValue( - INTERACTION_METRIC_NAME, NuxEmailProvidersInteractions[finalValue], - INTERACTION_METRIC_COUNT); + EMAIL_SELECTION_METRIC_NAME, providerId, + loadTimeData.getInteger('email_providers_enum_count')); } } @@ -186,4 +70,4 @@ cr.define('nux', function() { NuxEmailProxy: NuxEmailProxy, NuxEmailProxyImpl: NuxEmailProxyImpl, }; -});
\ No newline at end of file +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.html new file mode 100644 index 00000000000..f3bd4e1b341 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.html @@ -0,0 +1,58 @@ +<!doctype html> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> + <head> + <meta charset="utf-8"> + <title>$i18n{headerText}</title> + + <link rel="import" href="chrome://resources/html/polymer.html"> + + <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> + <link rel="import" href="chrome://resources/html/assert.html"> + <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> + <link rel="import" href="email/nux_email_proxy.html"> + <link rel="import" href="email_interstitial_proxy.html"> + <link rel="import" href="shared/action_link_style_css.html"> + <link rel="import" href="shared/onboarding_background.html"> + <link rel="import" href="shared/splash_pages_shared_css.html"> + <link rel="import" href="welcome_browser_proxy.html"> + + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + <style> + body { + margin: 0; + } + </style> + + <dom-module id="email-interstitial"> + <template> + <style include="paper-button-style action-link-style splash-pages-shared-css"> + :host { + align-items: center; + display: flex; + height: 100vh; + justify-content: center; + } + + h1 { + margin-top: 0; + outline: none; + } + </style> + <onboarding-background></onboarding-background> + <div id="container"> + <h1 tabindex="-1">$i18n{emailInterstitialTitle}</h1> + <paper-button class="action-button" on-click="onContinueClick_"> + $i18n{emailInterstitialContinue} + </paper-button> + <button class="action-link" on-click="onNoThanksClick_"> + $i18n{noThanks} + </button> + </div> + </template> + <script src="email_interstitial.js"></script> + </dom-module> + </head> + <body> + <email-interstitial></email-interstitial> + </body> +</html> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.js new file mode 100644 index 00000000000..9a121942dba --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial.js @@ -0,0 +1,72 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview When user gets to chrome://welcome/email-interstitial, it will + * also have a ?provider=... url param. This value is an ID that should match + * one of the provider in the email list retrieved from the backend. If the user + * chooses the continue button, they should be directed to the landing page of + * that email provider. + */ +Polymer({ + is: 'email-interstitial', + + /** @private */ + welcomeBrowserProxy_: null, + + /** @private {?nux.EmailInterstitialProxy} */ + emailInterstitialProxy_: null, + + /** @private {boolean} */ + finalized_: false, + + /** @override */ + ready: function() { + this.welcomeBrowserProxy_ = welcome.WelcomeBrowserProxyImpl.getInstance(); + this.emailInterstitialProxy_ = nux.EmailInterstitialProxyImpl.getInstance(); + this.emailInterstitialProxy_.recordPageShown(); + + window.addEventListener('beforeunload', () => { + // Both buttons on this page will navigate to a new URL. + if (this.finalized_) { + return; + } + this.finalized_ = true; + this.emailInterstitialProxy_.recordNavigatedAway(); + }); + }, + + /** @override */ + attached: function() { + // Focus heading for accessibility. + this.$$('h1').focus(); + }, + + /** @private */ + onContinueClick_: function() { + this.finalized_ = true; + this.emailInterstitialProxy_.recordNext(); + const providerId = + (new URL(window.location.href)).searchParams.get('provider'); + nux.NuxEmailProxyImpl.getInstance().getEmailList().then(list => { + for (let i = 0; i < list.length; i++) { + if (list[i].id == providerId) { + this.welcomeBrowserProxy_.goToURL(list[i].url); + return; + } + } + + // It shouldn't be possible to go to a URL with a non-existent provider + // id. + assertNotReached(); + }); + }, + + /** @private */ + onNoThanksClick_: function() { + this.finalized_ = true; + this.emailInterstitialProxy_.recordSkip(); + this.welcomeBrowserProxy_.goToNewTabPage(); + } +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.html new file mode 100644 index 00000000000..5147b5e2ea8 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="email_interstitial_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.js new file mode 100644 index 00000000000..786a1d10fd6 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/email_interstitial_proxy.js @@ -0,0 +1,75 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('nux', function() { + const NUX_EMAIL_INTERSTITIAL_INTERACTION_METRIC_NAME = + 'FirstRun.NewUserExperience.EmailInterstitialInteraction'; + + /** + * NuxEmailInterstitialInteractions enum. + * These values are persisted to logs and should not be renumbered or re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxEmailInterstitialInteractions = { + PageShown: 0, + NavigatedAway: 1, + Skip: 2, + Next: 3, + }; + + const NUX_EMAIL_INTERSTITIAL_INTERACTIONS_COUNT = + Object.keys(NuxEmailInterstitialInteractions).length; + + /** @interface */ + class EmailInterstitialProxy { + recordPageShown() {} + + recordNavigatedAway() {} + + recordSkip() {} + + recordNext() {} + } + + /** @implements {nux.EmailInterstitialProxy} */ + class EmailInterstitialProxyImpl { + /** @override */ + recordPageShown() { + this.recordInteraction_(NuxEmailInterstitialInteractions.PageShown); + } + + /** @override */ + recordNavigatedAway() { + this.recordInteraction_(NuxEmailInterstitialInteractions.NavigatedAway); + } + + /** @override */ + recordSkip() { + this.recordInteraction_(NuxEmailInterstitialInteractions.Skip); + } + + /** @override */ + recordNext() { + this.recordInteraction_(NuxEmailInterstitialInteractions.Next); + } + + /** + * @param {number} interaction + * @private + */ + recordInteraction_(interaction) { + chrome.metricsPrivate.recordEnumerationValue( + NUX_EMAIL_INTERSTITIAL_INTERACTION_METRIC_NAME, interaction, + NUX_EMAIL_INTERSTITIAL_INTERACTIONS_COUNT); + } + } + + cr.addSingletonGetter(EmailInterstitialProxyImpl); + + return { + EmailInterstitialProxy: EmailInterstitialProxy, + EmailInterstitialProxyImpl: EmailInterstitialProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn index c2ce56522bf..505478a0997 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn @@ -12,16 +12,28 @@ js_type_check("closure_compile") { } js_library("apps_chooser") { - deps = [] + deps = [ + ":nux_google_apps_proxy", + "../shared:bookmark_proxy", + "../shared:module_metrics_proxy", + "../shared:step_indicator", + "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", + ] } js_library("nux_google_apps") { deps = [ ":apps_chooser", - ":nux_google_apps_proxy", + "../:navigation_behavior", + "../shared:nux_types", ] } js_library("nux_google_apps_proxy") { - deps = [] + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/chrome_send.js" ] } diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html index 2987f25a43e..c0105ba04b6 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html @@ -1,53 +1,62 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://welcome/shared/chooser_shared_css.html"> +<link rel="import" href="../navigation_behavior.html"> +<link rel="import" href="../shared/bookmark_proxy.html"> +<link rel="import" href="../shared/chooser_shared_css.html"> +<link rel="import" href="../shared/step_indicator.html"> +<link rel="import" href="nux_google_apps_proxy.html"> <dom-module id="apps-chooser"> <template> - <style include="chooser-shared-css"> + <style include="chooser-shared-css paper-button-style"> .gmail { content: -webkit-image-set( - url(chrome://welcome/apps/gmail_1x.png) 1x, - url(chrome://welcome/apps/gmail_2x.png) 2x); + url(chrome://welcome/images/gmail_1x.png) 1x, + url(chrome://welcome/images/gmail_2x.png) 2x); } .youtube { content: -webkit-image-set( - url(chrome://welcome/apps/youtube_1x.png) 1x, - url(chrome://welcome/apps/youtube_2x.png) 2x); + url(chrome://welcome/images/youtube_1x.png) 1x, + url(chrome://welcome/images/youtube_2x.png) 2x); } .maps { content: -webkit-image-set( - url(chrome://welcome/apps/maps_1x.png) 1x, - url(chrome://welcome/apps/maps_2x.png) 2x); + url(chrome://welcome/images/maps_1x.png) 1x, + url(chrome://welcome/images/maps_2x.png) 2x); } .translate { content: -webkit-image-set( - url(chrome://welcome/apps/translate_1x.png) 1x, - url(chrome://welcome/apps/translate_2x.png) 2x); + url(chrome://welcome/images/translate_1x.png) 1x, + url(chrome://welcome/images/translate_2x.png) 2x); } .news { content: -webkit-image-set( - url(chrome://welcome/apps/news_1x.png) 1x, - url(chrome://welcome/apps/news_2x.png) 2x); + url(chrome://welcome/images/news_1x.png) 1x, + url(chrome://welcome/images/news_2x.png) 2x); } - .chrome-store { + .web-store { content: -webkit-image-set( - url(chrome://welcome/apps/chrome_store_1x.png) 1x, - url(chrome://welcome/apps/chrome_store_2x.png) 2x); + url(chrome://welcome/images/chrome_store_1x.png) 1x, + url(chrome://welcome/images/chrome_store_2x.png) 2x); } </style> - <template is="dom-repeat" items="[[appList]]"> + <template is="dom-repeat" items="[[appList_]]"> <button active$="[[item.selected]]" + aria-pressed$="[[getAriaPressed_(item.selected)]]" on-click="onAppClick_" on-pointerdown="onAppPointerDown_" on-keyup="onAppKeyUp_" class="option"> <div class="option-icon-shadow"> @@ -57,6 +66,18 @@ <iron-icon icon="cr:check"></iron-icon> </button> </template> + + <div class="button-bar"> + <paper-button on-click="onNoThanksClicked_"> + $i18n{skip} + </paper-button> + <step-indicator model="[[indicatorModel]]"></step-indicator> + <paper-button class="action-button" disabled$="[[!hasAppsSelected_]]" + on-click="onGetStartedClicked_"> + $i18n{next} + <iron-icon icon="cr:chevron-right"></iron-icon> + </paper-button> + </div> </template> <script src="apps_chooser.js"></script> -</dom-module>
\ No newline at end of file +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js index 4cdeb1838ec..e70b9fbac49 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js @@ -2,88 +2,213 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +cr.exportPath('nuxGoogleApps'); + /** - * @const + * @typedef {{ + * id: number, + * name: string, + * icon: string, + * url: string, + * bookmarkId: ?string, + * selected: boolean, + * }} */ -var nuxGoogleApps = nuxGoogleApps || {}; +nuxGoogleApps.AppItem; /** * @typedef {{ - * item: !{ - * name: string, - * icon: string, - * selected: boolean, - * }, + * item: !nuxGoogleApps.AppItem, * set: function(string, boolean):void * }} */ -nuxGoogleApps.AppsArrayModel; +nuxGoogleApps.AppItemModel; Polymer({ is: 'apps-chooser', + + behaviors: [I18nBehavior], + properties: { - // TODO(hcarmona): Get this list dynamically. - appList: { - type: Array, - value: function() { - return [ - { - name: 'Gmail', - icon: 'gmail', - selected: true, - }, - { - name: 'YouTube', - icon: 'youtube', - selected: true, - }, - { - name: 'Maps', - icon: 'maps', - selected: true, - }, - { - name: 'Translate', - icon: 'translate', - selected: true, - }, - { - name: 'News', - icon: 'news', - selected: true, - }, - { - name: 'Web Store', - icon: 'chrome-store', - selected: true, - }, - ]; - }, - }, + /** @type {nux.stepIndicatorModel} */ + indicatorModel: Object, - hasAppsSelected: { + /** + * @type {!Array<!nuxGoogleApps.AppItem>} + * @private + */ + appList_: Array, + + hasAppsSelected_: { type: Boolean, notify: true, value: true, + }, + }, + + /** @private */ + finalized_: false, + + /** @private {nux.NuxGoogleAppsProxy} */ + appsProxy_: null, + + /** @private {nux.BookmarkProxy} */ + bookmarkProxy_: null, + + /** @private {nux.BookmarkBarManager} */ + bookmarkBarManager_: null, + + /** @private {?nux.ModuleMetricsManager} */ + metricsManager_: null, + + /** @private {boolean} */ + wasBookmarkBarShownOnInit_: false, + + /** @override */ + attached: function() { + Polymer.RenderStatus.afterNextRender(this, () => { + Polymer.IronA11yAnnouncer.requestAvailability(); + }); + }, + + /** @override */ + ready() { + this.appsProxy_ = nux.NuxGoogleAppsProxyImpl.getInstance(); + this.bookmarkProxy_ = nux.BookmarkProxyImpl.getInstance(); + this.bookmarkBarManager_ = nux.BookmarkBarManager.getInstance(); + this.metricsManager_ = new nux.ModuleMetricsManager( + nux.GoogleAppsMetricsProxyImpl.getInstance()); + }, + + onRouteEnter() { + this.finalized_ = false; + this.metricsManager_.recordPageInitialized(); + this.populateAllBookmarks(); + }, + + onRouteExit() { + if (this.finalized_) + return; + this.cleanUp_(); + this.metricsManager_.recordBrowserBackOrForward(); + }, + + onRouteUnload() { + if (this.finalized_) + return; + this.cleanUp_(); + this.metricsManager_.recordNavigatedAway(); + }, + + /** @private */ + onNoThanksClicked_: function() { + this.cleanUp_(); + this.metricsManager_.recordNoThanks(); + welcome.navigateToNextStep(); + }, + + /** @private */ + onGetStartedClicked_: function() { + this.finalized_ = true; + this.appList_.forEach(app => { + if (app.selected) { + this.appsProxy_.recordProviderSelected(app.id); + } + }); + this.metricsManager_.recordGetStarted(); + welcome.navigateToNextStep(); + }, + + /** Called when bookmarks should be created for all selected apps. */ + populateAllBookmarks() { + this.wasBookmarkBarShownOnInit_ = this.bookmarkBarManager_.getShown(); + + if (this.appList_) { + this.appList_.forEach(app => this.updateBookmark(app)); + } else { + this.appsProxy_.getGoogleAppsList().then(list => { + this.appList_ = list; + this.appList_.forEach((app, index) => { + // Default select first few items. + app.selected = index < 3; + this.updateBookmark(app); + }); + this.updateHasAppsSelected(); + this.fire('iron-announce', {text: this.i18n('bookmarksAdded')}); + }); + } + }, + + /** + * Called when bookmarks should be removed for all selected apps. + * @private + */ + cleanUp_() { + this.finalized_ = true; + + if (!this.appList_) + return; // No apps to remove. + + let removedBookmarks = false; + this.appList_.forEach(app => { + if (app.selected && app.bookmarkId) { + // Don't call |updateBookmark| b/c we want to save the selection in the + // event of a browser back/forward. + this.bookmarkProxy_.removeBookmark(app.bookmarkId); + app.bookmarkId = null; + removedBookmarks = true; + } + }); + // Only update and announce if we removed bookmarks. + if (removedBookmarks) { + this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_); + this.fire('iron-announce', {text: this.i18n('bookmarksRemoved')}); } }, /** - * Returns an array of booleans for each selected app. - * @return {Array<boolean>} + * @param {!nuxGoogleApps.AppItem} item + * @private */ - getSelectedAppList() { - return this.appList.map(a => a.selected); + updateBookmark(item) { + if (item.selected && !item.bookmarkId) { + this.bookmarkBarManager_.setShown(true); + this.bookmarkProxy_.addBookmark( + { + title: item.name, + url: item.url, + parentId: '1', + }, + result => { + item.bookmarkId = result.id; + }); + // Cache bookmark icon. + this.appsProxy_.cacheBookmarkIcon(item.id); + } else if (!item.selected && item.bookmarkId) { + this.bookmarkProxy_.removeBookmark(item.bookmarkId); + item.bookmarkId = null; + } }, /** * Handle toggling the apps selected. - * @param {!{model: !nuxGoogleApps.AppsArrayModel}} e + * @param {!{model: !nuxGoogleApps.AppItemModel}} e * @private */ onAppClick_: function(e) { - e.model.set('item.selected', !e.model.item.selected); - this.hasAppsSelected = this.computeHasAppsSelected_(); + const item = e.model.item; + e.model.set('item.selected', !item.selected); + this.updateBookmark(item); + this.updateHasAppsSelected(); + + this.metricsManager_.recordClickedOption(); + + // Announcements should NOT be in |updateBookmark| because there should be a + // different utterance when all app bookmarks are added/removed. + if (item.selected) + this.fire('iron-announce', {text: this.i18n('bookmarkAdded')}); + else + this.fire('iron-announce', {text: this.i18n('bookmarkRemoved')}); }, /** @@ -103,10 +228,23 @@ Polymer({ }, /** - * @return {boolean} + * Updates the value of hasAppsSelected_. * @private */ - computeHasAppsSelected_: function() { - return this.appList.some(a => a.selected); + updateHasAppsSelected: function() { + this.hasAppsSelected_ = + this.appList_ && this.appList_.some(a => a.selected); + if (!this.hasAppsSelected_) + this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_); }, + + /** + * Converts a boolean to a string because aria-pressed needs a string value. + * @param {boolean} value + * @return {string} + * @private + */ + getAriaPressed_: function(value) { + return value ? 'true' : 'false'; + } }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html index 499414bbfd9..0e61f1194bf 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html @@ -1,82 +1,41 @@ -<!DOCTYPE html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> -<meta charset="utf-8"> -<title>$i18n{headerText}</title> - <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://welcome/apps/apps_chooser.html"> -<link rel="import" href="chrome://welcome/apps/nux_google_apps_proxy.html"> +<link rel="import" href="../navigation_behavior.html"> +<link rel="import" href="apps_chooser.html"> <dom-module id="nux-google-apps"> <template> - <style include="paper-button-style"> - body { - margin: 0; - } - + <style> .apps-ask { - margin-left: auto; - margin-right: auto; - margin-top: 120px; - width: fit-content; + text-align: center; } .chrome-logo { content: -webkit-image-set( - url(chrome://welcome/apps/google_apps_1x.png) 1x, - url(chrome://welcome/apps/google_apps_2x.png) 2x); + url(chrome://welcome/images/google_apps_1x.png) 1x, + url(chrome://welcome/images/google_apps_2x.png) 2x); height: 38px; + margin: auto; margin-bottom: 16px; - margin-left: auto; - margin-right: auto; width: 42px; } h1 { - color: var(--cr-primary-text-color); - font-size: 24px; + color: var(--google-grey-900); + font-size: 1.5rem; font-weight: 500; + margin: 0; margin-bottom: 48px; - opacity: .8; - text-align: center; - } - - apps-chooser { - color: var(--cr-primary-text-color); - font-size: 14px; - margin-bottom: 48px; - } - - .button-bar { - display: flex; - justify-content: space-between; + outline: none; } </style> - <div class="apps-ask"> - <div class="chrome-logo"></div> - <h1>$i18n{googleAppsDescription}</h1> - - <apps-chooser id="appChooser" has-apps-selected="{{hasAppsSelected_}}"> + <div class="chrome-logo" alt=""></div> + <h1 tabindex="-1">$i18n{googleAppsDescription}</h1> + <apps-chooser id="appChooser" indicator-model="[[indicatorModel]]"> </apps-chooser> - - <div class="button-bar"> - <paper-button on-click="onNoThanksClicked_"> - $i18n{noThanks} - </paper-button> - <paper-button class="action-button" disabled$="[[!hasAppsSelected_]]" - on-click="onGetStartedClicked_">$i18n{getStarted}</paper-button> - </div> </div> </template> - <script src="apps/nux_google_apps.js"></script> + <script src="nux_google_apps.js"></script> </dom-module> - -<nux-google-apps></nux-google-apps> -<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> - -</html>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js index 911ec744765..6d23f6c7f27 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js @@ -5,21 +5,22 @@ Polymer({ is: 'nux-google-apps', + behaviors: [welcome.NavigationBehavior], + properties: { - /** @private */ - hasAppsSelected_: Boolean, + /** @type {nux.stepIndicatorModel} */ + indicatorModel: Object, + }, + + onRouteEnter: function() { + this.$.appChooser.onRouteEnter(); }, - /** @private */ - onNoThanksClicked_: function() { - chrome.send('rejectGoogleApps'); - window.location.replace('chrome://newtab'); + onRouteExit: function() { + this.$.appChooser.onRouteExit(); }, - /** @private */ - onGetStartedClicked_: function() { - let selectedApps = this.$.appChooser.getSelectedAppList(); - nux.NuxGoogleAppsProxyImpl.getInstance().addGoogleApps(selectedApps); - window.location.replace('chrome://newtab'); + onRouteUnload: function() { + this.$.appChooser.onRouteUnload(); }, }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.html index 604b825e5e1..06964db06af 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.html @@ -1,2 +1,3 @@ <link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://welcome/shared/i18n_setup.html"> <script src="nux_google_apps_proxy.js"></script>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.js index ea98a55fa8c..9ea9b0720b5 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps_proxy.js @@ -3,20 +3,65 @@ // found in the LICENSE file. cr.define('nux', function() { + // The metrics name corresponding to Nux EmailProvidersInteraction histogram. + const GOOGLE_APPS_SELECTION_METRIC_NAME = + 'FirstRun.NewUserExperience.GoogleAppsSelection'; + + /** + * NuxGoogleAppsSelections enum. + * These values are persisted to logs and should not be renumbered or + * re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxGoogleAppsSelections = { + Gmail_DEPRECATED: 0, + YouTube: 1, + Maps: 2, + Translate: 3, + News: 4, + ChromeWebStore: 5, + }; + /** @interface */ class NuxGoogleAppsProxy { /** - * Adds the selected apps to the bookmark bar. - * @param {!Array<boolean>} selectedApps + * Google app IDs are local to the list of Google apps, so their icon must + * be cached by the handler that provided the IDs. + * @param {number} appId + */ + cacheBookmarkIcon(appId) {} + + /** + * Returns a promise for an array of Google apps. + * @return {!Promise<!Array<!nux.BookmarkListItem>>} */ - addGoogleApps(selectedApps) {} + getGoogleAppsList() {} + + /** + * @param {number} providerId This should match one of the histogram enum + * value for NuxGoogleAppsSelections. + */ + recordProviderSelected(providerId) {} } /** @implements {nux.NuxGoogleAppsProxy} */ class NuxGoogleAppsProxyImpl { /** @override */ - addGoogleApps(selectedApps) { - chrome.send('addGoogleApps', selectedApps); + cacheBookmarkIcon(appId) { + chrome.send('cacheGoogleAppIcon', [appId]); + } + + /** @override */ + getGoogleAppsList() { + return cr.sendWithPromise('getGoogleAppsList'); + } + + /** @override */ + recordProviderSelected(providerId) { + chrome.metricsPrivate.recordEnumerationValue( + GOOGLE_APPS_SELECTION_METRIC_NAME, providerId, + Object.keys(NuxGoogleAppsSelections).length); } } @@ -26,4 +71,4 @@ cr.define('nux', function() { NuxGoogleAppsProxy: NuxGoogleAppsProxy, NuxGoogleAppsProxyImpl: NuxGoogleAppsProxyImpl, }; -});
\ No newline at end of file +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_1x.png Binary files differindex 845ae4a2b69..566cf211fd5 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_2x.png Binary files differindex 016b54ee215..4a5472f2441 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/aol_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/blue_circle.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/blue_circle.svg new file mode 100644 index 00000000000..3f34976ca98 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/blue_circle.svg @@ -0,0 +1,3 @@ +<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <circle fill="#1A73E8" fill-rule="evenodd" cx="21.5" cy="21.5" r="21.5"></circle> +</svg>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/green_rectangle.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/green_rectangle.svg new file mode 100644 index 00000000000..8cb0471291e --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/green_rectangle.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="371" height="371" viewBox="0 0 371 371"> + <path fill="#31A753" fill-rule="evenodd" d="M7.61078518,166.895209 L166.895209,7.61078518 C177.042923,-2.53692839 193.495617,-2.53692839 203.643331,7.61078518 L362.935748,166.903202 C373.083461,177.050916 373.083461,193.50361 362.935748,203.651324 L203.651324,362.935748 C193.50361,373.083461 177.050916,373.083461 166.903202,362.935748 L7.61078518,203.643331 C-2.53692839,193.495617 -2.53692839,177.042923 7.61078518,166.895209 Z"/> +</svg> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_oval.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_oval.svg new file mode 100644 index 00000000000..cf75ceb6861 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_oval.svg @@ -0,0 +1,3 @@ +<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <circle fill-rule="evenodd" fill="#F1F3F4" cx="50" cy="50" r="50"></circle> +</svg>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_rounded_rectangle.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_rounded_rectangle.svg new file mode 100644 index 00000000000..71f9fd63b98 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/grey_rounded_rectangle.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="132" height="132" viewBox="0 0 132 132"> + <path fill="#F1F3F4" fill-rule="evenodd" d="M81.6025226,14.0007794 L117.999221,50.3974774 C136.666926,69.0651833 136.666926,99.3315147 117.999221,117.999221 C99.3315147,136.666926 69.0651833,136.666926 50.3974774,117.999221 L14.0007794,81.6025226 C-4.66692648,62.9348167 -4.66692648,32.6684853 14.0007794,14.0007794 C32.6684853,-4.66692648 62.9348167,-4.66692648 81.6025226,14.0007794 Z"/> +</svg> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/red_triangle.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/red_triangle.svg new file mode 100644 index 00000000000..d89d1aeebdf --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/red_triangle.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="65" height="74" viewBox="0 0 65 74"> + <path fill="#E94235" fill-rule="evenodd" d="M64.5429228,7.29310524 L64.3644898,67.9344347 C64.1624511,71.340818 61.2707769,73.9365373 57.9057548,73.732136 C56.9598601,73.6746796 56.0401784,73.3950765 55.2195428,72.9154694 L3.60676683,42.7512281 C0.687353928,41.0450251 -0.312855086,37.266089 1.37273747,34.3107382 C1.84655098,33.4800006 2.50492275,32.7723367 3.29571384,32.2437891 L55.0869229,1.76670102 C57.9001639,-0.113607947 61.6864522,0.670655917 63.5438345,3.51840338 C64.2715067,4.63407375 64.6220761,5.95857646 64.5429228,7.29310524 Z"/> +</svg> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_dots.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_dots.svg new file mode 100644 index 00000000000..41ce568beb7 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_dots.svg @@ -0,0 +1,46 @@ +<svg width="76px" height="57px" viewBox="0 0 76 57" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <g fill-rule="evenodd" fill="#FDD663"> + <circle cx="14" cy="13" r="2"></circle> + <circle cx="14" cy="2" r="2"></circle> + <circle cx="14" cy="23" r="2"></circle> + <circle cx="14" cy="34" r="2"></circle> + <circle cx="14" cy="45" r="2"></circle> + <circle cx="14" cy="55" r="2"></circle> + <circle cx="2" cy="13" r="2"></circle> + <circle cx="2" cy="2" r="2"></circle> + <circle cx="2" cy="23" r="2"></circle> + <circle cx="2" cy="34" r="2"></circle> + <circle cx="2" cy="45" r="2"></circle> + <circle cx="2" cy="55" r="2"></circle> + <circle cx="26" cy="13" r="2"></circle> + <circle cx="26" cy="2" r="2"></circle> + <circle cx="26" cy="23" r="2"></circle> + <circle cx="26" cy="34" r="2"></circle> + <circle cx="26" cy="45" r="2"></circle> + <circle cx="26" cy="55" r="2"></circle> + <circle cx="38" cy="13" r="2"></circle> + <circle cx="38" cy="2" r="2"></circle> + <circle cx="38" cy="23" r="2"></circle> + <circle cx="38" cy="34" r="2"></circle> + <circle cx="38" cy="45" r="2"></circle> + <circle cx="38" cy="55" r="2"></circle> + <circle cx="50" cy="13" r="2"></circle> + <circle cx="50" cy="2" r="2"></circle> + <circle cx="50" cy="23" r="2"></circle> + <circle cx="50" cy="34" r="2"></circle> + <circle cx="50" cy="45" r="2"></circle> + <circle cx="50" cy="55" r="2"></circle> + <circle cx="62" cy="13" r="2"></circle> + <circle cx="62" cy="2" r="2"></circle> + <circle cx="62" cy="23" r="2"></circle> + <circle cx="62" cy="34" r="2"></circle> + <circle cx="62" cy="45" r="2"></circle> + <circle cx="62" cy="55" r="2"></circle> + <circle cx="74" cy="13" r="2"></circle> + <circle cx="74" cy="2" r="2"></circle> + <circle cx="74" cy="23" r="2"></circle> + <circle cx="74" cy="34" r="2"></circle> + <circle cx="74" cy="45" r="2"></circle> + <circle cx="74" cy="55" r="2"></circle> + </g> +</svg>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_semicircle.svg b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_semicircle.svg new file mode 100644 index 00000000000..3fe924d3524 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/background_svgs/yellow_semicircle.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="211" height="171" viewBox="0 0 211 171"> + <path fill="#FACF4C" fill-rule="evenodd" d="M152.95531,155.322875 C102.461259,184.681893 39.1648672,171.482614 4.01772623,126.776523 C0.528185501,122.337934 -5.16163709,112.29754 9.88388926,103.549542 C48.9517191,80.8341309 106.527836,47.3573508 182.61224,3.1192014 C196.248192,-4.80922088 200.05639,4.35165919 201.923,8.80779391 C224.340646,62.3251755 204.196032,125.529716 152.95531,155.322875 Z"/> +</svg> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_1x.png Binary files differindex 4307c077c65..a299b4543fa 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_2x.png Binary files differindex 91a950ff50d..8ccaa1c436c 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/chrome_store_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_1x.png Binary files differnew file mode 100644 index 00000000000..4ef0c29fc00 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_2x.png Binary files differnew file mode 100644 index 00000000000..62b761482b0 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/email_provider_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_1x.png Binary files differindex 0e354d69491..91a96a26d79 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_2x.png Binary files differindex c7296e60343..782c3bb7ca5 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/gmail_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_1x.png Binary files differindex a0135ea10f6..adaff6c6ee1 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_2x.png Binary files differindex 50c49174d81..eeccb7d66b6 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/google_apps_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_1x.png Binary files differindex 1eccfc03c41..f3f75380ffb 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_2x.png Binary files differindex 8304aec7f37..bb367838a56 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/icloud_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_1x.png Binary files differindex 0f09d60b4ec..88aa491abd6 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_2x.png Binary files differindex 9e8966fb3ed..a4c31bcfbe9 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/news_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_1x.png Binary files differindex 4ba9b40d2e4..0c9bed6a262 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_2x.png Binary files differindex 72221a321b5..3c402f8034c 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/outlook_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_1x.png Binary files differnew file mode 100644 index 00000000000..c6d263734ab --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_2x.png Binary files differnew file mode 100644 index 00000000000..b82f62010ee --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_1x.png Binary files differnew file mode 100644 index 00000000000..2624306c23b --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_2x.png Binary files differnew file mode 100644 index 00000000000..ff642c38198 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/set_as_default_illustration_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_1x.png Binary files differindex fb096711d63..3b0dcd407b7 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_2x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_2x.png Binary files differindex 00d96c19d80..6e3331671c6 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_2x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/yahoo_2x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/youtube_1x.png b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/youtube_1x.png Binary files differindex 4d40711765b..a99bee5b492 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/youtube_1x.png +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/images/youtube_1x.png diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html index e5046308305..35b8622a09e 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html @@ -3,51 +3,32 @@ <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="landing_view_proxy.html"> <link rel="import" href="navigation_behavior.html"> +<link rel="import" href="shared/action_link_style_css.html"> +<link rel="import" href="shared/onboarding_background.html"> +<link rel="import" href="shared/splash_pages_shared_css.html"> <link rel="import" href="welcome_browser_proxy.html"> <dom-module id="landing-view"> <template> - <style include="paper-button-style"> - #container { - align-items: center; - display: flex; - flex-direction: column; - height: 100%; - justify-content: center; - margin: auto; - width: 800px; - } - + <style + include="paper-button-style action-link-style splash-pages-shared-css"> h1 { - font-size: 4rem; - margin-bottom: 20px; - } - - h2 { - color: darkgrey; - font-size: 1.5rem; - } - - paper-button { - font-size: 1rem; - height: 2.5rem; - text-align: center; - white-space: nowrap; - width: 220px; + outline: none; } </style> - <!-- TODO(scottchen): localize --> + <onboarding-background></onboarding-background> <div id="container"> - <h2>Set up your browser in a few simple steps</h2> - <h1>Make Chrome your own</h1> + <h2>$i18n{landingDescription}</h2> + <h1 tabindex="-1">$i18n{landingTitle}</h1> <paper-button class="action-button" on-click="onNewUserClick_"> - Get Started - </paper-button> - <paper-button on-click="onExistingUserClick_"> - Already set up? Sign in + $i18n{landingNewUser} </paper-button> + <button class="action-link" on-click="onExistingUserClick_"> + $i18n{landingExistingUser} + </button> </div> </template> <script src="landing_view.js"></script> -</dom-module>
\ No newline at end of file +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js index 925b6fdcca5..2f17ffdab58 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js @@ -7,14 +7,43 @@ Polymer({ behaviors: [welcome.NavigationBehavior], + /** @private {?nux.LandingViewProxy} */ + landingViewProxy_: null, + + /** @private {boolean} */ + finalized_: false, + + /** @override */ + ready() { + this.landingViewProxy_ = nux.LandingViewProxyImpl.getInstance(); + }, + + onRouteEnter: function() { + this.finalized_ = false; + this.landingViewProxy_.recordPageShown(); + }, + + onRouteUnload: function() { + // Clicking on 'Returning user' will change the URL. + if (this.finalized_) { + return; + } + this.finalized_ = true; + this.landingViewProxy_.recordNavigatedAway(); + }, + /** @private */ onExistingUserClick_: function() { + this.finalized_ = true; + this.landingViewProxy_.recordExistingUser(); welcome.WelcomeBrowserProxyImpl.getInstance().handleActivateSignIn( 'chrome://welcome/returning-user'); }, /** @private */ onNewUserClick_: function() { - this.navigateTo(welcome.Routes.NEW_USER, 1); + this.finalized_ = true; + this.landingViewProxy_.recordNewUser(); + welcome.navigateTo(welcome.Routes.NEW_USER, 1); } }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.html new file mode 100644 index 00000000000..84eb5be238e --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="landing_view_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js new file mode 100644 index 00000000000..50d9fc06073 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js @@ -0,0 +1,75 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('nux', function() { + const NUX_LANDING_PAGE_INTERACTION_METRIC_NAME = + 'FirstRun.NewUserExperience.LandingPageInteraction'; + + /** + * NuxLandingPageInteractions enum. + * These values are persisted to logs and should not be renumbered or re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxLandingPageInteractions = { + PageShown: 0, + NavigatedAway: 1, + NewUser: 2, + ExistingUser: 3, + }; + + const NUX_LANDING_PAGE_INTERACTIONS_COUNT = + Object.keys(NuxLandingPageInteractions).length; + + /** @interface */ + class LandingViewProxy { + recordPageShown() {} + + recordNavigatedAway() {} + + recordNewUser() {} + + recordExistingUser() {} + } + + /** @implements {nux.LandingViewProxy} */ + class LandingViewProxyImpl { + /** @override */ + recordPageShown() { + this.recordInteraction_(NuxLandingPageInteractions.PageShown); + } + + /** @override */ + recordNavigatedAway() { + this.recordInteraction_(NuxLandingPageInteractions.NavigatedAway); + } + + /** @override */ + recordNewUser() { + this.recordInteraction_(NuxLandingPageInteractions.NewUser); + } + + /** @override */ + recordExistingUser() { + this.recordInteraction_(NuxLandingPageInteractions.ExistingUser); + } + + /** + * @param {number} interaction + * @private + */ + recordInteraction_(interaction) { + chrome.metricsPrivate.recordEnumerationValue( + NUX_LANDING_PAGE_INTERACTION_METRIC_NAME, interaction, + NUX_LANDING_PAGE_INTERACTIONS_COUNT); + } + } + + cr.addSingletonGetter(LandingViewProxyImpl); + + return { + LandingViewProxy: LandingViewProxy, + LandingViewProxyImpl: LandingViewProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/navigation_behavior.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/navigation_behavior.js index c1cdfa6fdc6..5e10ba646d0 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/navigation_behavior.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/navigation_behavior.js @@ -52,30 +52,119 @@ cr.define('welcome', function() { /** @type {!Set<!PolymerElement>} */ const routeObservers = new Set(); + /** @type {?PolymerElement} */ + let currentRouteElement; + // Notifies all the elements that extended NavigationBehavior. function notifyObservers() { + if (currentRouteElement) { + (/** @type {{onRouteExit: Function}} */ (currentRouteElement)) + .onRouteExit(); + currentRouteElement = null; + } + const route = /** @type {!welcome.Routes} */ (history.state.route); const step = history.state.step; - routeObservers.forEach((observer) => { - observer.onRouteChange(route, step); + routeObservers.forEach(observer => { + (/** @type {{onRouteChange: Function}} */ (observer)) + .onRouteChange(route, step); + + // Modules are only attached to DOM if they're for the current route, so + // as long as the id of an element matches up to the current step, it + // means that element is for the current route. + if (observer.id == `step-${step}`) { + currentRouteElement = observer; + } }); + + // If currentRouteElement is not null, it means there was a new route. + if (currentRouteElement) { + (/** @type {{onRouteEnter: Function}} */ (currentRouteElement)) + .onRouteEnter(); + (/** @type {{updateFocusForA11y: Function}} */ (currentRouteElement)) + .updateFocusForA11y(); + } } // Notifies all elements when browser history is popped. window.addEventListener('popstate', notifyObservers); - /** @polymerBehavior */ + // Notify the active element before unload. + window.addEventListener('beforeunload', () => { + if (currentRouteElement) { + (/** @type {{onRouteUnload: Function}} */ (currentRouteElement)) + .onRouteUnload(); + } + }); + + function navigateToNextStep() { + history.pushState( + { + route: history.state.route, + step: history.state.step + 1, + }, + '', `/${history.state.route}`); + notifyObservers(); + } + + /** + * @param {!welcome.Routes} route + * @param {number} step + */ + function navigateTo(route, step) { + assert([ + Routes.LANDING, + Routes.NEW_USER, + Routes.RETURNING_USER, + ].includes(route)); + + history.pushState( + { + route: route, + step: step, + }, + '', '/' + (route === Routes.LANDING ? '' : route)); + notifyObservers(); + } + + /** + * Elements can override onRoute(Change|Enter|Exit) to handle route changes. + * Order of hooks being called: + * 1) onRouteExit() on the old route + * 2) onRouteChange() on all subscribed routes + * 3) onRouteEnter() on the new route + * + * @polymerBehavior + */ const NavigationBehavior = { /** @override */ attached: function() { assert(!routeObservers.has(this)); routeObservers.add(this); + const route = /** @type {!welcome.Routes} */ (history.state.route); + const step = history.state.step; + // history state was set when page loaded, so when the element first // attaches, call the route-change handler to initialize first. - this.onRouteChange( - /** @type {!welcome.Routes} */ (history.state.route), - history.state.step); + this.onRouteChange(route, step); + + // Modules are only attached to DOM if they're for the current route, so + // as long as the id of an element matches up to the current step, it + // means that element is for the current route. + if (this.id == `step-${step}`) { + currentRouteElement = this; + this.onRouteEnter(); + this.updateFocusForA11y(); + } + }, + + /** Called to update focus when progressing through the modules. */ + updateFocusForA11y: function() { + const header = this.$$('h1'); + if (header) { + Polymer.RenderStatus.afterNextRender(this, () => header.focus()); + } }, /** @override */ @@ -83,42 +172,23 @@ cr.define('welcome', function() { assert(routeObservers.delete(this)); }, - /** Elements can override onRouteChange to handle route changes. */ - onRouteChange: function() {}, - - navigateToNextStep: function() { - history.pushState( - { - route: history.state.route, - step: history.state.step + 1, - }, - '', `/${history.state.route}`); - notifyObservers(); - }, - /** * @param {!welcome.Routes} route * @param {number} step */ - navigateTo: function(route, step) { - assert([ - Routes.LANDING, - Routes.NEW_USER, - Routes.RETURNING_USER, - ].includes(route)); - - history.pushState( - { - route: route, - step: step, - }, - '', '/' + (route === Routes.LANDING ? '' : route)); - notifyObservers(); - }, + onRouteChange: function(route, step) {}, + + onRouteEnter: function() {}, + + onRouteExit: function() {}, + + onRouteUnload: function() {}, }; return { NavigationBehavior: NavigationBehavior, + navigateTo: navigateTo, + navigateToNextStep: navigateToNextStep, Routes: Routes, }; -});
\ No newline at end of file +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/onboarding_welcome_resources.grd b/chromium/chrome/browser/resources/welcome/onboarding_welcome/onboarding_welcome_resources.grd new file mode 100644 index 00000000000..a5cfb53341c --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/onboarding_welcome_resources.grd @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> + <outputs> + <output filename="grit/onboarding_welcome_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="grit/onboarding_welcome_resources_map.cc" + type="resource_file_map_source" /> + <output filename="grit/onboarding_welcome_resources_map.h" + type="resource_map_header" /> + <output filename="onboarding_welcome_resources.pak" type="data_package" /> + </outputs> + <release seq="1"> + <includes> + <include name="IDR_NUX_EMAIL_AOL_1X" file="images\aol_1x.png" type="BINDATA"/> + <include name="IDR_NUX_EMAIL_AOL_2X" file="images\aol_2x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_GMAIL_1X" file="images\gmail_1x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_GMAIL_2X" file="images\gmail_2x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_ICLOUD_1X" file="images\icloud_1x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_ICLOUD_2X" file="images\icloud_2x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_OUTLOOK_1X" file="images\outlook_1x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_OUTLOOK_2X" file="images\outlook_2x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_PROVIDER_LOGO_1X" file="images\email_provider_1x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_PROVIDER_LOGO_2X" file="images\email_provider_2x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_YAHOO_1X" file="images\yahoo_1x.png" type="BINDATA" /> + <include name="IDR_NUX_EMAIL_YAHOO_2X" file="images\yahoo_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_CHROME_STORE_1X" file="images\chrome_store_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_CHROME_STORE_2X" file="images\chrome_store_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_LOGO_1X" file="images\google_apps_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_LOGO_2X" file="images\google_apps_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_MAPS_1X" file="images\maps_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_MAPS_2X" file="images\maps_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_NEWS_1X" file="images\news_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_NEWS_2X" file="images\news_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_TRANSLATE_1X" file="images\translate_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_TRANSLATE_2X" file="images\translate_2x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_YOUTUBE_1X" file="images\youtube_1x.png" type="BINDATA" /> + <include name="IDR_NUX_GOOGLE_APPS_YOUTUBE_2X" file="images\youtube_2x.png" type="BINDATA" /> + <include name="IDR_NUX_SET_AS_DEFAULT_ILLUSTRATION_1X" file="images\set_as_default_illustration_1x.png" type="BINDATA" /> + <include name="IDR_NUX_SET_AS_DEFAULT_ILLUSTRATION_2X" file="images\set_as_default_illustration_2x.png" type="BINDATA" /> + <include name="IDR_NUX_SET_AS_DEFAULT_LOGO_1X" file="images\set_as_default_1x.png" type="BINDATA" /> + <include name="IDR_NUX_SET_AS_DEFAULT_LOGO_2X" file="images\set_as_default_2x.png" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_BLUE_CIRCLE_SVG" file="images\background_svgs\blue_circle.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREEN_RECTANGLE_SVG" file="images\background_svgs\green_rectangle.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_OVAL_SVG" file="images\background_svgs\grey_oval.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_ROUNDED_RECTANGLE_SVG" file="images\background_svgs\grey_rounded_rectangle.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_RED_TRIANGLE_SVG" file="images\background_svgs\red_triangle.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_DOTS_SVG" file="images\background_svgs\yellow_dots.svg" type="BINDATA" /> + <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_SEMICIRCLE_SVG" file="images\background_svgs\yellow_semicircle.svg" type="BINDATA" /> + </includes> + <structures> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_EMAIL_INTERSTITIAL_HTML" + file="email_interstitial.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_EMAIL_INTERSTITIAL_JS" + file="email_interstitial.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_EMAIL_INTERSTITIAL_PROXY_HTML" + file="email_interstitial_proxy.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_EMAIL_INTERSTITIAL_PROXY_JS" + file="email_interstitial_proxy.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_HTML" + file="landing_view.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_JS" + file="landing_view.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_PROXY_HTML" + file="landing_view_proxy.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_PROXY_JS" + file="landing_view_proxy.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_NAVIGATION_BEHAVIOR_HTML" + file="navigation_behavior.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_NAVIGATION_BEHAVIOR_JS" + file="navigation_behavior.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ACTION_LINK_STYLE_JS" + file="shared\action_link_style.js" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ACTION_LINK_STYLE_CSS_HTML" + file="shared\action_link_style_css.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_BOOKMARK_PROXY_HTML" + file="shared\bookmark_proxy.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_BOOKMARK_PROXY_JS" + file="shared\bookmark_proxy.js" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_CHOOSER_SHARED_CSS" + file="shared\chooser_shared_css.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_I18N_SETUP_HTML" + file="shared\i18n_setup.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_MODULE_METRICS_PROXY_HTML" + file="shared\module_metrics_proxy.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_MODULE_METRICS_PROXY_JS" + file="shared\module_metrics_proxy.js" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ONBOARDING_BACKGROUND_HTML" + file="shared\onboarding_background.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ONBOARDING_BACKGROUND_JS" + file="shared\onboarding_background.js" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_STEP_INDICATOR_HTML" + file="shared\step_indicator.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_STEP_INDICATOR_JS" + file="shared\step_indicator.js" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_SPLASH_PAGES_SHARED_CSS" + file="shared\splash_pages_shared_css.html" + type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_HTML" + file="signin_view.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_JS" + file="signin_view.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_PROXY_HTML" + file="signin_view_proxy.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_PROXY_JS" + file="signin_view_proxy.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_APP_HTML" + file="welcome_app.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_APP_JS" + file="welcome_app.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_BROWSER_PROXY_HTML" + file="welcome_browser_proxy.html" + type="chrome_html"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_BROWSER_PROXY_JS" + file="welcome_browser_proxy.js" + type="chrome_html"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_CSS" + file="welcome.css" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_HTML" + file="welcome.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_JS" + file="welcome.js" + type="chrome_html" + preprocess="true"/> + + <!-- NUX Email--> + <structure name="IDR_NUX_EMAIL_CHOOSER_HTML" + file="email\email_chooser.html" + type="chrome_html" /> + <structure name="IDR_NUX_EMAIL_CHOOSER_JS" + file="email\email_chooser.js" + type="chrome_html" /> + <structure name="IDR_NUX_EMAIL_PROXY_HTML" + file="email\nux_email_proxy.html" + type="chrome_html" /> + <structure name="IDR_NUX_EMAIL_PROXY_JS" + file="email\nux_email_proxy.js" + type="chrome_html" /> + <structure name="IDR_NUX_EMAIL_HTML" + file="email\nux_email.html" + type="chrome_html" /> + <structure name="IDR_NUX_EMAIL_JS" + file="email\nux_email.js" + type="chrome_html" /> + + <!-- NUX Google apps--> + <structure name="IDR_NUX_GOOGLE_APPS_CHOOSER_HTML" + file="google_apps\apps_chooser.html" + type="chrome_html" /> + <structure name="IDR_NUX_GOOGLE_APPS_CHOOSER_JS" + file="google_apps\apps_chooser.js" + type="chrome_html" /> + <structure name="IDR_NUX_GOOGLE_APPS_HTML" + file="google_apps\nux_google_apps.html" + type="chrome_html" /> + <structure name="IDR_NUX_GOOGLE_APPS_JS" + file="google_apps\nux_google_apps.js" + type="chrome_html" /> + <structure name="IDR_NUX_GOOGLE_APPS_PROXY_HTML" + file="google_apps\nux_google_apps_proxy.html" + type="chrome_html" /> + <structure name="IDR_NUX_GOOGLE_APPS_PROXY_JS" + file="google_apps\nux_google_apps_proxy.js" + type="chrome_html" /> + <structure name="IDR_NUX_SET_AS_DEFAULT_HTML" + file="set_as_default\nux_set_as_default.html" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_NUX_SET_AS_DEFAULT_JS" + file="set_as_default\nux_set_as_default.js" + type="chrome_html" + preprocess="true"/> + <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_HTML" + file="set_as_default\nux_set_as_default_proxy.html" + type="chrome_html" /> + <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_JS" + file="set_as_default\nux_set_as_default_proxy.js" + type="chrome_html" /> + </structures> + </release> +</grit> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/BUILD.gn b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/BUILD.gn index 4db1759d472..70d75a12893 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/BUILD.gn +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/BUILD.gn @@ -13,9 +13,19 @@ js_type_check("closure_compile") { js_library("nux_set_as_default") { deps = [ ":nux_set_as_default_proxy", + "../:navigation_behavior", + "../shared:nux_types", + "//ui/webui/resources/js:load_time_data", + "//ui/webui/resources/js:web_ui_listener_behavior", ] } js_library("nux_set_as_default_proxy") { - deps = [] + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ + "$externs_path/chrome_send.js", + "$externs_path/metrics_private.js", + ] } diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html index 0e29e032aa7..0f97022e56c 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html @@ -1,97 +1,95 @@ -<!DOCTYPE html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> -<head> - <meta charset="utf-8"> - <title>$i18n{headerText}</title> - <link rel="import" href="chrome://resources/html/polymer.html"> - <link rel="import" href="chrome://resources/cr_elements/icons.html"> - <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> - <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> - <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> - <link rel="import" href="nux_set_as_default_proxy.html"> - <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> - <style> - body { - margin: 0; - } - </style> +<link rel="import" href="chrome://resources/html/polymer.html"> - <dom-module id="nux-set-as-default"> - <template> - <style include="paper-button-style"> - :host { - align-items: center; - display: flex; - height: 100vh; - justify-content: space-around; - } +<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="../navigation_behavior.html"> +<link rel="import" href="../shared/i18n_setup.html"> +<link rel="import" href="../shared/step_indicator.html"> +<link rel="import" href="nux_set_as_default_proxy.html"> +<if expr="is_win"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +</if> - .container { - text-align: center; - width: 800px; - } +<dom-module id="nux-set-as-default"> + <template> + <style include="paper-button-style"> + .container { + text-align: center; + } - .logo { - margin-bottom: 16px; - /* TODO(scottchen): placeholder; replace when asset is available. */ - width: 32px; - height: 32px; - display: inline-block; - background: red; - } + .logo { + content: -webkit-image-set( + url(../images/set_as_default_1x.png) 1x, + url(../images/set_as_default_2x.png) 2x); + display: inline-block; + height: 38px; + margin-bottom: 16px; + width: 42px; + } - h1 { - color: #202124; - font-weight: 500; - font-size: 1.5rem; - line-height: 2.5rem; - margin: 0; - } + .illustration { + content: -webkit-image-set( + url(../images/set_as_default_illustration_1x.png) 1x, + url(../images/set_as_default_illustration_2x.png) 2x); + width: 454px; + } - h2 { - color: #202124; - font-weight: unset; - font-size: 1.25rem; - line-height: 1.875rem; - margin: 0; - margin-top: 16px; - margin-bottom: 48px; - } + h1 { + color: var(--google-grey-900); + font-size: 1.5rem; + font-weight: 500; + line-height: 2.5rem; + margin: 0; + outline: none; + } - img { - /* TODO(scottchen): placeholder; replace when asset is available. */ - width: 454px; - height: 186px; - display: inline-block; - background: red; - } + h2 { + color: var(--google-grey-900); + font-size: 1.25rem; + font-weight: unset; + line-height: 1.875rem; + margin: auto; + margin-bottom: 48px; + margin-top: 16px; + max-width: 400px; + } - .button-bar { - display: flex; - margin-top: 64px; - justify-content: space-between; - } - </style> - <div class="container"> - <div class="logo"></div> - <h1>TODO_HEADER</h1> - <h2>TODO_SUBHEADER</h2> - <!-- TODO(scottchen): WIP behind feature flag, add src later. --> - <img> - <div class="button-bar"> - <paper-button on-click="onDeclineClick_"> - TODO_NO_THANKS - </paper-button> - <paper-button class="action-button" on-click="onSetDefaultClick_"> - TODO_SET_AS_DEFAULT - </paper-button> - </div> + .button-bar { + display: flex; + justify-content: space-between; + margin-top: 64px; + } + +<if expr="is_win"> + iron-icon[icon='cr:open-in-new'] { + height: 20px; + margin-left: 6px; + margin-right: -10px; + width: 20px; + } +</if> + </style> + <div class="container"> + <div class="logo"></div> + <h1 tabindex="-1">$i18n{setDefaultHeader}</h1> + <h2>$i18n{setDefaultSubHeader}</h2> + <div class="illustration"></div> + <div class="button-bar"> + <paper-button id="decline-button" on-click="onDeclineClick_"> + $i18n{setDefaultSkip} + </paper-button> + <step-indicator model="[[indicatorModel]]"></step-indicator> + <paper-button class="action-button" on-click="onSetDefaultClick_"> + $i18n{setDefaultConfirm} +<if expr="is_win"> + <iron-icon icon="cr:open-in-new" hidden="[[!isWin10]]"></iron-icon> +</if> + </paper-button> </div> - </template> - <script src="nux_set_as_default.js"></script> - </dom-module> -</head> -<body> - <nux-set-as-default></nux-set-as-default> -</body> -</html>
\ No newline at end of file + </div> + </template> + <script src="nux_set_as_default.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js index 97e443a4a00..7e0c67488f7 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js @@ -5,13 +5,31 @@ Polymer({ is: 'nux-set-as-default', - behaviors: [WebUIListenerBehavior], + behaviors: [ + WebUIListenerBehavior, + welcome.NavigationBehavior, + ], + + properties: { + /** @type {nux.stepIndicatorModel} */ + indicatorModel: Object, + + // <if expr="is_win"> + isWin10: { + type: Boolean, + value: loadTimeData.getBoolean('is_win10'), + }, + // </if> + }, /** @private {nux.NuxSetAsDefaultProxy} */ browserProxy_: null, + /** @private {boolean} */ + finalized_: false, + /** @override */ - attached: function() { + ready: function() { this.browserProxy_ = nux.NuxSetAsDefaultProxyImpl.getInstance(); this.addWebUIListener( @@ -19,33 +37,59 @@ Polymer({ this.onDefaultBrowserChange_.bind(this)); }, + onRouteEnter: function() { + this.finalized_ = false; + this.browserProxy_.recordPageShown(); + }, + + onRouteExit: function() { + if (this.finalized_) + return; + this.finalized_ = true; + this.browserProxy_.recordNavigatedAwayThroughBrowserHistory(); + }, + + onRouteUnload: function() { + if (this.finalized_) + return; + this.finalized_ = true; + this.browserProxy_.recordNavigatedAway(); + }, + /** @private */ onDeclineClick_: function() { - // TODO(scottchen): Add UMA collection here. + if (this.finalized_) + return; + this.browserProxy_.recordSkip(); this.finished_(); }, /** @private */ onSetDefaultClick_: function() { + if (this.finalized_) + return; + + this.browserProxy_.recordBeginSetDefault(); this.browserProxy_.setAsDefault(); }, /** * Automatically navigate to the next onboarding step once default changed. - * @param {boolean} isDefault + * @param {!nux.DefaultBrowserInfo} status * @private */ - onDefaultBrowserChange_: function(isDefault) { - // TODO(scottchen): Add UMA collection here. - - if (isDefault) + onDefaultBrowserChange_: function(status) { + if (status.isDefault) { + this.browserProxy_.recordSuccessfullySetDefault(); this.finished_(); + } }, /** @private */ finished_: function() { - // TODO(scottchen): use navigation behavior to go to next step once this - // module is integrated with onboarding-welcome's welcome-app. + this.finalized_ = true; + + welcome.navigateToNextStep(); }, }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js index d4b50fe0f5c..1596232b152 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js @@ -3,17 +3,92 @@ // found in the LICENSE file. cr.define('nux', function() { + const NUX_SET_AS_DEFAULT_INTERACTION_METRIC_NAME = + 'FirstRun.NewUserExperience.SetAsDefaultInteraction'; + + /** + * NuxSetAsDefaultInteractions enum. + * These values are persisted to logs and should not be renumbered or re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxSetAsDefaultInteractions = { + PageShown: 0, + NavigatedAway: 1, + Skip: 2, + ClickSetDefault: 3, + SuccessfullySetDefault: 4, + NavigatedAwayThroughBrowserHistory: 5, + }; + + const NUX_SET_AS_DEFAULT_INTERACTIONS_COUNT = + Object.keys(NuxSetAsDefaultInteractions).length; + /** @interface */ class NuxSetAsDefaultProxy { + requestDefaultBrowserState() {} setAsDefault() {} + recordPageShown() {} + recordNavigatedAway() {} + recordNavigatedAwayThroughBrowserHistory() {} + recordSkip() {} + recordBeginSetDefault() {} + recordSuccessfullySetDefault() {} } /** @implements {nux.NuxSetAsDefaultProxy} */ class NuxSetAsDefaultProxyImpl { /** @override */ + requestDefaultBrowserState() { + chrome.send('requestDefaultBrowserState'); + } + + /** @override */ setAsDefault() { chrome.send('setAsDefaultBrowser'); } + + /** @override */ + recordPageShown() { + this.recordInteraction_(NuxSetAsDefaultInteractions.PageShown); + } + + /** @override */ + recordNavigatedAway() { + this.recordInteraction_(NuxSetAsDefaultInteractions.NavigatedAway); + } + + /** @override */ + recordNavigatedAwayThroughBrowserHistory() { + this.recordInteraction_( + NuxSetAsDefaultInteractions.NavigatedAwayThroughBrowserHistory); + } + + /** @override */ + recordSkip() { + this.recordInteraction_(NuxSetAsDefaultInteractions.Skip); + } + + /** @override */ + recordBeginSetDefault() { + this.recordInteraction_(NuxSetAsDefaultInteractions.ClickSetDefault); + } + + /** @override */ + recordSuccessfullySetDefault() { + this.recordInteraction_( + NuxSetAsDefaultInteractions.SuccessfullySetDefault); + } + + /** + * @param {number} interaction + * @private + */ + recordInteraction_(interaction) { + chrome.metricsPrivate.recordEnumerationValue( + NUX_SET_AS_DEFAULT_INTERACTION_METRIC_NAME, interaction, + NUX_SET_AS_DEFAULT_INTERACTIONS_COUNT); + } } cr.addSingletonGetter(NuxSetAsDefaultProxyImpl); @@ -22,4 +97,4 @@ cr.define('nux', function() { NuxSetAsDefaultProxy: NuxSetAsDefaultProxy, NuxSetAsDefaultProxyImpl: NuxSetAsDefaultProxyImpl, }; -});
\ No newline at end of file +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/BUILD.gn b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/BUILD.gn new file mode 100644 index 00000000000..d2c36998d69 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":bookmark_proxy", + ":nux_types", + ":step_indicator", + ] +} + +js_library("bookmark_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ + "$externs_path/chrome_extensions.js", + "$externs_path/chrome_send.js", + ] +} + +js_library("module_metrics_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/metrics_private.js" ] +} + +js_library("nux_types") { + deps = [ + "//ui/webui/resources/js:cr", + ] +} + +js_library("step_indicator") { +} diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style.js new file mode 100644 index 00000000000..b4e52c4ba58 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style.js @@ -0,0 +1,9 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Initiates focus-outline-manager for this document so that + * action-link style can take advantage of it. + */ +cr.ui.FocusOutlineManager.forDocument(document);
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html new file mode 100644 index 00000000000..b4fb1e7b4ca --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html @@ -0,0 +1,34 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/cr/ui/focus_outline_manager.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + +<dom-module id="action-link-style"> + <template> + <style> + button.action-link { + @apply --cr-actionable; + -webkit-appearance: none; + background: none; + border: none; + color: var(--google-blue-700); + display: inline-block; + font-family: inherit; + text-decoration: none; + } + + button.action-link[disabled] { + color: var(--paper-grey-600); + cursor: default; + opacity: 0.65; + } + + :host-context(html:not(.focus-outline-visible)) button.action-link { + outline: none; + } + </style> + </template> +</dom-module> + +<script src="action_link_style.js"></script>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.html new file mode 100644 index 00000000000..0336d1ff108 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="bookmark_proxy.js"></script>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js new file mode 100644 index 00000000000..d7a4da7656d --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js @@ -0,0 +1,92 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('nux', function() { + /** + * @typedef {{ + * parentId: string, + * title: string, + * url: string, + * }} + */ + let bookmarkData; + + /** @interface */ + class BookmarkProxy { + /** + * @param {!bookmarkData} data + * @param {!Function} callback + */ + addBookmark(data, callback) {} + + /** @param {string} id ID provided by callback when bookmark was added. */ + removeBookmark(id) {} + + /** @param {boolean} show */ + toggleBookmarkBar(show) {} + + /** @return {!Promise<boolean>} */ + isBookmarkBarShown() {} + } + + /** @implements {nux.BookmarkProxy} */ + class BookmarkProxyImpl { + /** @override */ + addBookmark(data, callback) { + chrome.bookmarks.create(data, callback); + } + + /** @override */ + removeBookmark(id) { + chrome.bookmarks.remove(id); + } + + /** @override */ + toggleBookmarkBar(show) { + chrome.send('toggleBookmarkBar', [show]); + } + + /** @override */ + isBookmarkBarShown() { + return cr.sendWithPromise('isBookmarkBarShown'); + } + } + + cr.addSingletonGetter(BookmarkProxyImpl); + + // Wrapper for bookmark proxy to keep some additional states. + class BookmarkBarManager { + constructor() { + /** @private {nux.BookmarkProxy} */ + this.proxy_ = BookmarkProxyImpl.getInstance(); + + /** @private {boolean} */ + this.isBarShown_ = false; + + /** @type {!Promise} */ + this.initialized = this.proxy_.isBookmarkBarShown().then(shown => { + this.isBarShown_ = shown; + }); + } + + /** @return {boolean} */ + getShown() { + return this.isBarShown_; + } + + /** @param {boolean} show */ + setShown(show) { + this.isBarShown_ = show; + this.proxy_.toggleBookmarkBar(show); + } + } + + cr.addSingletonGetter(BookmarkBarManager); + + return { + BookmarkProxy: BookmarkProxy, + BookmarkProxyImpl: BookmarkProxyImpl, + BookmarkBarManager: BookmarkBarManager, + }; +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html index 71185daba33..6610aca18c6 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html @@ -6,6 +6,7 @@ <template> <style> :host { + color: var(--google-grey-900); display: block; white-space: nowrap; } @@ -35,7 +36,7 @@ } .option.keyboard-focused:focus { - outline: -webkit-focus-ring-color auto 5px; + outline: rgba(26, 115, 232, 0.4) solid 3px; } .option .option-name { @@ -72,8 +73,8 @@ height: 12px; margin: 0; position: absolute; - right: 10px; - top: 10px; + right: 6px; + top: 6px; width: 12px; } @@ -86,6 +87,7 @@ .option[active] { border: 1px solid var(--google-blue-600); color: var(--google-blue-600); + font-weight: 500; } .option[active] iron-icon[icon='cr:check'] { @@ -97,6 +99,13 @@ justify-content: space-between; margin-top: 64px; } + + iron-icon[icon='cr:chevron-right'] { + height: 20px; + margin-left: 6px; + margin-right: -10px; + width: 20px; + } </style> </template> -</dom-module>
\ No newline at end of file +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html index fa9610d9b90..c505b2c1365 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html @@ -1,2 +1,2 @@ <script src="chrome://resources/js/load_time_data.js"></script> -<script src="../strings.js"></script>
\ No newline at end of file +<script src="../strings.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.html new file mode 100644 index 00000000000..5c10f79489a --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="module_metrics_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js new file mode 100644 index 00000000000..57034af4d45 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js @@ -0,0 +1,260 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('nux', function() { + /** @interface */ + class ModuleMetricsProxy { + recordPageShown() {} + + recordDidNothingAndNavigatedAway() {} + + recordDidNothingAndChoseSkip() {} + + recordDidNothingAndChoseNext() {} + + recordChoseAnOptionAndNavigatedAway() {} + + recordChoseAnOptionAndChoseSkip() {} + + recordChoseAnOptionAndChoseNext() {} + + recordClickedDisabledNextButtonAndNavigatedAway() {} + + recordClickedDisabledNextButtonAndChoseSkip() {} + + recordClickedDisabledNextButtonAndChoseNext() {} + + recordNavigatedAwayThroughBrowserHistory() {} + } + + /** @implements {nux.ModuleMetricsProxy} */ + class ModuleMetricsProxyImpl { + /** + * @param {string} histogramName The histogram that will record the module + * navigation metrics. + */ + constructor(histogramName, interactions) { + /** @private {string} */ + this.interactionMetric_ = histogramName; + this.interactions_ = interactions; + } + + /** @override */ + recordPageShown() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, this.interactions_.PageShown, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordDidNothingAndNavigatedAway() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.DidNothingAndNavigatedAway, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordDidNothingAndChoseSkip() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, this.interactions_.DidNothingAndChoseSkip, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordDidNothingAndChoseNext() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, this.interactions_.DidNothingAndChoseNext, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordChoseAnOptionAndNavigatedAway() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.ChoseAnOptionAndNavigatedAway, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordChoseAnOptionAndChoseSkip() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, this.interactions_.ChoseAnOptionAndChoseSkip, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordChoseAnOptionAndChoseNext() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, this.interactions_.ChoseAnOptionAndChoseNext, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordClickedDisabledNextButtonAndNavigatedAway() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.ClickedDisabledNextButtonAndNavigatedAway, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordClickedDisabledNextButtonAndChoseSkip() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.ClickedDisabledNextButtonAndChoseSkip, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordClickedDisabledNextButtonAndChoseNext() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.ClickedDisabledNextButtonAndChoseNext, + Object.keys(this.interactions_).length); + } + + /** @override */ + recordNavigatedAwayThroughBrowserHistory() { + chrome.metricsPrivate.recordEnumerationValue( + this.interactionMetric_, + this.interactions_.NavigatedAwayThroughBrowserHistory, + Object.keys(this.interactions_).length); + } + } + + class ModuleMetricsManager { + /** @param {nux.ModuleMetricsProxy} metricsProxy */ + constructor(metricsProxy) { + this.metricsProxy_ = metricsProxy; + + this.options_ = { + didNothing: { + andNavigatedAway: metricsProxy.recordDidNothingAndNavigatedAway, + andChoseSkip: metricsProxy.recordDidNothingAndChoseSkip, + andChoseNext: metricsProxy.recordDidNothingAndChoseNext, + }, + choseAnOption: { + andNavigatedAway: metricsProxy.recordChoseAnOptionAndNavigatedAway, + andChoseSkip: metricsProxy.recordChoseAnOptionAndChoseSkip, + andChoseNext: metricsProxy.recordChoseAnOptionAndChoseNext, + }, + clickedDisabledNextButton: { + andNavigatedAway: + metricsProxy.recordClickedDisabledNextButtonAndNavigatedAway, + andChoseSkip: + metricsProxy.recordClickedDisabledNextButtonAndChoseSkip, + andChoseNext: + metricsProxy.recordClickedDisabledNextButtonAndChoseNext, + }, + }; + + this.firstPart = this.options_.didNothing; + } + + recordPageInitialized() { + this.metricsProxy_.recordPageShown(); + this.firstPart = this.options_.didNothing; + } + + recordClickedOption() { + // Only overwrite this.firstPart if it's not overwritten already + if (this.firstPart == this.options_.didNothing) + this.firstPart = this.options_.choseAnOption; + } + + recordClickedDisabledButton() { + // Only overwrite this.firstPart if it's not overwritten already + if (this.firstPart == this.options_.didNothing) + this.firstPart = this.options_.clickedDisabledNextButton; + } + + recordNoThanks() { + this.firstPart.andChoseSkip.call(this.metricsProxy_); + } + + recordGetStarted() { + this.firstPart.andChoseNext.call(this.metricsProxy_); + } + + recordNavigatedAway() { + this.firstPart.andNavigatedAway.call(this.metricsProxy_); + } + + recordBrowserBackOrForward() { + this.metricsProxy_.recordNavigatedAwayThroughBrowserHistory(); + } + } + + return { + ModuleMetricsProxy: ModuleMetricsProxy, + ModuleMetricsProxyImpl: ModuleMetricsProxyImpl, + ModuleMetricsManager: ModuleMetricsManager, + }; +}); + +// This is done outside |cr.define| because the closure compiler wants a fully +// qualified name for |nux.ModuleMetricsProxyImpl|. +nux.EmailMetricsProxyImpl = class extends nux.ModuleMetricsProxyImpl { + constructor() { + /** + * NuxEmailProvidersInteractions enum. + * These values are persisted to logs and should not be renumbered or + * re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxEmailProvidersInteractions = { + PageShown: 0, + DidNothingAndNavigatedAway: 1, + DidNothingAndChoseSkip: 2, + ChoseAnOptionAndNavigatedAway: 3, + ChoseAnOptionAndChoseSkip: 4, + ChoseAnOptionAndChoseNext: 5, + ClickedDisabledNextButtonAndNavigatedAway: 6, + ClickedDisabledNextButtonAndChoseSkip: 7, + ClickedDisabledNextButtonAndChoseNext: 8, + DidNothingAndChoseNext: 9, + NavigatedAwayThroughBrowserHistory: 10, + }; + + super( + 'FirstRun.NewUserExperience.EmailProvidersInteraction', + NuxEmailProvidersInteractions); + } +}; + +nux.GoogleAppsMetricsProxyImpl = class extends nux.ModuleMetricsProxyImpl { + constructor() { + /** + * NuxGoogleAppsInteractions enum. + * These values are persisted to logs and should not be renumbered or + * re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxGoogleAppsInteractions = { + PageShown: 0, + NotUsed_DEPRECATED: 1, + GetStarted_DEPRECATED: 2, + DidNothingAndNavigatedAway: 3, + DidNothingAndChoseSkip: 4, + ChoseAnOptionAndNavigatedAway: 5, + ChoseAnOptionAndChoseSkip: 6, + ChoseAnOptionAndChoseNext: 7, + ClickedDisabledNextButtonAndNavigatedAway: 8, + ClickedDisabledNextButtonAndChoseSkip: 9, + ClickedDisabledNextButtonAndChoseNext: 10, + DidNothingAndChoseNext: 11, + NavigatedAwayThroughBrowserHistory: 12, + }; + + super( + 'FirstRun.NewUserExperience.GoogleAppsInteraction', + NuxGoogleAppsInteractions); + } +}; + +cr.addSingletonGetter(nux.EmailMetricsProxyImpl); +cr.addSingletonGetter(nux.GoogleAppsMetricsProxyImpl); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js new file mode 100644 index 00000000000..e429b900cf6 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js @@ -0,0 +1,35 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.exportPath('nux'); + +/** + * @typedef {{ + * id: number, + * name: string, + * icon: string, + * url: string, + * }} + */ +nux.BookmarkListItem; + +/** + * @typedef {{ + * total: number, + * active: number, + * }} + */ +nux.stepIndicatorModel; + +/** + * TODO(scottchen): somehow reuse from + * chrome/browser/resources/settings/default_browser_page/default_browser_browser_proxy.js + * @typedef {{ + * canBeDefault: boolean, + * isDefault: boolean, + * isDisabledByPolicy: boolean, + * isUnknownError: boolean, + * }}; + */ +nux.DefaultBrowserInfo;
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.html new file mode 100644 index 00000000000..6df7693a29d --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.html @@ -0,0 +1,145 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<dom-module id="onboarding-background"> + <template> + <style> + @keyframes blue-circle-anim-x { + 50% { + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateX(44px); + } + } + + @keyframes blue-circle-anim-y { + 50% { + animation-timing-function: cubic-bezier(0.55, 0, 0.2, 1); + transform: translateY(17px); + } + } + + @keyframes green-rectangle-anim { + 100% { + transform: rotate(360deg); + } + } + + @keyframes red-triangle-anim { + 50% { + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateY(25px) rotate(-53deg); + } + } + + @keyframes yellow-semicircle-anim { + 40% { + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateY(40px) rotate(-1deg); + } + } + + @keyframes grey-rounded-rectangle-anim { + 65% { + animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateY(-48px) rotate(-75deg); + } + } + + :host { + bottom: 0; + left: 0; + margin: auto; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + z-index: -1; + } + + /* The container is necessary in order for :host to hide overflowing SVGs + correctly without disturbing their positions. */ + #container { + height: 100%; + left: 50%; + min-height: 700px; + min-width: 1024px; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 100%; + } + + img, + span { + position: absolute; + } + + #blue-circle-container { + animation: blue-circle-anim-x 9s cubic-bezier(0.4, 0, 0.2, 1) infinite; + left: calc(13% - 50px); /* Relative to #yellow-dots. */ + top: calc(18% - 26px); /* Relative to #yellow-dots. */ + } + + #blue-circle-container::after { + animation: blue-circle-anim-y 9s cubic-bezier(0.25, 0, 0.2, 1) infinite; + content: url(../images/background_svgs/blue_circle.svg); + position: absolute; + } + + #yellow-dots { + left: 13%; + top: 18%; + } + + #grey-rounded-rectangle { + animation: grey-rounded-rectangle-anim 10s cubic-bezier(0.4, 0, 0.2, 1) + infinite; + left: -42px; + top: 45%; + } + + #red-triangle { + animation: red-triangle-anim 9.6s cubic-bezier(0.4, 0, 0.2, 1) infinite; + bottom: 15%; + left: 12%; + } + + #yellow-semicircle { + animation: yellow-semicircle-anim 10s cubic-bezier(0.4, 0, 0.2, 1) + infinite; + right: 28.5%; + top: -50px; + transform: rotate(-7deg); + } + + #green-rectangle { + animation: green-rectangle-anim 40s infinite linear; + bottom: 8%; + right: -255px; + } + + #grey-oval { + bottom: calc(8% + 24px); /* Relative to green-rectangle. */ + mix-blend-mode: multiply; + right: 48px; + } + </style> + <div id="container"> + <!-- Using span as container for an :after element that actually contains + the blue-circle svg, because the animation needs to curve so x and y + needs to be animated separately. --> + <span id="blue-circle-container"></span> + <img id="green-rectangle" alt="" + src="../images/background_svgs/green_rectangle.svg"> + <img id="grey-oval" alt="" src="../images/background_svgs/grey_oval.svg"> + <img id="grey-rounded-rectangle" alt="" + src="../images/background_svgs/grey_rounded_rectangle.svg"> + <img id="red-triangle" alt="" + src="../images/background_svgs/red_triangle.svg"> + <img id="yellow-dots" alt="" + src="../images/background_svgs/yellow_dots.svg"> + <img id="yellow-semicircle" alt="" + src="../images/background_svgs/yellow_semicircle.svg"> + </div> + </template> + <script src="onboarding_background.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.js new file mode 100644 index 00000000000..12358fa84c5 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/onboarding_background.js @@ -0,0 +1,11 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview This element contains a set of SVGs that together acts as an + * animated and responsive background for any page that contains it. + */ +Polymer({ + is: 'onboarding-background', +});
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html new file mode 100644 index 00000000000..c23baac6e64 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html @@ -0,0 +1,52 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> + +<dom-module id="splash-pages-shared-css"> + <template> + <style> + #container { + align-items: center; + display: flex; + flex-direction: column; + height: 100%; + justify-content: center; + margin: auto; + min-width: 800px; + } + + h1 { + font-size: 4rem; + margin-bottom: 40px; + margin-top: 16px; + text-align: center; + } + + h2 { + color: var(--google-grey-600); + font-size: 1.5rem; + font-weight: 500; + line-height: 2.25rem; + margin: 0; + opacity: 0.8; + text-align: center; + } + + paper-button { + font-size: 1rem; + height: 3rem; + padding-bottom: 12px; + padding-top: 12px; + text-align: center; + white-space: nowrap; + width: 256px; + } + + .action-link { + font-size: 1rem; + font-weight: 500; + margin-top: 24px; + } + </style> + </template> +</dom-module>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.html new file mode 100644 index 00000000000..22cf1147f3c --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.html @@ -0,0 +1,32 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> + +<dom-module id="step-indicator"> + <template> + <style> + :host { + align-items: center; + display: flex; + } + + span { + background: var(--google-grey-200); + border-radius: 50%; + display: inline-block; + height: 8px; + margin: 0 4px; + width: 8px; + } + + span.active { + background: var(--google-blue-600); + opacity: 0.5; + } + </style> + <template is="dom-repeat" items="[[dots_]]"> + <span class$="[[getActiveClass_(index, model.active)]]"></span> + </template> + </template> + <script src="step_indicator.js"></script> +</dom-module>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js new file mode 100644 index 00000000000..4a0bee38e92 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js @@ -0,0 +1,40 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview This element contains a set of SVGs that together acts as an + * animated and responsive background for any page that contains it. + */ +Polymer({ + is: 'step-indicator', + + properties: { + /** @type {nux.stepIndicatorModel} */ + model: Object, + + /** @private */ + dots_: { + type: Array, + computed: 'computeDots_(model.total)', + }, + }, + + /** + * @return {!Array<undefined>} + * @private + */ + computeDots_: function() { + // If total is 1, show nothing. + return new Array(this.model.total > 1 ? this.model.total : 0); + }, + + /** + * @param {number} index + * @return {string} + * @private + */ + getActiveClass_: function(index) { + return index == this.model.active ? 'active' : ''; + }, +});
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html new file mode 100644 index 00000000000..aca488b96db --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html @@ -0,0 +1,36 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="email/nux_email_proxy.html"> +<link rel="import" href="navigation_behavior.html"> +<link rel="import" href="shared/action_link_style_css.html"> +<link rel="import" href="shared/i18n_setup.html"> +<link rel="import" href="shared/onboarding_background.html"> +<link rel="import" href="shared/splash_pages_shared_css.html"> +<link rel="import" href="signin_view_proxy.html"> +<link rel="import" href="welcome_browser_proxy.html"> + +<dom-module id="signin-view"> + <template> + <style + include="paper-button-style action-link-style splash-pages-shared-css"> + h1 { + outline: none; + } + </style> + <onboarding-background></onboarding-background> + <div id="container"> + <h2>$i18n{signInSubHeader}</h2> + <h1 tabindex="-1">$i18n{signInHeader}</h1> + <paper-button class="action-button" on-click="onSignInClick_"> + $i18n{signIn} + </paper-button> + <button class="action-link" on-click="onNoThanksClick_"> + $i18n{noThanks} + </button> + </div> + </template> + <script src="signin_view.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js new file mode 100644 index 00000000000..0480a603499 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js @@ -0,0 +1,85 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +Polymer({ + is: 'signin-view', + + behaviors: [welcome.NavigationBehavior], + + /** @private {boolean} */ + shouldShowEmailInterstitial_: + loadTimeData.getBoolean('showEmailInterstitial'), + + /** @private {boolean} */ + finalized_: false, + + /** @private {?welcome.WelcomeBrowserProxy} */ + welcomeBrowserProxy_: null, + + /** @private {?nux.SigninViewProxy} */ + signinViewProxy_: null, + + /** @override */ + ready: function() { + this.welcomeBrowserProxy_ = welcome.WelcomeBrowserProxyImpl.getInstance(); + this.signinViewProxy_ = nux.SigninViewProxyImpl.getInstance(); + }, + + onRouteEnter: function() { + this.finalized_ = false; + this.signinViewProxy_.recordPageShown(); + }, + + onRouteExit: function() { + if (this.finalized_) { + return; + } + this.finalized_ = true; + this.signinViewProxy_.recordNavigatedAwayThroughBrowserHistory(); + }, + + onRouteUnload: function() { + // URL is expected to change when signing in or skipping. + if (this.finalized_) { + return; + } + this.finalized_ = true; + this.signinViewProxy_.recordNavigatedAway(); + }, + + /** + * @return {?string} + * @private + */ + getTargetUrl_: function() { + const savedProvider = + nux.NuxEmailProxyImpl.getInstance().getSavedProvider(); + if (savedProvider != undefined && this.shouldShowEmailInterstitial_) { + return `chrome://welcome/email-interstitial?provider=${savedProvider}`; + } else { + return null; + } + }, + + /** + * When the user clicks sign-in, check whether or not they previously + * selected an email provider they prefer to use. If so, direct them back to + * the email-interstitial page, otherwise let it direct to NTP. + * @private + */ + onSignInClick_: function() { + this.finalized_ = true; + this.signinViewProxy_.recordSignIn(); + this.welcomeBrowserProxy_.handleActivateSignIn(this.getTargetUrl_()); + }, + + /** @private */ + onNoThanksClick_: function() { + this.finalized_ = true; + this.signinViewProxy_.recordSkip(); + // It's safe to assume sign-view is always going to be the last step, so + // go to the target url directly. If there's no target, it lands on NTP. + this.welcomeBrowserProxy_.handleUserDecline(this.getTargetUrl_()); + } +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.html new file mode 100644 index 00000000000..5d26af4e3f0 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="signin_view_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js new file mode 100644 index 00000000000..0d90282e7ec --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js @@ -0,0 +1,80 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('nux', function() { + const NUX_SIGNIN_VIEW_INTERACTION_METRIC_NAME = + 'FirstRun.NewUserExperience.SignInInterstitialInteraction'; + + /** + * NuxSignInInterstitialInteractions enum. + * These values are persisted to logs and should not be renumbered or re-used. + * See tools/metrics/histograms/enums.xml. + * @enum {number} + */ + const NuxSignInInterstitialInteractions = { + PageShown: 0, + NavigatedAway: 1, + Skip: 2, + SignIn: 3, + NavigatedAwayThroughBrowserHistory: 4, + }; + + const NUX_SIGNIN_VIEW_INTERACTIONS_COUNT = + Object.keys(NuxSignInInterstitialInteractions).length; + + /** @interface */ + class SigninViewProxy { + recordPageShown() {} + recordNavigatedAway() {} + recordNavigatedAwayThroughBrowserHistory() {} + recordSkip() {} + recordSignIn() {} + } + + /** @implements {nux.SigninViewProxy} */ + class SigninViewProxyImpl { + /** @override */ + recordPageShown() { + this.recordInteraction_(NuxSignInInterstitialInteractions.PageShown); + } + + /** @override */ + recordNavigatedAway() { + this.recordInteraction_(NuxSignInInterstitialInteractions.NavigatedAway); + } + + /** @override */ + recordNavigatedAwayThroughBrowserHistory() { + this.recordInteraction_( + NuxSignInInterstitialInteractions.NavigatedAwayThroughBrowserHistory); + } + + /** @override */ + recordSkip() { + this.recordInteraction_(NuxSignInInterstitialInteractions.Skip); + } + + /** @override */ + recordSignIn() { + this.recordInteraction_(NuxSignInInterstitialInteractions.SignIn); + } + + /** + * @param {number} interaction + * @private + */ + recordInteraction_(interaction) { + chrome.metricsPrivate.recordEnumerationValue( + NUX_SIGNIN_VIEW_INTERACTION_METRIC_NAME, interaction, + NUX_SIGNIN_VIEW_INTERACTIONS_COUNT); + } + } + + cr.addSingletonGetter(SigninViewProxyImpl); + + return { + SigninViewProxy: SigninViewProxy, + SigninViewProxyImpl: SigninViewProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.html index 565172be89f..165ac0a3efb 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.html @@ -9,5 +9,6 @@ </head> <body> <welcome-app></welcome-app> + <script src="/welcome.js"></script> </body> </html> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.js new file mode 100644 index 00000000000..2e78a6476da --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome.js @@ -0,0 +1,15 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This file should only be included once. It will generate an assert error if + * it's included more than once, which can happen when an include is misspelled. + */ + +cr.exportPath('welcome'); +assert( + !welcome.defaultResourceLoaded, + 'welcome.js run twice. You probably have an invalid import.'); +/** Global defined when the main welcome script runs. */ +welcome.defaultResourceLoaded = true; diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html index 31388710dcc..b9cdecae74e 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html @@ -1,12 +1,22 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_view_manager/cr_view_manager.html"> -<link rel="import" href="navigation_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/html/promise_resolver.html"> +<link rel="import" href="google_apps/nux_google_apps.html"> +<link rel="import" href="email/nux_email.html"> <link rel="import" href="landing_view.html"> +<link rel="import" href="navigation_behavior.html"> +<link rel="import" href="set_as_default/nux_set_as_default.html"> +<link rel="import" href="set_as_default/nux_set_as_default_proxy.html"> +<link rel="import" href="shared/bookmark_proxy.html"> +<link rel="import" href="shared/i18n_setup.html"> +<link rel="import" href="signin_view.html"> <dom-module id="welcome-app"> <template> - <style include="paper-button-style"> + <style include="paper-button-style cr-hidden-style"> #viewManager { align-items: center; display: flex; @@ -17,17 +27,16 @@ min-height: 100vh; } - [slot='view'] { - /* Each view should be centered instead of taking full page. */ - --cr-view-manager-view: { - bottom: initial; - top: initial; - right: initial; - left: initial; - }; + #viewManager :-webkit-any(nux-email, + nux-google-apps, nux-set-as-default) { + /* Override cr-view-manager's default styling for view. */ + bottom: initial; + left: initial; + right: initial; + top: initial; } </style> - <cr-view-manager id="viewManager"> + <cr-view-manager id="viewManager" hidden="[[!modulesInitialized_]]"> <landing-view id="step-landing" slot="view" class="active"></landing-view> </cr-view-manager> </template> diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js index 4122b2ea2f4..4ab89be47f9 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js @@ -11,6 +11,22 @@ */ let NuxOnboardingModules; +/** + * This list needs to be updated if new modules need to be supported in the + * onboarding flow. + * @const {!Set<string>} + */ +const MODULES_WHITELIST = new Set( + ['nux-email', 'nux-google-apps', 'nux-set-as-default', 'signin-view']); + +/** + * This list needs to be updated if new modules that need step-indicators are + * added. + * @const {!Set<string>} + */ +const MODULES_NEEDING_INDICATOR = + new Set(['nux-email', 'nux-google-apps', 'nux-set-as-default']); + Polymer({ is: 'welcome-app', @@ -19,11 +35,46 @@ Polymer({ /** @private {?welcome.Routes} */ currentRoute_: null, - // TODO(scottchen): instead of dummy, get data from finch/load time data. + /** @private {?PromiseResolver} */ + defaultCheckPromise_: null, + /** @private {NuxOnboardingModules} */ modules_: { - 'new-user': ['h1', 'h1', 'h1'], - 'returning-user': ['h3', 'h3'], + 'new-user': loadTimeData.getString('newUserModules').split(','), + 'returning-user': loadTimeData.getString('returningUserModules').split(','), + }, + + properties: { + /** @private */ + modulesInitialized_: { + type: Boolean, + // Default to false so view-manager is hidden until views are initialized. + value: false, + }, + }, + + /** @override */ + ready: function() { + this.defaultCheckPromise_ = new PromiseResolver(); + + /** @param {!nux.DefaultBrowserInfo} status */ + const defaultCheckCallback = status => { + if (status.isDefault || !status.canBeDefault) { + this.defaultCheckPromise_.resolve(false); + } else if (!status.isDisabledByPolicy && !status.isUnknownError) { + this.defaultCheckPromise_.resolve(true); + } else { // Unknown error. + this.defaultCheckPromise_.resolve(false); + } + + cr.removeWebUIListener(defaultCheckCallback); + }; + + cr.addWebUIListener('browser-default-state-changed', defaultCheckCallback); + + // TODO(scottchen): convert the request to cr.sendWithPromise + // (see https://crbug.com/874520#c6). + nux.NuxSetAsDefaultProxyImpl.getInstance().requestDefaultBrowserState(); }, /** @@ -32,46 +83,79 @@ Polymer({ * @private */ onRouteChange: function(route, step) { + const setStep = () => { + // If the specified step doesn't exist, that means there are no more + // steps. In that case, replace this page with NTP. + if (!this.$$(`#step-${step}`)) { + welcome.WelcomeBrowserProxyImpl.getInstance().goToNewTabPage( + /* replace */ true); + } else { // Otherwise, go to the chosen step of that route. + // At this point, views are ready to be shown. + this.modulesInitialized_ = true; + this.$.viewManager.switchView( + `step-${step}`, 'fade-in', 'no-animation'); + } + }; + // If the route changed, initialize the steps of modules for that route. if (this.currentRoute_ != route) { - this.currentRoute_ = route; - this.initializeModules(this.modules_[route]); + this.initializeModules(route).then(setStep); + } else { + setStep(); } - // If the specified step doesn't exist, that means there are no more steps. - // In that case, go to NTP. - if (!this.$$('#step-' + step)) - welcome.WelcomeBrowserProxyImpl.getInstance().goToNewTabPage(); - else // Otherwise, go to the chosen step of that route. - this.$.viewManager.switchView('step-' + step); + this.currentRoute_ = route; }, - /** @param {!Array<string>} modules Array of valid DOM element names. */ - initializeModules: function(modules) { - assert(this.currentRoute_); // this.currentRoute_ should be set by now. - if (this.currentRoute_ == welcome.Routes.LANDING) - return; - assert(modules); // modules should be defined if on a valid route. - + /** @param {welcome.Routes} route */ + initializeModules: function(route) { // Remove all views except landing. this.$.viewManager .querySelectorAll('[slot="view"]:not([id="step-landing"])') - .forEach(element => { - element.remove(); - }); + .forEach(element => element.remove()); + + // If it is on landing route, end here. + if (route == welcome.Routes.LANDING) { + return Promise.resolve(); + } - modules.forEach((elementTagName, index) => { - const element = document.createElement(elementTagName); - element.id = 'step-' + (index + 1); - element.setAttribute('slot', 'view'); - this.$.viewManager.appendChild(element); - - // TODO(scottchen): this is just to test routing works. Actual elements - // will have buttons that are responsible for navigation. - element.textContent = index + 1; - element.addEventListener('click', () => { - this.navigateToNextStep(); - }); - }); + let modules = this.modules_[route]; + assert(modules); // Modules should be defined if on a valid route. + + // Wait until the default-browser state and bookmark visibility are known + // before anything initializes. + return Promise + .all([ + this.defaultCheckPromise_.promise, + nux.BookmarkBarManager.getInstance().initialized, + ]) + .then(args => { + const canSetDefault = args[0]; + if (!canSetDefault) + modules = modules.filter(module => module != 'nux-set-as-default'); + + const indicatorElementCount = modules.reduce((count, module) => { + return count += MODULES_NEEDING_INDICATOR.has(module) ? 1 : 0; + }, 0); + + let indicatorActiveCount = 0; + modules.forEach((elementTagName, index) => { + // Makes sure the module specified by the feature configuration is + // whitelisted. + assert(MODULES_WHITELIST.has(elementTagName)); + + const element = document.createElement(elementTagName); + element.id = 'step-' + (index + 1); + element.setAttribute('slot', 'view'); + this.$.viewManager.appendChild(element); + + if (MODULES_NEEDING_INDICATOR.has(elementTagName)) { + element.indicatorModel = { + total: indicatorElementCount, + active: indicatorActiveCount++, + }; + } + }); + }); }, }); diff --git a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_browser_proxy.js b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_browser_proxy.js index 679fe6555ca..fd2b128e134 100644 --- a/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_browser_proxy.js +++ b/chromium/chrome/browser/resources/welcome/onboarding_welcome/welcome_browser_proxy.js @@ -11,9 +11,20 @@ cr.define('welcome', function() { /** @interface */ class WelcomeBrowserProxy { - /** @param {string} redirectUrl the URL to redirect to, after signing in. */ + /** @param {?string} redirectUrl the URL to go to, after signing in. */ handleActivateSignIn(redirectUrl) {} - goToNewTabPage() {} + + /** + * @param {?string} redirectUrl the URL to go to after backend records the + * user declining signin. + */ + handleUserDecline(redirectUrl) {} + + /** @param {boolean=} replace */ + goToNewTabPage(replace) {} + + /** @param {string} url */ + goToURL(url) {} } /** @implements {welcome.WelcomeBrowserProxy} */ @@ -24,8 +35,21 @@ cr.define('welcome', function() { } /** @override */ - goToNewTabPage() { - window.location.replace('chrome://newtab'); + handleUserDecline(redirectUrl) { + chrome.send('handleUserDecline', redirectUrl ? [redirectUrl] : []); + } + + /** @override */ + goToNewTabPage(replace) { + if (replace) + window.location.replace('chrome://newtab'); + else + window.location.assign('chrome://newtab'); + } + + /** @override */ + goToURL(url) { + window.location.assign(url); } } |