/** * Hardware-Backbutton (Android). * * Muster aus der Wissensbasis (KB #480, #549): Den nativen Listener NICHT im * Svelte-$effect registrieren — bei State-Toggles würde er mehrfach hängen und * Taps verschlucken. Stattdessen Modul-Scope mit Single-Instance-Garantie. * * Ablauf eines Back-Taps: * 1. Gibt es einen offenen Dialog/Sheet? -> schließen (handler liefert true) * 2. Sind wir nicht auf der Hauptroute? -> eine Ebene zurück * 3. Auf der Hauptroute: 1. Tap = Hinweis, 2. Tap binnen 1,8 s = App beenden */ import { App, type PluginListenerHandle } from '@capacitor/app'; import { Capacitor } from '@capacitor/core'; interface BackConfig { /** Schließt einen offenen Overlay-Zustand. true = verarbeitet, nichts weiter tun. */ handleOverlay: () => boolean; /** true wenn die aktuelle Route die Hauptroute (Auftragsliste) ist */ isHomeRoute: () => boolean; /** Eine Navigationsebene zurück */ goBack: () => void; /** Hinweis "nochmal drücken zum Beenden" anzeigen */ showExitHint: () => void; } let listener: PluginListenerHandle | null = null; let registering = false; let config: BackConfig | null = null; let exitRequestedUntil = 0; const EXIT_WINDOW_MS = 1800; function onBackPressed(): void { if (!config) return; // 1. Overlay schließen if (config.handleOverlay()) { exitRequestedUntil = 0; return; } // 2. Nicht auf der Hauptroute -> zurück if (!config.isHomeRoute()) { exitRequestedUntil = 0; config.goBack(); return; } // 3. Hauptroute -> Doppel-Tap zum Beenden const now = Date.now(); if (now < exitRequestedUntil) { App.exitApp(); } else { exitRequestedUntil = now + EXIT_WINDOW_MS; config.showExitHint(); } } /** * Backbutton-Listener registrieren bzw. Konfiguration aktualisieren. * Mehrfachaufrufe sind sicher — der native Listener wird nur einmal angelegt. */ export function registerBackListener(cfg: BackConfig): void { config = cfg; // Callbacks immer aktualisieren if (!Capacitor.isNativePlatform()) return; if (listener || registering) return; registering = true; App.addListener('backButton', onBackPressed) .then((handle) => { listener = handle; }) .finally(() => { registering = false; }); } /** Listener endgültig entfernen (nur beim Zerstören des Root-Layouts) */ export function removeBackListener(): void { listener?.remove(); listener = null; config = null; }