Commit 6a920289 authored by Gordon Seto's avatar Gordon Seto Committed by Chromium LUCI CQ

[CrOS Settings] Add loading indicators to eSIM flow pages.

Add loading state UI to activation code, confirmation code, and profile
discovery pages.

Add default profile image to profile discovery page.

Screenshots:
https://screenshot.googleplex.com/B7TLNiG56hJbZEF.png
https://screenshot.googleplex.com/3EdZ4PYUNj2cbKu.png
https://screenshot.googleplex.com/9M9YhorePsHxQiX.png

Bug: 1093185
Change-Id: I5d69077dda0969b72c040b7f3e751402b88aa0ae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2628014Reviewed-by: default avatarAzeem Arshad <azeemarshad@chromium.org>
Commit-Queue: Gordon Seto <gordonseto@google.com>
Cr-Commit-Position: refs/heads/master@{#843726}
parent 524c75dd
......@@ -348,6 +348,9 @@
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID" desc="Label informing the user that the activation code is invalid.">
Invalid code, please try again.
</message>
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_LOADING" desc="Label informing the user that the activation code is currently being verified.">
Verifying activation code...
</message>
<message name="IDS_CELLULAR_SETUP_ESTABLISH_NETWORK_CONNECTION" desc="Message, informing user that a network connection is being established during cellular setup">
Establishing network connection ...
</message>
......@@ -369,6 +372,9 @@
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_ERROR" desc="Message, informing the user the confirmation code entered to activate an eSIM profile is invalid and to contact their carrier.">
Unable to connect to this profile. For technical support, please contact your carrier.
</message>
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_LOADING" desc="Message, informing the user the confirmation code entered to activate an eSIM profile is currently being verified.">
Verifying confirmation code...
</message>
<!-- Upgrade notifications -->
<message name="IDS_RELAUNCH_REQUIRED_TITLE_DAYS" desc="The title of a dialog that tells users the device must be restarted within two or more days.">
......
544d231e4f61770d485b4626bc4c6262ee587d20
\ No newline at end of file
d4eacbb65f2bb3f8dfd0fe98bba9dcbe43584db7
\ No newline at end of file
......@@ -65,6 +65,7 @@ constexpr webui::LocalizedString kLocalizedStringsWithoutPlaceholders[] = {
{"scanQRCodeSuccess", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_SUCCESS},
{"qrCodeRetry", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY},
{"scanQrCodeInvalid", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID},
{"scanQrCodeLoading", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_LOADING},
{"profileListPageMessage", IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE},
{"eidPopupTitle", IDS_CELLULAR_SETUP_EID_POPUP_TITLE},
{"eidPopupDescription", IDS_CELLULAR_SETUP_EID_POPUP_DESCRIPTION},
......@@ -75,7 +76,9 @@ constexpr webui::LocalizedString kLocalizedStringsWithoutPlaceholders[] = {
{"confirmationCodeInput",
IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_INPUT},
{"confirmationCodeError",
IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_ERROR}}; // namespace
IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_ERROR},
{"confirmationCodeLoading",
IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_LOADING}}; // namespace
struct NamedBoolean {
const char* name;
......
......@@ -33,7 +33,7 @@ suite('CrComponentsActivationCodePageTest', function() {
activationCodePage.setMediaDevices(mediaDevices);
});
test('Button states', async function() {
test('UI states', async function() {
const video = activationCodePage.$$('#video');
const startScanningContainer =
activationCodePage.$$('#startScanningContainer');
......@@ -42,6 +42,7 @@ suite('CrComponentsActivationCodePageTest', function() {
const switchCameraButton = activationCodePage.$$('#switchCameraButton');
const scanSuccessContainer = activationCodePage.$$('#scanSuccessContainer');
const scanFailureContainer = activationCodePage.$$('#scanFailureContainer');
const spinner = activationCodePage.$$('paper-spinner-lite');
assertTrue(!!video);
assertTrue(!!startScanningContainer);
......@@ -50,12 +51,14 @@ suite('CrComponentsActivationCodePageTest', function() {
assertTrue(!!switchCameraButton);
assertTrue(!!scanSuccessContainer);
assertTrue(!!scanFailureContainer);
assertTrue(!!spinner);
// Initial state should only be showing the start scanning UI.
assertFalse(startScanningContainer.hidden);
assertTrue(video.hidden);
assertTrue(scanFinishContainer.hidden);
assertTrue(switchCameraButton.hidden);
assertTrue(spinner.hidden);
// Click the start scanning button.
startScanningButton.click();
......@@ -113,6 +116,9 @@ suite('CrComponentsActivationCodePageTest', function() {
assertTrue(video.hidden);
assertTrue(scanSuccessContainer.hidden);
assertFalse(scanFailureContainer.hidden);
activationCodePage.showLoadingIndicator = true;
assertFalse(spinner.hidden);
});
test('Switch camera button states', async function() {
......
......@@ -235,6 +235,7 @@ js_library("activation_code_page.m") {
deps = [
":cellular_setup_delegate.m",
":subflow_behavior.m",
"//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:i18n_behavior.m",
]
......@@ -243,13 +244,19 @@ js_library("activation_code_page.m") {
js_library("confirmation_code_page.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.m.js" ]
deps = [ "//ui/webui/resources/js:i18n_behavior.m" ]
deps = [
"//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
"//ui/webui/resources/js:i18n_behavior.m",
]
extra_deps = [ ":confirmation_code_page_module" ]
}
js_library("profile_discovery_list_item.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.m.js" ]
deps = [ "//ui/webui/resources/js:i18n_behavior.m" ]
deps = [
"//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
"//ui/webui/resources/js:i18n_behavior.m",
]
extra_deps = [ ":profile_discovery_list_item_module" ]
}
......
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.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-spinner/paper-spinner-lite.html">
<link rel="import" href="../../../html/i18n_behavior.html">
<link rel="import" href="../../../cr_elements/cr_input/cr_input.html">
<link rel="import" href="base_page.html">
......@@ -9,7 +11,7 @@
<dom-module id="activation-code-page">
<template>
<style>
<style include="iron-positioning">
[slot='page-body'] {
height: 300px;
margin-top: -20px;
......@@ -109,6 +111,23 @@
filter: brightness(2.1);
--iron-icon-fill-color: #5F6368;
}
paper-spinner-lite {
height: 20px;
position: absolute;
right: 16px;
top: 24px;
width: 20px;
}
#loadingMessage {
bottom: 0;
color: var(--google-grey-refresh-500);
font-size: var(--cr-form-field-label-font-size);
letter-spacing: .4px;
line-height: var(--cr-form-field-label-line-height);
position: absolute;
}
</style>
<base-page>
<div slot="page-body">
......@@ -160,10 +179,18 @@
</cr-button>
</div>
</div>
<cr-input id="activationCode"
<div class="relative">
<cr-input id="activationCode"
label="[[i18n('activationCode')]]"
value="{{activationCode}}">
</cr-input>
</cr-input>
<paper-spinner-lite active
hidden$="[[!showLoadingIndicator]]">
</paper-spinner-lite>
<div id="loadingMessage" hidden$="[[!showLoadingIndicator]]">
[[i18n('scanQrCodeLoading')]]
</div>
</div>
</div>
</base-page>
</template>
......
......@@ -51,6 +51,11 @@ Polymer({
observer: 'onShowErrorChanged_',
},
showLoadingIndicator: {
type: Boolean,
value: false,
},
/**
* @type {!PageState}
* @private
......
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../../../html/i18n_behavior.html">
<link rel="import" href="base_page.html">
......@@ -14,6 +15,7 @@
#outerDiv {
height: 236px;
}
.container {
width: 472px;
}
......@@ -29,9 +31,26 @@
margin-inline-end: 16px;
}
#confirmationCode {
#confirmationCodeContainer {
margin-inline-end: 16px;
}
paper-spinner-lite {
height: 20px;
position: absolute;
right: 16px;
top: 24px;
width: 20px;
}
#loadingMessage {
bottom: 0;
color: var(--google-grey-refresh-500);
font-size: var(--cr-form-field-label-font-size);
letter-spacing: .4px;
line-height: var(--cr-form-field-label-line-height);
position: absolute;
}
</style>
<base-page>
<div slot="page-body">
......@@ -45,13 +64,21 @@
[[getProfileName_(profileProperties_)]]
</div>
</div>
<cr-input id="confirmationCode"
label="[[i18n('confirmationCodeInput')]]"
value="{{confirmationCode}}"
aria-describedby="description"
error-message="[[i18n('confirmationCodeError')]]"
invalid="[[showError]]">
</cr-input>
<div id="confirmationCodeContainer" class="relative">
<cr-input id="confirmationCode"
label="[[i18n('confirmationCodeInput')]]"
value="{{confirmationCode}}"
aria-describedby="description"
error-message="[[i18n('confirmationCodeError')]]"
invalid="[[showError]]">
</cr-input>
<paper-spinner-lite active
hidden$="[[!showLoadingIndicator]]">
</paper-spinner-lite>
<div id="loadingMessage" hidden$="[[!showLoadingIndicator]]">
[[i18n('confirmationCodeLoading')]]
</div>
</div>
</div>
</div>
</div>
......
......@@ -30,6 +30,10 @@ Polymer({
type: Boolean,
},
showLoadingIndicator: {
type: Boolean,
},
/**
* @type {?chromeos.cellularSetup.mojom.ESimProfileProperties}
* @private
......
......@@ -31,17 +31,20 @@
</setup-loading-page>
<profile-discovery-list-page id="profileDiscoveryPage"
pending-profiles="[[pendingProfiles_]]"
selected-profile="{{selectedProfile_}}">
selected-profile="{{selectedProfile_}}"
show-loading-indicator="[[showPageLoadingIndicator_]]">
</profile-discovery-list-page>
<activation-code-page id="activationCodePage"
activation-code="{{activationCode_}}"
show-no-profiles-message="[[getShowNoProfilesMessage_(pendingProfiles_)]]"
show-error="{{showError_}}">
show-error="{{showError_}}"
show-loading-indicator="[[showPageLoadingIndicator_]]">
</activation-code-page>
<confirmation-code-page id="confirmationCodePage"
confirmation-code="{{confirmationCode_}}"
profile="[[selectedProfile_]]"
show-error="{{showError_}}">
show-error="{{showError_}}"
show-loading-indicator="[[showPageLoadingIndicator_]]">
</confirmation-code-page>
<final-page
id="finalPage"
......
......@@ -65,6 +65,15 @@ cr.define('cellular_setup', function() {
value: false,
},
/**
* Whether a loading indicator should be shown for the current page.
* @private {boolean}
*/
showPageLoadingIndicator_: {
type: Boolean,
value: false,
},
/**
* Profiles fetched that have status kPending.
* @type {!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>}
......@@ -169,6 +178,7 @@ cr.define('cellular_setup', function() {
* response
*/
handleProfileInstallResponse_(response) {
this.showPageLoadingIndicator_ = false;
if (response.result ===
chromeos.cellularSetup.mojom.ProfileInstallResult
.kErrorNeedsConfirmationCode) {
......@@ -313,6 +323,8 @@ cr.define('cellular_setup', function() {
/** SubflowBehavior override */
navigateForward() {
this.showError_ = false;
this.showPageLoadingIndicator_ = true;
switch (this.state_) {
case ESimUiState.ACTIVATION_CODE_ENTRY:
// Assume installing the profile doesn't require a confirmation
......@@ -329,6 +341,7 @@ cr.define('cellular_setup', function() {
this.selectedProfile_.installProfile('').then(
this.handleProfileInstallResponse_.bind(this));
} else {
this.showPageLoadingIndicator_ = false;
this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY;
}
break;
......
......@@ -4,11 +4,12 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.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-spinner/paper-spinner-lite.html">
<link rel="import" href="cellular_setup_icons.html">
<dom-module id="profile-discovery-list-item">
<template>
<style include="iron-flex">
<style include="iron-flex iron-positioning">
#details {
align-items: center;
display: flex;
......@@ -24,17 +25,27 @@
color: var(--cr-primary-text-color);
}
#checkmark {
--iron-icon-fill-color: var(--google-blue-600);
.icon {
margin-inline-end: 8px;
padding-inline-end: var(--cr-section-padding);
}
#checkmark {
--iron-icon-fill-color: var(--google-blue-600);
}
paper-spinner-lite {
height: 16px;
vertical-align: middle;
width: 16px;
}
</style>
<div class="two-line no-padding" selectable>
<div class="flex layout horizontal center link-wrapper">
<div id="details" no-flex$="false">
<!-- TODO(crbug.com/1093185): Update UI to new spec. -->
<div id="details">
<!-- TODO(crbug.com/1093185): Update with real profile image. -->
<img id="profileImage" src="../../../images/200-logo_googleg.png">
<img id="profileImage" src="default_esim_profile.svg">
<!-- The item's aria properties are set in profile_discovery_list_page. -->
<div class="flex settings-box-text">
<div id="profileTitleLabel">
......@@ -45,11 +56,17 @@
</div>
</div>
</div>
<iron-icon id="checkmark"
icon="cellular-setup:checked"
hidden$="[[!selected]]"
tabindex="-1">
</iron-icon>
<div class="icon"
hidden$="[[!selected]]">
<iron-icon id="checkmark"
icon="cellular-setup:checked"
tabindex="-1"
hidden$="[[showLoadingIndicator]]">
</iron-icon>
<paper-spinner-lite active
hidden$="[[!showLoadingIndicator]]">
</paper-spinner-lite>
</div>
</div>
</div>
</template>
......
......@@ -26,6 +26,10 @@ Polymer({
reflectToAttribute: true,
},
showLoadingIndicator: {
type: Boolean,
},
/**
* @type {?chromeos.cellularSetup.mojom.ESimProfileProperties}
* @private
......
......@@ -43,7 +43,8 @@
selected="[[isProfileSelected_(item, selectedProfile)]]"
tabindex="0"
role="option"
aria-selected="[[isProfileSelected_(item, selectedProfile)]]">
aria-selected="[[isProfileSelected_(item, selectedProfile)]]"
show-loading-indicator="[[showLoadingIndicator]]">
</profile-discovery-list-item>
</template>
</iron-list>
......
......@@ -29,6 +29,10 @@ Polymer({
type: Object,
notify: true,
},
showLoadingIndicator: {
type: Boolean,
},
},
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment