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
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue