From 591147e72b2d1e248c466516badab402d7085c81 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 12:25:12 +0900 Subject: [PATCH 1/6] feat: implement progress bar for export all (#110) --- frontend/src/App.tsx | 15 +++++++++++++-- frontend/src/hooks/useExport.ts | 14 +++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7cdf312..b0521cc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -30,6 +30,7 @@ function App() { const [openMenuVisible, setOpenMenuVisible] = useState(false); const [exportMenuVisible, setExportMenuVisible] = useState(false); const canvasRef = useRef(null); + const [exportProgress, setExportProgress] = useState({ current: 0, total: 0 }); useBackgroundProcessor(); const { updateState, dismissUpdateError, triggerUpdate, restartApp } = useUpdater(); @@ -79,7 +80,8 @@ function App() { showToast, profile: settings.profile, visibility: settings.visibility, - globalJpegQuality: settings.globalJpegQuality + globalJpegQuality: settings.globalJpegQuality, + onProgress: (current, total) => setExportProgress({ current, total }) }); useEffect(() => { @@ -408,7 +410,16 @@ function App() { -

Processing images...

+ {exportProgress.total > 0 ? ( +
+

Exporting images... ({exportProgress.current} / {exportProgress.total})

+
+
+
+
+ ) : ( +

Processing images...

+ )} ) : ( <> diff --git a/frontend/src/hooks/useExport.ts b/frontend/src/hooks/useExport.ts index a723e6b..59361e4 100644 --- a/frontend/src/hooks/useExport.ts +++ b/frontend/src/hooks/useExport.ts @@ -17,6 +17,8 @@ export interface UseExportProps { profile: string; visibility: MetadataVisibility; globalJpegQuality: string; + + onProgress?: (current: number, total: number) => void; } const uploadCanvasBlob = async ( @@ -59,7 +61,7 @@ const uploadCanvasBlob = async ( export function useExport({ canvasRef, imageObj, currentImage, importedImages, isSelectingRef, setIsSelecting, showToast, - profile, visibility, globalJpegQuality + profile, visibility, globalJpegQuality, onProgress }: UseExportProps) { const downloadImage = async () => { @@ -119,6 +121,9 @@ export function useExport({ try { showToast("Exporting images..."); + if (onProgress) { + onProgress(0, importedImages.length); + } for (let i = 0; i < importedImages.length; i++) { const imgState = importedImages[i]; @@ -187,6 +192,10 @@ export function useExport({ imgToDraw.src = ""; } } + + if (onProgress) { + onProgress(i + 1, importedImages.length); + } } if (failCount > 0) { @@ -199,6 +208,9 @@ export function useExport({ console.error("Failed to export all:", errStr); showToast("Failed to export all: " + errStr, true); } finally { + if (onProgress) { + onProgress(0, 0); // Reset progress + } setIsSelecting(false); isSelectingRef.current = false; } From 80db6ad3c76e7786aa3c55de98cc278bd2e19cd9 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 12:34:26 +0900 Subject: [PATCH 2/6] fix: move progress bar overlay to canvas-wrapper --- frontend/src/App.tsx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b0521cc..d216a6b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -410,16 +410,7 @@ function App() { - {exportProgress.total > 0 ? ( -
-

Exporting images... ({exportProgress.current} / {exportProgress.total})

-
-
-
-
- ) : ( -

Processing images...

- )} +

Processing images...

) : ( <> @@ -439,11 +430,22 @@ function App() { pointerEvents: imageManager.isCurrentImageLoaded ? 'auto' : 'none' }} /> -
+
- Loading... + {exportProgress.total > 0 ? ( +
+ Exporting images... ({exportProgress.current} / {exportProgress.total}) +
+
+
+
+ ) : isSelecting ? ( + Processing images... + ) : ( + Loading... + )}
)} From 4f52a51bcf59e106f46b0cfc71d29caaeaf86956 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 12:55:51 +0900 Subject: [PATCH 3/6] style: move export progress to top bar --- frontend/src/App.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d216a6b..58d4cfd 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -220,7 +220,12 @@ function App() { }}>

ExifFrame

- {updateState.stage !== 'idle' && (() => { + {exportProgress.total > 0 ? ( + + ) : updateState.stage !== 'idle' && (() => { const { stage, version, downloadPct, errorMessage, releaseNotes } = updateState; if (stage === 'checking') { return ( @@ -434,14 +439,7 @@ function App() { - {exportProgress.total > 0 ? ( -
- Exporting images... ({exportProgress.current} / {exportProgress.total}) -
-
-
-
- ) : isSelecting ? ( + {isSelecting ? ( Processing images... ) : ( Loading... From 7707c8d6a5fbe5b431794c2f19e37ba58ae2a3ea Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 12:58:45 +0900 Subject: [PATCH 4/6] style: remove central processing overlay --- frontend/src/App.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 58d4cfd..5937be3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -435,15 +435,11 @@ function App() { pointerEvents: imageManager.isCurrentImageLoaded ? 'auto' : 'none' }} /> -
+
- {isSelecting ? ( - Processing images... - ) : ( - Loading... - )} + Loading...
)} From e4fa7fdcefa520816fbc676b372fa4d1dba3d5e8 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 17:28:45 +0900 Subject: [PATCH 5/6] fix: add exception handling to export progress callbacks --- frontend/src/hooks/useExport.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/frontend/src/hooks/useExport.ts b/frontend/src/hooks/useExport.ts index 59361e4..048352e 100644 --- a/frontend/src/hooks/useExport.ts +++ b/frontend/src/hooks/useExport.ts @@ -119,11 +119,19 @@ export function useExport({ let successCount = 0; let failCount = 0; - try { - showToast("Exporting images..."); + const safeOnProgress = (current: number, total: number) => { if (onProgress) { - onProgress(0, importedImages.length); + try { + onProgress(current, total); + } catch (e) { + console.error("onProgress failed:", e); + } } + }; + + try { + showToast("Exporting images..."); + safeOnProgress(0, importedImages.length); for (let i = 0; i < importedImages.length; i++) { const imgState = importedImages[i]; @@ -193,9 +201,7 @@ export function useExport({ } } - if (onProgress) { - onProgress(i + 1, importedImages.length); - } + safeOnProgress(i + 1, importedImages.length); } if (failCount > 0) { @@ -208,11 +214,9 @@ export function useExport({ console.error("Failed to export all:", errStr); showToast("Failed to export all: " + errStr, true); } finally { - if (onProgress) { - onProgress(0, 0); // Reset progress - } setIsSelecting(false); isSelectingRef.current = false; + safeOnProgress(0, 0); // Reset progress } }; From d80373353452f37bbc3c3dd9ea2a788d1e28adf2 Mon Sep 17 00:00:00 2001 From: amemya Date: Wed, 24 Jun 2026 17:36:10 +0900 Subject: [PATCH 6/6] fix: ensure export progress is updated even on error --- frontend/src/hooks/useExport.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/hooks/useExport.ts b/frontend/src/hooks/useExport.ts index 048352e..904b909 100644 --- a/frontend/src/hooks/useExport.ts +++ b/frontend/src/hooks/useExport.ts @@ -199,9 +199,8 @@ export function useExport({ if (imgToDraw && !imgState.imageObj) { imgToDraw.src = ""; } + safeOnProgress(i + 1, importedImages.length); } - - safeOnProgress(i + 1, importedImages.length); } if (failCount > 0) {