Some checks failed
Build APK / build-apk (push) Failing after 11m29s
SvelteKit + Capacitor 6 Netzwerk-Diagnose-App: - Tool-Plattform (IP-Scan, Port, Ping, WLAN, DHCP, SNMP, Traceroute, Stresstest, iperf) - Offline-First SQLite-Cache + idempotenter Dolibarr-Sync - Natives Kotlin-Plugin NetDiagScanner (ARP, Ping, Ports, WLAN, DHCP, SNMP, Traceroute) - Backbutton-Single-Instance-Modul, Auto-Updater, Toast-System - Auftrags-/Kunden-Übersicht nach Baustellen-App-Muster - CI: [apk]-Tag → Forgejo Runner → Package Registry netdiag-apk Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
/**
|
|
* 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;
|
|
}
|