Give /scanner a md+ camera, live match inspector, and history strip (with device picker, batch scan, and tips) without regressing the mobile immersive checkout. Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
/**
|
|
* @typedef {{ current: number, total: number, file: File }} BatchProgress
|
|
*/
|
|
|
|
/**
|
|
* Run gallery identify sequentially over multiple files with progress, cancel, and per-file failure continuation.
|
|
*
|
|
* @param {File[] | FileList | Iterable<File>} files
|
|
* @param {(file: File) => Promise<unknown>} identifyFn
|
|
* @param {{
|
|
* onProgress?: (progress: BatchProgress) => void,
|
|
* onFileSuccess?: (payload: { file: File, index: number }) => void,
|
|
* onFileError?: (payload: { file: File, index: number, error: unknown }) => void,
|
|
* cancelRef?: { current: boolean },
|
|
* }} [options]
|
|
* @returns {Promise<{ results: Array<{ file: File, ok: true } | { file: File, ok: false, error: unknown }>, cancelled: boolean }>}
|
|
*/
|
|
export async function runSequentialGalleryIdentify(files, identifyFn, options = {}) {
|
|
const {
|
|
onProgress,
|
|
onFileSuccess,
|
|
onFileError,
|
|
cancelRef = { current: false },
|
|
} = options;
|
|
|
|
const list = Array.from(files || []);
|
|
const total = list.length;
|
|
const results = [];
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
if (cancelRef.current) break;
|
|
const file = list[i];
|
|
onProgress?.({ current: i + 1, total, file });
|
|
|
|
try {
|
|
await identifyFn(file);
|
|
results.push({ file, ok: true });
|
|
onFileSuccess?.({ file, index: i });
|
|
} catch (error) {
|
|
results.push({ file, ok: false, error });
|
|
onFileError?.({ file, index: i, error });
|
|
}
|
|
}
|
|
|
|
return { results, cancelled: cancelRef.current };
|
|
}
|