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 { ...@@ -81,6 +81,9 @@ class FakeScanService {
/** @private {?chromeos.scanning.mojom.ScanJobObserverRemote} */ /** @private {?chromeos.scanning.mojom.ScanJobObserverRemote} */
this.scanJobObserverRemote_ = null; this.scanJobObserverRemote_ = null;
/** @private {boolean} */
this.failStartScan_ = false;
this.resetForTest(); this.resetForTest();
} }
...@@ -88,6 +91,7 @@ class FakeScanService { ...@@ -88,6 +91,7 @@ class FakeScanService {
this.scanners_ = []; this.scanners_ = [];
this.capabilities_ = new Map(); this.capabilities_ = new Map();
this.scanJobObserverRemote_ = null; this.scanJobObserverRemote_ = null;
this.failStartScan_ = false;
this.resolverMap_.set('getScanners', new PromiseResolver()); this.resolverMap_.set('getScanners', new PromiseResolver());
this.resolverMap_.set('getScannerCapabilities', new PromiseResolver()); this.resolverMap_.set('getScannerCapabilities', new PromiseResolver());
this.resolverMap_.set('startScan', new PromiseResolver()); this.resolverMap_.set('startScan', new PromiseResolver());
...@@ -142,6 +146,11 @@ class FakeScanService { ...@@ -142,6 +146,11 @@ class FakeScanService {
this.capabilities_ = capabilities; this.capabilities_ = capabilities;
} }
/** @param {boolean} failStartScan */
setFailStartScan(failStartScan) {
this.failStartScan_ = failStartScan;
}
/** /**
* @param {number} pageNumber * @param {number} pageNumber
* @param {number} progressPercent * @param {number} progressPercent
...@@ -205,7 +214,7 @@ class FakeScanService { ...@@ -205,7 +214,7 @@ class FakeScanService {
return new Promise(resolve => { return new Promise(resolve => {
this.scanJobObserverRemote_ = remote; this.scanJobObserverRemote_ = remote;
this.methodCalled('startScan'); this.methodCalled('startScan');
resolve({success: true}); resolve({success: !this.failStartScan_});
}); });
} }
...@@ -542,6 +551,42 @@ export function scanningAppTest() { ...@@ -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', () => { test('PanelContainerContent', () => {
const scanners = []; const scanners = [];
const capabilities = new Map(); const capabilities = new Map();
......
...@@ -576,6 +576,12 @@ Try tapping the mic to ask me anything. ...@@ -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."> <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 Show file location
</message> </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 --> <!-- Diagnostics App -->
<!-- TODO(michaelcheco): Update with finalized copies of the strings --> <!-- 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") { ...@@ -128,6 +128,7 @@ js_library("scanning_app") {
":scanning_browser_proxy", ":scanning_browser_proxy",
":source_select", ":source_select",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//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", "//ui/webui/resources/js:i18n_behavior.m",
] ]
} }
......
...@@ -75,6 +75,38 @@ ...@@ -75,6 +75,38 @@
justify-content: flex-end; justify-content: flex-end;
width: 289px; 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> </style>
<div id="scanningContainer"> <div id="scanningContainer">
<div class="panel-container"> <div class="panel-container">
...@@ -146,4 +178,14 @@ ...@@ -146,4 +178,14 @@
</template> </template>
</div> </div>
</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> </div>
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; 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/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/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/string16.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
...@@ -178,6 +180,12 @@ Polymer({ ...@@ -178,6 +180,12 @@ Polymer({
* @private {?mojoBase.mojom.FilePath} * @private {?mojoBase.mojom.FilePath}
*/ */
lastScannedFilePath_: Object, lastScannedFilePath_: Object,
/**
* The key to retrieve the appropriate string to display in the toast.
* @private {string}
*/
toastMessageKey_: String,
}, },
/** @override */ /** @override */
...@@ -311,11 +319,14 @@ Polymer({ ...@@ -311,11 +319,14 @@ Polymer({
/** @private */ /** @private */
onScanClick_() { onScanClick_() {
// Force hide the toast if user attempts a new scan before the toast times
// out.
this.$.toast.hide();
if (!this.selectedScannerId || !this.selectedSource || if (!this.selectedScannerId || !this.selectedSource ||
!this.selectedFileType || !this.selectedColorMode || !this.selectedFileType || !this.selectedColorMode ||
!this.selectedPageSize || !this.selectedResolution) { !this.selectedPageSize || !this.selectedResolution) {
// TODO(jschettler): Replace status text with finalized i18n strings. this.showToast_('startScanFailedToast');
this.statusText_ = 'Failed to start scan.';
return; return;
} }
...@@ -367,7 +378,7 @@ Polymer({ ...@@ -367,7 +378,7 @@ Polymer({
*/ */
onStartScanResponse_(response) { onStartScanResponse_(response) {
if (!response.success) { if (!response.success) {
this.statusText_ = 'Failed to start scan.'; this.showToast_('startScanFailedToast');
return; return;
} }
...@@ -468,4 +479,13 @@ Polymer({ ...@@ -468,4 +479,13 @@ Polymer({
this.showCancelButton_ = this.appState_ === AppState.SCANNING; this.showCancelButton_ = this.appState_ === AppState.SCANNING;
this.showDoneSection_ = this.appState_ === AppState.DONE; 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) { ...@@ -66,6 +66,7 @@ void AddScanningAppStrings(content::WebUIDataSource* html_source) {
{"fitToScanAreaOptionText", {"fitToScanAreaOptionText",
IDS_SCANNING_APP_FIT_TO_SCAN_AREA_OPTION_TEXT}, IDS_SCANNING_APP_FIT_TO_SCAN_AREA_OPTION_TEXT},
{"flatbedOptionText", IDS_SCANNING_APP_FLATBED_OPTION_TEXT}, {"flatbedOptionText", IDS_SCANNING_APP_FLATBED_OPTION_TEXT},
{"getHelpLinkText", IDS_SCANNING_APP_GET_HELP_LINK_TEXT},
{"grayscaleOptionText", IDS_SCANNING_APP_GRAYSCALE_OPTION_TEXT}, {"grayscaleOptionText", IDS_SCANNING_APP_GRAYSCALE_OPTION_TEXT},
{"jpgOptionText", IDS_SCANNING_APP_JPG_OPTION_TEXT}, {"jpgOptionText", IDS_SCANNING_APP_JPG_OPTION_TEXT},
{"letterOptionText", IDS_SCANNING_APP_LETTER_OPTION_TEXT}, {"letterOptionText", IDS_SCANNING_APP_LETTER_OPTION_TEXT},
...@@ -89,6 +90,7 @@ void AddScanningAppStrings(content::WebUIDataSource* html_source) { ...@@ -89,6 +90,7 @@ void AddScanningAppStrings(content::WebUIDataSource* html_source) {
{"selectFolderOption", IDS_SCANNING_APP_SELECT_FOLDER_OPTION}, {"selectFolderOption", IDS_SCANNING_APP_SELECT_FOLDER_OPTION},
{"showFileLocationLabel", IDS_SCANNING_APP_SHOW_FILE_LOCATION_LABEL}, {"showFileLocationLabel", IDS_SCANNING_APP_SHOW_FILE_LOCATION_LABEL},
{"sourceDropdownLabel", IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL}, {"sourceDropdownLabel", IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL},
{"startScanFailedToast", IDS_SCANNING_APP_START_SCAN_FAILED_TOAST},
{"twoSidedDocFeederOptionText", {"twoSidedDocFeederOptionText",
IDS_SCANNING_APP_TWO_SIDED_DOC_FEEDER_OPTION_TEXT}}; 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