UX: Wetter-Preset + robusteres Tile-Prefetch (gemeinsamer LastPos), SW by-v1091

Beide nutzen jetzt by_last_position aus localStorage:

- wetter.js: speichert jede erfolgreiche GPS-Position; bei GPS-Fehler
  (kein Netz, Permission verweigert) wird der letzte bekannte Ort
  als Fallback genutzt — kein Error-Banner mehr wenn man ihn schon
  einmal hatte
- offline-indicator.js: _prefetchTiles versucht erst GPS, fällt
  dann auf den gespeicherten letzten Ort zurück → Step 5 wird auch
  ohne aktive GPS-Permission grün, sobald Wetter (oder andere
  Module) einmal eine Position eingeloggt haben
- TILE_MIN von 50 auf 20 gesenkt — 5x4 Tiles reichen für eine
  brauchbare Offline-Karte im Nahbereich
This commit is contained in:
rene 2026-05-26 17:10:52 +02:00
parent 2876469e91
commit 0ba0de12b3
6 changed files with 65 additions and 24 deletions

View file

@ -11,7 +11,8 @@ window.OfflineIndicator = (() => {
// Cache-Namen dynamisch finden — robust gegen Versions-Updates
const CACHE_TILES = 'ban-yaro-tiles-v1';
const CACHE_API = 'ban-yaro-api-v1';
const TILE_MIN = 50;
const TILE_MIN = 20; // niedriger Schwellwert: 5x4 Tiles reichen für Nahbereich
const LS_LAST_POS = 'by_last_position'; // teilt sich Storage mit wetter.js
async function _staticCache() {
const names = await caches.keys();
@ -195,21 +196,42 @@ window.OfflineIndicator = (() => {
return out;
}
// Tile-Prefetch im Umkreis der aktuellen GPS-Position (nur wenn Permission schon da)
// Tile-Prefetch — versucht aktuelle GPS-Position, sonst fällt auf gespeicherte zurück
async function _prefetchTiles() {
if (!navigator.serviceWorker?.controller) return;
if (!navigator.permissions || !navigator.geolocation) return;
let lat = null, lon = null;
// 1. Versuch: GPS wenn Permission schon erteilt (kein Popup)
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 });
if (navigator.permissions && navigator.geolocation) {
const perm = await navigator.permissions.query({ name: 'geolocation' });
if (perm.state === 'granted') {
const pos = await new Promise(res =>
navigator.geolocation.getCurrentPosition(p => res(p), () => res(null), { timeout: 5000 }));
if (pos) { lat = pos.coords.latitude; lon = pos.coords.longitude; }
}
}
} catch {}
// 2. Fallback: zuletzt bekannte Position aus localStorage (gesetzt von wetter.js u.a.)
if (lat == null) {
try {
const raw = localStorage.getItem(LS_LAST_POS);
if (raw) {
const stored = JSON.parse(raw);
if (stored?.lat != null && stored?.lon != null) {
lat = stored.lat; lon = stored.lon;
}
}
} catch {}
}
if (lat == null) return;
const urls = [];
TILE_PREFETCH.forEach(({ zoom, radius }) =>
urls.push(..._tileUrls(lat, lon, zoom, radius)));
navigator.serviceWorker.controller.postMessage({ type: 'CACHE_TILES', urls });
}
// Page-Module proaktiv fetchen — falls SW-Install sie noch nicht alle hatte