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:
parent
2876469e91
commit
0ba0de12b3
6 changed files with 65 additions and 24 deletions
|
|
@ -410,7 +410,7 @@ async def serve_media(path: str, request: _Request):
|
||||||
raise _HE(404, "Nicht gefunden.")
|
raise _HE(404, "Nicht gefunden.")
|
||||||
return _media_response(filepath)
|
return _media_response(filepath)
|
||||||
|
|
||||||
APP_VER = "1090" # muss mit APP_VER in app.js übereinstimmen
|
APP_VER = "1091" # muss mit APP_VER in app.js übereinstimmen
|
||||||
|
|
||||||
@app.get("/.well-known/assetlinks.json")
|
@app.get("/.well-known/assetlinks.json")
|
||||||
async def assetlinks():
|
async def assetlinks():
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||||
<link rel="stylesheet" href="/css/design-system.css?v=1090">
|
<link rel="stylesheet" href="/css/design-system.css?v=1091">
|
||||||
<link rel="stylesheet" href="/css/layout.css?v=1090">
|
<link rel="stylesheet" href="/css/layout.css?v=1091">
|
||||||
<link rel="stylesheet" href="/css/components.css?v=1090">
|
<link rel="stylesheet" href="/css/components.css?v=1091">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -625,11 +625,11 @@
|
||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
|
|
||||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||||
<script src="/js/api.js?v=1090"></script>
|
<script src="/js/api.js?v=1091"></script>
|
||||||
<script src="/js/ui.js?v=1090"></script>
|
<script src="/js/ui.js?v=1091"></script>
|
||||||
<script src="/js/app.js?v=1090"></script>
|
<script src="/js/app.js?v=1091"></script>
|
||||||
<script src="/js/worlds.js?v=1090"></script>
|
<script src="/js/worlds.js?v=1091"></script>
|
||||||
<script src="/js/offline-indicator.js?v=1090"></script>
|
<script src="/js/offline-indicator.js?v=1091"></script>
|
||||||
|
|
||||||
<!-- Feature-Seiten werden lazy geladen -->
|
<!-- Feature-Seiten werden lazy geladen -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '1090'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '1091'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
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_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||||
window.APP_VERSION = APP_VERSION;
|
window.APP_VERSION = APP_VERSION;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ window.OfflineIndicator = (() => {
|
||||||
// Cache-Namen dynamisch finden — robust gegen Versions-Updates
|
// Cache-Namen dynamisch finden — robust gegen Versions-Updates
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1';
|
const CACHE_TILES = 'ban-yaro-tiles-v1';
|
||||||
const CACHE_API = 'ban-yaro-api-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() {
|
async function _staticCache() {
|
||||||
const names = await caches.keys();
|
const names = await caches.keys();
|
||||||
|
|
@ -195,21 +196,42 @@ window.OfflineIndicator = (() => {
|
||||||
return out;
|
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() {
|
async function _prefetchTiles() {
|
||||||
if (!navigator.serviceWorker?.controller) return;
|
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 {
|
try {
|
||||||
const perm = await navigator.permissions.query({ name: 'geolocation' });
|
if (navigator.permissions && navigator.geolocation) {
|
||||||
if (perm.state !== 'granted') return; // kein Popup wenn nicht schon erlaubt
|
const perm = await navigator.permissions.query({ name: 'geolocation' });
|
||||||
const pos = await new Promise(res =>
|
if (perm.state === 'granted') {
|
||||||
navigator.geolocation.getCurrentPosition(p => res(p), () => res(null), { timeout: 5000 }));
|
const pos = await new Promise(res =>
|
||||||
if (!pos) return;
|
navigator.geolocation.getCurrentPosition(p => res(p), () => res(null), { timeout: 5000 }));
|
||||||
const urls = [];
|
if (pos) { lat = pos.coords.latitude; lon = pos.coords.longitude; }
|
||||||
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 {}
|
} 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
|
// Page-Module proaktiv fetchen — falls SW-Install sie noch nicht alle hatte
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,31 @@ window.Page_wetter = (() => {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LS_LAST_POS = 'by_last_position';
|
||||||
|
|
||||||
async function _tryAutoLocate() {
|
async function _tryAutoLocate() {
|
||||||
|
// Letzte bekannte Position als Fallback einlesen (für offline / GPS-verweigert)
|
||||||
|
let cached = null;
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(LS_LAST_POS);
|
||||||
|
if (raw) cached = JSON.parse(raw);
|
||||||
|
} catch {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pos = await API.getLocation({ timeout: 8000, maximumAge: 300_000 });
|
const pos = await API.getLocation({ timeout: 8000, maximumAge: 300_000 });
|
||||||
|
try {
|
||||||
|
localStorage.setItem(LS_LAST_POS, JSON.stringify({
|
||||||
|
lat: pos.lat, lon: pos.lon, ts: Date.now(),
|
||||||
|
}));
|
||||||
|
} catch {}
|
||||||
await _loadData(pos.lat, pos.lon);
|
await _loadData(pos.lat, pos.lon);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_showLocationError(err?.code);
|
// GPS fehlgeschlagen → letzte bekannte Position nutzen (statt Error-Banner)
|
||||||
|
if (cached?.lat != null && cached?.lon != null) {
|
||||||
|
await _loadData(cached.lat, cached.lon);
|
||||||
|
} else {
|
||||||
|
_showLocationError(err?.code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||||
const VER = '1090';
|
const VER = '1091';
|
||||||
const CACHE_VERSION = `by-v${VER}`;
|
const CACHE_VERSION = `by-v${VER}`;
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue