UX: Offline-Pfote — automatischer Tile-Prefetch + Step 5 umgebaut, SW by-v1086
- Step 5 misst jetzt 'Welt-Daten' (Streak + Wetter) statt Wiki/Übungen — die kommen automatisch beim Welten-Aufruf, kein zusätzliches Prefetch nötig (User-Wunsch: Wiki+Übungen NICHT preloaden) - Neuer _prefetchTiles(): beim App-Start werden 49+9 OSM-Tiles (Zoom 14 +13) im 3km-Umkreis automatisch gecacht — aber NUR wenn GPS-Permission schon erteilt ist (kein nerviger Popup beim Start). Damit wird Step 4 nach kurzer Zeit grün. - _fetchMissing für Step 5 lädt jetzt Streak + Wetter (statt Wiki)
This commit is contained in:
parent
94f02dbe3a
commit
307b4a5486
5 changed files with 65 additions and 18 deletions
|
|
@ -101,9 +101,9 @@
|
|||
</script>
|
||||
|
||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1085">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1085">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1085">
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1086">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1086">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1086">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
@ -625,11 +625,11 @@
|
|||
<div id="modal-container"></div>
|
||||
|
||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||
<script src="/js/api.js?v=1085"></script>
|
||||
<script src="/js/ui.js?v=1085"></script>
|
||||
<script src="/js/app.js?v=1085"></script>
|
||||
<script src="/js/worlds.js?v=1085"></script>
|
||||
<script src="/js/offline-indicator.js?v=1085"></script>
|
||||
<script src="/js/api.js?v=1086"></script>
|
||||
<script src="/js/ui.js?v=1086"></script>
|
||||
<script src="/js/app.js?v=1086"></script>
|
||||
<script src="/js/worlds.js?v=1086"></script>
|
||||
<script src="/js/offline-indicator.js?v=1086"></script>
|
||||
|
||||
<!-- Feature-Seiten werden lazy geladen -->
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '1085'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '1086'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
||||
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||
window.APP_VERSION = APP_VERSION;
|
||||
|
|
|
|||
|
|
@ -58,17 +58,23 @@ window.OfflineIndicator = (() => {
|
|||
return (await c.keys()).length >= TILE_MIN;
|
||||
} },
|
||||
|
||||
{ step: 5, title: 'Training & Wissen',
|
||||
detail: 'Übungen, Wiki-Rassen, Wetter',
|
||||
{ step: 5, title: 'Welt-Daten',
|
||||
detail: 'Streak, Wetter, Hundepass — kommt beim Welten-Aufruf',
|
||||
probe: async () => {
|
||||
const c = await caches.open(CACHE_API).catch(() => null);
|
||||
if (!c) return false;
|
||||
const urls = (await c.keys()).map(r => r.url);
|
||||
return urls.some(u => u.includes('/api/training/exercises'))
|
||||
&& urls.some(u => u.includes('/api/wiki/rassen'));
|
||||
return urls.some(u => u.includes('/api/streak/'))
|
||||
&& urls.some(u => u.includes('/api/weather'));
|
||||
} },
|
||||
];
|
||||
|
||||
// Tile-Prefetch-Konfiguration
|
||||
const TILE_PREFETCH = [
|
||||
{ zoom: 14, radius: 3 }, // 7x7 = 49 Tiles im Nahbereich
|
||||
{ zoom: 13, radius: 1 }, // 3x3 = 9 Tiles für Übersicht
|
||||
];
|
||||
|
||||
let _fab = null;
|
||||
|
||||
async function refresh() {
|
||||
|
|
@ -161,19 +167,60 @@ window.OfflineIndicator = (() => {
|
|||
}
|
||||
}
|
||||
} else if (m.step === 5) {
|
||||
tasks.push(fetch('/api/training/exercises').catch(() => {}));
|
||||
tasks.push(fetch('/api/wiki/rassen?limit=50').catch(() => {}));
|
||||
// Welt-Daten: Streak braucht Hund-ID, Wetter braucht GPS
|
||||
tasks.push(fetch('/api/weather').catch(() => {}));
|
||||
const dogId = window._appState?.activeDog?.id;
|
||||
if (dogId) tasks.push(fetch(`/api/streak/${dogId}`).catch(() => {}));
|
||||
}
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Tile-URL-Berechnung (OSM, Subdomain 'a')
|
||||
// ----------------------------------------------------------
|
||||
function _tile(lat, lon, z) {
|
||||
const n = Math.pow(2, z);
|
||||
const x = Math.floor((lon + 180) / 360 * n);
|
||||
const latRad = lat * Math.PI / 180;
|
||||
const y = Math.floor((1 - Math.log(Math.tan(latRad) + 1/Math.cos(latRad)) / Math.PI) / 2 * n);
|
||||
return { x, y };
|
||||
}
|
||||
function _tileUrls(lat, lon, zoom, radius) {
|
||||
const center = _tile(lat, lon, zoom);
|
||||
const out = [];
|
||||
for (let dx = -radius; dx <= radius; dx++) {
|
||||
for (let dy = -radius; dy <= radius; dy++) {
|
||||
out.push(`https://a.tile.openstreetmap.org/${zoom}/${center.x + dx}/${center.y + dy}.png`);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Tile-Prefetch im Umkreis der aktuellen GPS-Position (nur wenn Permission schon da)
|
||||
async function _prefetchTiles() {
|
||||
if (!navigator.serviceWorker?.controller) return;
|
||||
if (!navigator.permissions || !navigator.geolocation) return;
|
||||
try {
|
||||
const perm = await navigator.permissions.query({ name: 'geolocation' });
|
||||
if (perm.state !== 'granted') return; // kein Popup wenn nicht schon erlaubt
|
||||
const pos = await new Promise(res =>
|
||||
navigator.geolocation.getCurrentPosition(p => res(p), () => res(null), { timeout: 5000 }));
|
||||
if (!pos) return;
|
||||
const urls = [];
|
||||
TILE_PREFETCH.forEach(({ zoom, radius }) =>
|
||||
urls.push(..._tileUrls(pos.coords.latitude, pos.coords.longitude, zoom, radius)));
|
||||
navigator.serviceWorker.controller.postMessage({ type: 'CACHE_TILES', urls });
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function init() {
|
||||
refresh();
|
||||
_prefetchTiles(); // im Hintergrund
|
||||
if (navigator.serviceWorker) {
|
||||
navigator.serviceWorker.addEventListener('message', e => {
|
||||
if (e?.data?.type === 'CACHE_UPDATE') refresh();
|
||||
if (e?.data?.type === 'CACHE_UPDATE') refresh();
|
||||
if (e?.data?.type === 'CACHE_TILES_PROGRESS') refresh();
|
||||
});
|
||||
}
|
||||
setInterval(refresh, 60_000);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
============================================================ */
|
||||
|
||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||
const VER = '1085';
|
||||
const VER = '1086';
|
||||
const CACHE_VERSION = `by-v${VER}`;
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue