fixing clients

new frontend
This commit is contained in:
stefan
2025-09-26 14:57:09 +02:00
parent 0da4d87823
commit 85249be62c
4 changed files with 43 additions and 10 deletions
@@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import at.mocode.clients.shared.commonui.components.AppHeader import at.mocode.clients.shared.commonui.components.AppHeader
import at.mocode.clients.shared.commonui.components.AppScaffold import at.mocode.clients.shared.commonui.components.AppScaffold
import at.mocode.clients.shared.commonui.theme.AppTheme import at.mocode.clients.shared.commonui.theme.AppTheme
@@ -15,6 +14,8 @@ import at.mocode.clients.pingfeature.PingViewModel
@Composable @Composable
fun App() { fun App() {
var currentScreen: AppScreen by remember { mutableStateOf(AppScreen.Home) } var currentScreen: AppScreen by remember { mutableStateOf(AppScreen.Home) }
// Create a single PingViewModel instance for the lifetime of the App composition.
val pingViewModel: PingViewModel = remember { PingViewModel() }
AppTheme { AppTheme {
AppScaffold( AppScaffold(
@@ -31,7 +32,6 @@ fun App() {
LandingScreen() LandingScreen()
} }
is AppScreen.Ping -> { is AppScreen.Ping -> {
val pingViewModel: PingViewModel = viewModel()
PingScreen(viewModel = pingViewModel) PingScreen(viewModel = pingViewModel)
} }
} }
+12 -3
View File
@@ -7,14 +7,23 @@
<meta name="theme-color" content="#0f172a"> <meta name="theme-color" content="#0f172a">
<link type="text/css" rel="stylesheet" href="styles.css"> <link type="text/css" rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.webmanifest"> <link rel="manifest" href="manifest.webmanifest">
<link rel="icon" href="icons/icon-192.png" type="image/png">
</head> </head>
<body> <body>
<div id="ComposeTarget"></div> <div id="ComposeTarget"></div>
<script> <script>
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
window.addEventListener('load', () => { const isLocalhost = ['localhost', '127.0.0.1', '::1'].includes(location.hostname);
navigator.serviceWorker.register('sw.js').catch(console.error); if (isLocalhost) {
}); // Unregister any existing service workers to avoid dev reload loops
navigator.serviceWorker.getRegistrations().then(regs => {
for (const reg of regs) reg.unregister();
}).catch(console.error);
} else {
window.addEventListener('load', () => {
navigator.serviceWorker.register('sw.js').catch(console.error);
});
}
} }
</script> </script>
</body> </body>
@@ -7,7 +7,7 @@
"background_color": "#ffffff", "background_color": "#ffffff",
"theme_color": "#0f172a", "theme_color": "#0f172a",
"icons": [ "icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" } { "src": "icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
] ]
} }
+27 -3
View File
@@ -1,4 +1,6 @@
const CACHE_NAME = 'meldestelle-cache-v1'; const IS_DEV = self.location.hostname === 'localhost' || self.location.hostname === '127.0.0.1' || self.location.hostname === '::1';
const CACHE_NAME = 'meldestelle-cache-v2';
const PRECACHE_URLS = [ const PRECACHE_URLS = [
'/', '/',
'/index.html', '/index.html',
@@ -6,6 +8,11 @@ const PRECACHE_URLS = [
]; ];
self.addEventListener('install', (event) => { self.addEventListener('install', (event) => {
if (IS_DEV) {
// In dev, don't precache. Just activate the SW immediately.
self.skipWaiting();
return;
}
event.waitUntil( event.waitUntil(
caches.open(CACHE_NAME) caches.open(CACHE_NAME)
.then((cache) => cache.addAll(PRECACHE_URLS)) .then((cache) => cache.addAll(PRECACHE_URLS))
@@ -14,6 +21,10 @@ self.addEventListener('install', (event) => {
}); });
self.addEventListener('activate', (event) => { self.addEventListener('activate', (event) => {
if (IS_DEV) {
event.waitUntil(self.clients.claim());
return;
}
event.waitUntil( event.waitUntil(
caches.keys().then((keys) => Promise.all( caches.keys().then((keys) => Promise.all(
keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)) keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))
@@ -22,6 +33,10 @@ self.addEventListener('activate', (event) => {
}); });
self.addEventListener('fetch', (event) => { self.addEventListener('fetch', (event) => {
if (IS_DEV) {
return; // don't interfere with dev server/HMR
}
const req = event.request; const req = event.request;
const url = new URL(req.url); const url = new URL(req.url);
@@ -29,9 +44,10 @@ self.addEventListener('fetch', (event) => {
const sameOrigin = url.origin === self.location.origin; const sameOrigin = url.origin === self.location.origin;
const isExtension = url.protocol === 'chrome-extension:'; const isExtension = url.protocol === 'chrome-extension:';
const isHotUpdate = url.pathname.includes('hot-update'); const isHotUpdate = url.pathname.includes('hot-update');
const isWebSocketUpgrade = req.headers.get('upgrade') === 'websocket';
// Ignore non-GET, cross-origin, browser extensions, and HMR/hot-update requests // Ignore non-GET, cross-origin, browser extensions, HMR, and WebSocket upgrade requests
if (req.method !== 'GET' || !isHttp || !sameOrigin || isExtension || isHotUpdate) { if (req.method !== 'GET' || !isHttp || !sameOrigin || isExtension || isHotUpdate || isWebSocketUpgrade) {
return; // Let the browser handle it return; // Let the browser handle it
} }
@@ -51,6 +67,14 @@ self.addEventListener('fetch', (event) => {
return; return;
} }
// Avoid noisy errors for favicon during dev/prod when missing
if (url.pathname === '/favicon.ico') {
event.respondWith(
fetch(req).catch(() => caches.match(req))
);
return;
}
// Cache-first for static assets // Cache-first for static assets
event.respondWith( event.respondWith(
caches.match(req).then((cached) => { caches.match(req).then((cached) => {