Commit a56e7b26 authored by Gavin Williams's avatar Gavin Williams Committed by Commit Bot

scanning: Show error toast when a scan fails to start

The toast will pop up and show for 5 seconds or be removed immediately
if the scan button is clicked again.

http://screen/9bUx9VbiapdgKrC

Bug: 1059779
Change-Id: Ifc0b44f79920b0f2daa167a5355ecdf9e1500b6e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2559254
Commit-Queue: Gavin Williams <gavinwill@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#831207}
parent bcd4545d
......@@ -81,6 +81,9 @@ class FakeScanService {
/** @private {?chromeos.scanning.mojom.ScanJobObserverRemote} */
this.scanJobObserverRemote_ = null;
/** @private {boolean} */
this.failStartScan_ = false;
this.resetForTest();
}
......@@ -88,6 +91,7 @@ class FakeScanService {
this.scanners_ = [];
this.capabilities_ = new Map();
this.scanJobObserverRemote_ = null;
this.failStartScan_ = false;
this.resolverMap_.set('getScanners', new PromiseResolver());
this.resolverMap_.set('getScannerCapabilities', new PromiseResolver());
this.resolverMap_.set('startScan', new PromiseResolver());
......@@ -142,6 +146,11 @@ class FakeScanService {
this.capabilities_ = capabilities;
}
/** @param {boolean} failStartScan */
setFailStartScan(failStartScan) {
this.failStartScan_ = failStartScan;
}
/**
* @param {number} pageNumber
* @param {number} progressPercent
......@@ -205,7 +214,7 @@ class FakeScanService {
return new Promise(resolve => {
this.scanJobObserverRemote_ = remote;
this.methodCalled('startScan');
resolve({success: true});
resolve({success: !this.failStartScan_});
});
}
......@@ -542,6 +551,42 @@ export function scanningAppTest() {
});
});
test('ScanFailedToStart', () => {
const expectedScanners = [
createScanner(firstScannerId, firstScannerName),
];
let capabilities = new Map();
capabilities.set(firstScannerId, firstCapabilities);
fakeScanService_.setFailStartScan(true);
/** @type {!CrButtonElement} */
let scanButton;
return initializeScanningApp(expectedScanners, capabilities)
.then(() => {
scanButton =
/** @type {!CrButtonElement} */ (scanningApp.$$('#scanButton'));
return fakeScanService_.whenCalled('getScannerCapabilities');
})
.then(() => {
assertFalse(scanningApp.$$('#toast').open);
// Click the Scan button and the scan will fail to start.
scanButton.click();
return fakeScanService_.whenCalled('startScan');
})
.then(() => {
assertTrue(scanningApp.$$('#toast').open);
assertEquals(
scanningApp.i18n('startScanFailedToast'),
scanningApp.$$('#toastText').textContent.trim());
assertFalse(scanButton.disabled);
assertTrue(isVisible(scanButton));
});
});
test('PanelContainerContent', () => {
const scanners = [];
const capabilities = new Map();
......
......@@ -576,6 +576,12 @@ Try tapping the mic to ask me anything.
<message name="IDS_SCANNING_APP_SHOW_FILE_LOCATION_LABEL" desc="The label for the button that opens the Files app. The Files app will open with the user's saved scan file highlighted.">
Show file location
</message>
<message name="IDS_SCANNING_APP_START_SCAN_FAILED_TOAST" desc="The error message displayed when a scan job fails to start.">
Couldn't start scanning
</message>
<message name="IDS_SCANNING_APP_GET_HELP_LINK_TEXT" desc="The text used for the link that navigates to the Scan app help webpage. This is shown to the user after a scanning error.">
Get help
</message>
<!-- Diagnostics App -->
<!-- TODO(michaelcheco): Update with finalized copies of the strings -->
......
29a4a9c4235f6c04e2619acba6d69035b187152b
\ No newline at end of file
23afbe1de7cb3886cd74c66418c1829af100ee06
\ No newline at end of file
......@@ -128,6 +128,7 @@ js_library("scanning_app") {
":scanning_browser_proxy",
":source_select",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
"//ui/webui/resources/js:i18n_behavior.m",
]
}
......
......@@ -75,6 +75,38 @@
justify-content: flex-end;
width: 289px;
}
#toast {
bottom: 0;
left: 0;
}
#toastDiv {
align-items: center;
display: flex;
min-width: 280px;
}
#infoIcon {
fill: var(--google-red-refresh-300);
margin-inline-end: 10px;
margin-inline-start: -8px;
}
#toastText {
color: var(--google-grey-200);
}
#getHelpDiv {
flex: 1;
margin-inline-start: 10px;
text-align: right;
}
#getHelpLink {
color: var(--google-blue-refresh-300);
text-decoration: none;
}
</style>
<div id="scanningContainer">
<div class="panel-container">
......@@ -146,4 +178,14 @@
</template>
</div>
</div>
<cr-toast id="toast" duration="5000">
<div id="toastDiv">
<iron-icon id="infoIcon" icon="cr:info-outline"></iron-icon>
<span id="toastText">[[i18n(toastMessageKey_)]]</span>
<!-- TODO(gavinwill): Add href to the help link when available -->
<div id="getHelpDiv">
<a id="getHelpLink" href="#">[[i18n('getHelpLinkText')]]</a>
</div>
</div>
</cr-toast>
</div>
......@@ -3,7 +3,9 @@
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_toast/cr_toast.m.js';
import 'chrome://resources/cr_elements/icons.m.js';
import 'chrome://resources/cr_elements/shared_vars_css.m.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
......@@ -178,6 +180,12 @@ Polymer({
* @private {?mojoBase.mojom.FilePath}
*/
lastScannedFilePath_: Object,
/**
* The key to retrieve the appropriate string to display in the toast.
* @private {string}
*/
toastMessageKey_: String,
},
/** @override */
......@@ -311,11 +319,14 @@ Polymer({
/** @private */
onScanClick_() {
// Force hide the toast if user attempts a new scan before the toast times
// out.
this.$.toast.hide();
if (!this.selectedScannerId || !this.selectedSource ||
!this.selectedFileType || !this.selectedColorMode ||
!this.selectedPageSize || !this.selectedResolution) {
// TODO(jschettler): Replace status text with finalized i18n strings.
this.statusText_ = 'Failed to start scan.';
this.showToast_('startScanFailedToast');
return;
}
......@@ -367,7 +378,7 @@ Polymer({
*/
onStartScanResponse_(response) {
if (!response.success) {
this.statusText_ = 'Failed to start scan.';
this.showToast_('startScanFailedToast');
return;
}
......@@ -468,4 +479,13 @@ Polymer({
this.showCancelButton_ = this.appState_ === AppState.SCANNING;
this.showDoneSection_ = this.appState_ === AppState.DONE;
},
/**
* @param {string} toastMessageKey
* @private
*/
showToast_(toastMessageKey) {
this.toastMessageKey_ = toastMessageKey;
this.$.toast.show();
},
});
......@@ -66,6 +66,7 @@ void AddScanningAppStrings(content::WebUIDataSource* html_source) {
{"fitToScanAreaOptionText",
IDS_SCANNING_APP_FIT_TO_SCAN_AREA_OPTION_TEXT},
{"flatbedOptionText", IDS_SCANNING_APP_FLATBED_OPTION_TEXT},
{"getHelpLinkText", IDS_SCANNING_APP_GET_HELP_LINK_TEXT},
{"grayscaleOptionText", IDS_SCANNING_APP_GRAYSCALE_OPTION_TEXT},
{"jpgOptionText", IDS_SCANNING_APP_JPG_OPTION_TEXT},
{"letterOptionText", IDS_SCANNING_APP_LETTER_OPTION_TEXT},
......@@ -89,6 +90,7 @@ void AddScanningAppStrings(content::WebUIDataSource* html_source) {
{"selectFolderOption", IDS_SCANNING_APP_SELECT_FOLDER_OPTION},
{"showFileLocationLabel", IDS_SCANNING_APP_SHOW_FILE_LOCATION_LABEL},
{"sourceDropdownLabel", IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL},
{"startScanFailedToast", IDS_SCANNING_APP_START_SCAN_FAILED_TOAST},
{"twoSidedDocFeederOptionText",
IDS_SCANNING_APP_TWO_SIDED_DOC_FEEDER_OPTION_TEXT}};
......
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