Drei zusammenhängende Verhaltensfehler rund um main.js behoben: - Kamerafehler ruft die Dateiauswahl nicht mehr ohne Nutzergeste auf (Handy-Browser blockieren das). Stattdessen zeigt scan-view.js eine sichtbare, dauerhaft eingeblendete Schaltfläche "Bild auswählen"; der Kamera-Hinweis wird nicht mehr von der OCR-Verfügbarkeitsanzeige überschrieben. - Eine beim Start gefundene, gesicherte Sitzung wird nicht mehr stillschweigend übernommen, sondern über den neuen Dialog askResumeSession (resume-dialog.js, nach dem Muster von ambiguous-dialog.js) zur Fortsetzung angeboten. Fortsetzen zeigt den tatsächlich letzten Eintrag, Verwerfen löscht den gesicherten Stand. - Während einer laufenden Erkennung sind Sitzungsliste und Rückgängig- Fläche gesperrt; zusätzlich bucht ein durch einen zwischenzeitlichen Sitzungswechsel verspätetes Erkennungsergebnis nicht mehr in die neue, leere Sitzung (targetSession-Vergleich in processCapture). - Auch ohne erfasste Stapel bleibt die Sitzungsliste (und damit "Sitzung beenden") über eine Schaltfläche in der Stapel-Leiste erreichbar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
87 lines
3.1 KiB
JavaScript
87 lines
3.1 KiB
JavaScript
/**
|
|
* Baut die Hauptansicht auf und liefert Aktualisierungsfunktionen zurueck.
|
|
* Kennt weder Kamera noch Erkennung - alles kommt ueber die Rueckrufe.
|
|
*/
|
|
export function renderScanView(root, { onCapture, onUndo, onOpenList, onPickFile }) {
|
|
root.innerHTML = `
|
|
<div class="camera">
|
|
<video id="preview" playsinline muted></video>
|
|
<div class="frame"></div>
|
|
</div>
|
|
<div class="status" id="status"></div>
|
|
<button class="action capture" id="capture">Modul scannen</button>
|
|
<button class="action secondary" id="pick-file-button" hidden>Bild auswählen</button>
|
|
<div class="stacks" id="stacks"></div>
|
|
<div class="last">
|
|
<span id="last">Noch nichts erfasst</span>
|
|
<button class="action secondary" id="undo" style="min-width:64px" aria-label="Letzten Scan zurücknehmen">↶</button>
|
|
</div>
|
|
<input type="file" id="file" accept="image/*" hidden />
|
|
`;
|
|
|
|
const stacksEl = root.querySelector('#stacks');
|
|
const lastEl = root.querySelector('#last');
|
|
const statusEl = root.querySelector('#status');
|
|
const fileEl = root.querySelector('#file');
|
|
const pickFileButtonEl = root.querySelector('#pick-file-button');
|
|
|
|
root.querySelector('#capture').addEventListener('click', onCapture);
|
|
root.querySelector('#undo').addEventListener('click', onUndo);
|
|
// Klick auf die sichtbare Schaltflaeche ist selbst die Nutzergeste, die
|
|
// die versteckte Dateiauswahl oeffnen darf - anders als ein Aufruf aus dem
|
|
// Code heraus, den Handy-Browser blockieren.
|
|
pickFileButtonEl.addEventListener('click', () => fileEl.click());
|
|
fileEl.addEventListener('change', () => {
|
|
if (fileEl.files[0]) onPickFile(fileEl.files[0]);
|
|
fileEl.value = '';
|
|
});
|
|
|
|
return {
|
|
video: root.querySelector('#preview'),
|
|
|
|
/** @param {{id: string, count: number}[]} stacks */
|
|
setStacks(stacks) {
|
|
stacksEl.innerHTML = '';
|
|
if (stacks.length === 0) {
|
|
// Auch ohne erfasste Stapel muss die Sitzungsliste erreichbar
|
|
// bleiben - darueber liegt der einzige Weg zu "Sitzung beenden".
|
|
const button = document.createElement('button');
|
|
button.textContent = 'Noch keine Stapel';
|
|
button.addEventListener('click', onOpenList);
|
|
stacksEl.appendChild(button);
|
|
return;
|
|
}
|
|
for (const stack of stacks) {
|
|
const button = document.createElement('button');
|
|
button.textContent = `${stack.id}: ${stack.count}`;
|
|
button.addEventListener('click', onOpenList);
|
|
stacksEl.appendChild(button);
|
|
}
|
|
},
|
|
|
|
setLast(text) {
|
|
lastEl.textContent = text;
|
|
},
|
|
|
|
/** @param {string} text @param {boolean} warn */
|
|
setStatus(text, warn = false) {
|
|
statusEl.textContent = text;
|
|
statusEl.classList.toggle('warn', warn);
|
|
},
|
|
|
|
openFilePicker() {
|
|
fileEl.click();
|
|
},
|
|
|
|
/**
|
|
* Blendet die Ersatzweg-Schaltflaeche "Bild auswaehlen" ein oder aus.
|
|
* Wird eingeblendet, wenn die Kamera nicht zur Verfuegung steht, und
|
|
* bleibt dann dauerhaft sichtbar.
|
|
* @param {boolean} visible
|
|
*/
|
|
setFilePickerVisible(visible) {
|
|
pickFileButtonEl.hidden = !visible;
|
|
},
|
|
};
|
|
}
|