All checks were successful
Build APK / build-apk (push) Successful in 1m42s
Ersetzt den Browser-Umweg (window.open) durch einen echten In-App-Installer: das native Plugin lädt die APK streamend herunter (Fortschritts-Events updateProgress 0–100 %), prüft die Installationsberechtigung (Android 8+) und öffnet den Paketinstaller über den vorhandenen FileProvider. Versionsvergleich jetzt numerisch (YYYYMMDD-HHMM) statt lexikografisch. Banner ist schließbar; Einstellungsseite zeigt separaten Fortschrittsbalken. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
125 lines
3.8 KiB
Svelte
125 lines
3.8 KiB
Svelte
<script lang="ts">
|
||
import '../app.css';
|
||
import { onMount, onDestroy } from 'svelte';
|
||
import { goto } from '$app/navigation';
|
||
import { page } from '$app/stores';
|
||
import { auth } from '$lib/auth.svelte';
|
||
import { sync } from '$lib/sync.svelte';
|
||
import { toast } from '$lib/toast.svelte';
|
||
import { initDb } from '$lib/db';
|
||
import { registerBackListener, removeBackListener } from '$lib/backButton.svelte';
|
||
import { checkForUpdate, installUpdate, type UpdateInfo } from '$lib/updater';
|
||
import { initDebugLog } from '$lib/debuglog.svelte';
|
||
import Toast from '$lib/components/Toast.svelte';
|
||
|
||
let { children } = $props();
|
||
|
||
let booted = $state(false);
|
||
let updateInfo = $state<UpdateInfo | null>(null);
|
||
let updateDismissed = $state(false);
|
||
let updateBusy = $state(false);
|
||
let updatePercent = $state(0);
|
||
|
||
const HOME = '/auftraege/';
|
||
|
||
// Update herunterladen und Installer öffnen — Fortschritt im Banner
|
||
async function runUpdate() {
|
||
if (!updateInfo || updateBusy) return;
|
||
updateBusy = true;
|
||
updatePercent = 0;
|
||
try {
|
||
await installUpdate(updateInfo, (p) => (updatePercent = p));
|
||
// Erfolg: Android übernimmt die Installation, Banner bleibt bei 100 %
|
||
} catch (e) {
|
||
toast.show(e instanceof Error ? e.message : 'Update fehlgeschlagen', 'error', 6000);
|
||
updateBusy = false;
|
||
}
|
||
}
|
||
|
||
onMount(async () => {
|
||
initDebugLog(); // zuerst — damit auch Startfehler erfasst werden
|
||
await auth.init();
|
||
await initDb();
|
||
if (auth.loggedIn) await sync.start();
|
||
|
||
// Hardware-Backbutton (Modul-Scope, Single-Instance — KB #480/#549)
|
||
registerBackListener({
|
||
handleOverlay: () => false,
|
||
isHomeRoute: () => {
|
||
const p = $page.url.pathname;
|
||
return p === HOME || p === '/' || p === '/login/';
|
||
},
|
||
goBack: () => history.back(),
|
||
showExitHint: () => toast.show('Nochmal drücken zum Beenden'),
|
||
});
|
||
|
||
// Auf neue APK prüfen — beim Start still (kein Toast), nur Banner bei Erfolg
|
||
try {
|
||
updateInfo = await checkForUpdate();
|
||
} catch (e) {
|
||
console.warn('Update-Prüfung beim Start fehlgeschlagen:', e);
|
||
}
|
||
|
||
booted = true;
|
||
});
|
||
|
||
onDestroy(() => {
|
||
removeBackListener();
|
||
sync.stop();
|
||
});
|
||
|
||
// Auth-Gate: nicht angemeldet -> Login
|
||
$effect(() => {
|
||
if (!booted) return;
|
||
const path = $page.url.pathname;
|
||
const onLogin = path.startsWith('/login');
|
||
if (!auth.loggedIn && !onLogin) {
|
||
goto('/login/');
|
||
} else if (auth.loggedIn && onLogin) {
|
||
goto(HOME);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<div class="flex min-h-screen flex-col">
|
||
{#if !booted}
|
||
<div class="flex flex-1 items-center justify-center text-zinc-500">
|
||
<span>NetDiag startet …</span>
|
||
</div>
|
||
{:else}
|
||
{#if updateInfo && !updateDismissed}
|
||
<div class="bg-sky-700 text-sm text-white safe-top">
|
||
{#if updateBusy}
|
||
<div class="px-4 pb-2">
|
||
<div class="flex justify-between">
|
||
<span>Update wird geladen …</span>
|
||
<span class="font-mono">{updatePercent}%</span>
|
||
</div>
|
||
<div class="mt-1 h-1.5 overflow-hidden rounded bg-sky-900">
|
||
<div
|
||
class="h-full rounded bg-white transition-all"
|
||
style="width:{updatePercent}%"
|
||
></div>
|
||
</div>
|
||
</div>
|
||
{:else}
|
||
<div class="flex items-center">
|
||
<button class="flex-1 px-4 pb-2 text-left" onclick={runUpdate}>
|
||
Neue Version {updateInfo.version} verfügbar — tippen zum Aktualisieren
|
||
</button>
|
||
<button
|
||
class="px-4 pb-2 text-lg leading-none"
|
||
aria-label="Hinweis ausblenden"
|
||
onclick={() => (updateDismissed = true)}
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
{/if}
|
||
</div>
|
||
{/if}
|
||
{@render children()}
|
||
{/if}
|
||
</div>
|
||
|
||
<Toast />
|