CCA: Enhance multi-page document scanning UI
* Store cropped blobs to speed up saving/sharing files.
* Wait for cropping when closing the review UI to avoid flickering.
* Don't close the review UI when saving files fails.
Bug: b:223089758
Test: tast run dut camera.CCAUIDocumentScanning*. Trigger error when saving files. Add delay in cropping images and close the UI by pressing ESC.
Change-Id: I5389c945cc2bfb11fffdf42e32a6aa091bd0e331
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4008139
Commit-Queue: Chu-Hsuan Yang <chuhsuan@chromium.org>
Reviewed-by: Wei Lee <wtlee@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1069568}
diff --git a/ash/webui/camera_app_ui/resources/css/mode/scan.css b/ash/webui/camera_app_ui/resources/css/mode/scan.css
index ec8324b..5fdf1d84 100644
--- a/ash/webui/camera_app_ui/resources/css/mode/scan.css
+++ b/ash/webui/camera_app_ui/resources/css/mode/scan.css
@@ -425,15 +425,15 @@
}
#view-document-review {
- --preview-area-padding-inline-end: 22px;
- --preview-area-padding-inline-start: 26px;
--buttons-container-height: calc(var(--bottom-line) * 2);
+ --preview-area-padding-inline-end: calc(var(--right-line) * 2);
+ --preview-area-padding-inline-start: calc(var(--left-line) * 2);
display: flex;
}
-#view-document-review.single {
- --preview-area-padding-inline-end: calc(var(--right-line) * 2);
- --preview-area-padding-inline-start: calc(var(--left-line) * 2);
+#view-document-review:has(.page:nth-child(2)) {
+ --preview-area-padding-inline-end: 22px;
+ --preview-area-padding-inline-start: 26px;
}
#view-document-review .document-pages {
@@ -443,7 +443,7 @@
padding: 16px;
}
-#view-document-review.single .document-pages {
+#view-document-review:not(:has(.page:nth-child(2))) .document-pages {
display: none;
}
@@ -563,7 +563,7 @@
justify-content: center;
}
-#view-document-review:not(.single) .document-preview-mode button[i18n-text=label_save_photo_document] {
+#view-document-review:has(.page:nth-child(2)) .document-preview-mode button[i18n-text=label_save_photo_document] {
display: none;
}
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_review.ts b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
index 0f62e61..ea52c8a 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_review.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
@@ -51,6 +51,7 @@
interface PageInternal extends Page {
isCornersUpdated: boolean;
isRotationUpdated: boolean;
+ croppedBlob: Blob;
}
export enum Mode {
@@ -95,7 +96,6 @@
pages: 'document-pages',
preview: 'document-preview',
thumbnail: 'thumbnail',
- single: 'single',
} as const;
private readonly pageTemplateSelector = '#document-review-page';
@@ -222,10 +222,17 @@
mimeType === MimeType.JPEG ? DocScanResultActionType.SAVE_AS_PHOTO :
DocScanResultActionType.SAVE_AS_PDF);
nav.open(ViewName.FLASH);
- this.save(mimeType).then(() => this.clearPages()).finally(() => {
- this.close();
- nav.close(ViewName.FLASH);
- });
+ this.save(mimeType)
+ .then(() => {
+ this.clearPages();
+ this.close();
+ })
+ .catch(() => {
+ showToast(I18nString.ERROR_MSG_SAVE_FILE_FAILED);
+ })
+ .finally(() => {
+ nav.close(ViewName.FLASH);
+ });
},
});
this.modes = {
@@ -239,15 +246,15 @@
* Adds a page to `this.pages` and updates related elements.
*/
async addPage(page: Page): Promise<void> {
+ const {blob: croppedBlob} = await this.crop(page);
const pageInternal: PageInternal = {
...page,
isCornersUpdated: false,
isRotationUpdated: false,
+ croppedBlob,
};
- const croppedPage = await this.crop(pageInternal);
- await this.addPageView(croppedPage.blob);
+ await this.addPageView(croppedBlob);
this.pages.push(pageInternal);
- this.root.classList.toggle(this.classes.single, this.pages.length === 1);
}
private async addPageView(blob: Blob): Promise<void> {
@@ -261,21 +268,13 @@
* is JPEG, only saves the first page.
*/
private async save(mimeType: MimeType.JPEG|MimeType.PDF): Promise<void> {
- const blobs = await Promise.all(this.pages.map(async (page) => {
- const croppedPage = await this.crop(page);
- return croppedPage.blob;
- }));
+ const blobs = this.pages.map((page) => page.croppedBlob);
const name = (new Filenamer()).newDocumentName(mimeType);
- try {
- if (mimeType === MimeType.JPEG) {
- await this.resultSaver.savePhoto(blobs[0], name, null);
- } else {
- const pdfBlob = await ChromeHelper.getInstance().convertToPdf(blobs);
- await this.resultSaver.savePhoto(pdfBlob, name, null);
- }
- } catch (e) {
- showToast(I18nString.ERROR_MSG_SAVE_FILE_FAILED);
- throw e;
+ if (mimeType === MimeType.JPEG) {
+ await this.resultSaver.savePhoto(blobs[0], name, null);
+ } else {
+ const pdfBlob = await ChromeHelper.getInstance().convertToPdf(blobs);
+ await this.resultSaver.savePhoto(pdfBlob, name, null);
}
}
@@ -284,10 +283,7 @@
* share the first page.
*/
private async share(mimeType: MimeType.JPEG|MimeType.PDF): Promise<void> {
- const blobs = await Promise.all(this.pages.map(async (page) => {
- const croppedPage = await this.crop(page);
- return croppedPage.blob;
- }));
+ const blobs = this.pages.map((page) => page.croppedBlob);
const name = (new Filenamer()).newDocumentName(mimeType);
const blob = mimeType === MimeType.JPEG ?
blobs[0] :
@@ -396,10 +392,10 @@
private async updatePageInternal(index: number, page: PageInternal):
Promise<void> {
- const croppedPage = await this.crop(page);
+ const {blob: croppedBlob} = await this.crop(page);
const pageElement = this.pagesElement.children[index];
- await this.updatePageView(pageElement, croppedPage.blob);
- this.pages[index] = page;
+ await this.updatePageView(pageElement, croppedBlob);
+ this.pages[index] = {...page, croppedBlob};
}
private async updatePageView(pageElement: ParentNode, blob: Blob):
@@ -431,7 +427,6 @@
await this.selectPage(
this.selectedIndex === this.pages.length ? this.pages.length - 1 :
this.selectedIndex);
- this.root.classList.toggle(this.classes.single, this.pages.length === 1);
}
private deletePageView(index: number): void {
@@ -482,7 +477,7 @@
this.pagesElement.replaceChildren();
}
- private async crop(page: PageInternal): Promise<PageInternal> {
+ private async crop(page: Page): Promise<Page> {
const {blob, corners, rotation} = page;
const newBlob = await ChromeHelper.getInstance().convertToDocument(
blob, corners, rotation, MimeType.JPEG);
@@ -512,6 +507,7 @@
protected override leaving(): boolean {
this.hideMultiPageAvailableIndicator?.();
this.hideMultiPageAvailableIndicator = null;
+ this.waitForUpdatingPage();
if (this.pages.length === 0) {
this.fixCount = 0;
}