Offline-Karten Runde 6: Standort-Grundversorgung — aktuelles Gebiet bleibt immer geladen
Renes Modell Punkt 1 war zu eng interpretiert (nur Funkloecher): das Gebiet um die aktuelle Position gehoert zur Grundversorgung. - ensureHomeArea(lat,lon): Zentrums-Kachel-Check -> bei Luecke Budget-Download (type 'standort', Cap-gated) - Start-Check: Standort raw pruefen (ohne GL-Stack) und bei Bedarf laden - 'Alles loeschen': Standort-Gebiet wird SOFORT neu geladen (+ Toast) — vorher war die Offline-Funktionalitaet genau am wichtigsten Ort weg - Pfote Segment 5: Standort-Kachel da UND Zonen im 50-km-Umkreis gefuellt (ferne Zonen zaehlen nicht mehr — sie laden erst vor Ort) - Tests r6 + Regression r1/r3/r4/r5 gruen Bump v1234
This commit is contained in:
parent
97f0518c54
commit
94a6ce49ba
11 changed files with 185 additions and 26 deletions
|
|
@ -25,9 +25,27 @@ window.OfflineIndicator = (() => {
|
|||
function _offlineTilesMode() {
|
||||
try { return !!(window.BY && BY.offlineTiles()); } catch (e) { return false; }
|
||||
}
|
||||
// Slippy-Kachel-Koordinaten (z14, wie map-offline.js MAXZOOM) — für raw IDB-Checks
|
||||
// ohne den GL-Stack zu laden.
|
||||
function _tileKey14(lat, lon) {
|
||||
const n = Math.pow(2, 14);
|
||||
const x = Math.floor((lon + 180) / 360 * n);
|
||||
const rad = lat * Math.PI / 180;
|
||||
const y = Math.floor((1 - Math.log(Math.tan(rad) + 1 / Math.cos(rad)) / Math.PI) / 2 * n);
|
||||
return `14/${x}/${y}`;
|
||||
}
|
||||
function _lsPos() {
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_LAST_POS);
|
||||
if (raw) { const p = JSON.parse(raw); if (p?.lat != null) return { lat: p.lat, lon: p.lon }; }
|
||||
} catch {}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Offline-Ready (Pfote Segment 5) — ohne MapOffline/GL-Stack zu laden.
|
||||
// Semantik (Modell René 2026-06-08): Gibt es bekannte FUNKLOCH-Zonen, zählt deren
|
||||
// Füllstand (alle gefüllt = grün); ohne bekannte Zonen wie bisher: irgendein Gebiet da.
|
||||
// Semantik (Modell René 2026-06-08): Standort-Gebiet gespeichert UND alle bekannten
|
||||
// Funkloch-Zonen IM UMKREIS (50 km, ferne zählen nicht — sie laden erst vor Ort) gefüllt.
|
||||
// Ohne Position: irgendein Gebiet da.
|
||||
// WICHTIG: dasselbe Schema/Version wie map-offline.js anlegen — sonst legt ein versionsloses
|
||||
// open() die DB leer an und MapOffline kann seine Stores nicht mehr erstellen.
|
||||
function _offlineRegionStored() {
|
||||
|
|
@ -44,12 +62,25 @@ window.OfflineIndicator = (() => {
|
|||
if (!db.objectStoreNames.contains('tiles') || !db.objectStoreNames.contains('meta')) {
|
||||
db.close(); return res(false);
|
||||
}
|
||||
const pos = _lsPos();
|
||||
const mz = db.transaction('meta', 'readonly').objectStore('meta').get('deadzones');
|
||||
mz.onsuccess = () => {
|
||||
const zones = mz.result || [];
|
||||
if (zones.length) { res(zones.every(z => z.filled)); db.close(); return; }
|
||||
const zones = (mz.result || []).filter(z => {
|
||||
if (!pos) return true;
|
||||
const dLat = (z.lat - pos.lat) * 111,
|
||||
dLon = (z.lon - pos.lon) * 111 * Math.cos(pos.lat * Math.PI / 180);
|
||||
return Math.sqrt(dLat * dLat + dLon * dLon) <= 50;
|
||||
});
|
||||
const zonesOk = zones.every(z => z.filled);
|
||||
if (pos) {
|
||||
// Standort-Kachel vorhanden? (Grundversorgung)
|
||||
const tq = db.transaction('tiles', 'readonly').objectStore('tiles').get(_tileKey14(pos.lat, pos.lon));
|
||||
tq.onsuccess = () => { res(!!tq.result && zonesOk); db.close(); };
|
||||
tq.onerror = () => { res(false); db.close(); };
|
||||
return;
|
||||
}
|
||||
const cnt = db.transaction('tiles', 'readonly').objectStore('tiles').count();
|
||||
cnt.onsuccess = () => { res(cnt.result > 0); db.close(); };
|
||||
cnt.onsuccess = () => { res(cnt.result > 0 && zonesOk); db.close(); };
|
||||
cnt.onerror = () => { res(false); db.close(); };
|
||||
};
|
||||
mz.onerror = () => { res(false); db.close(); };
|
||||
|
|
@ -59,6 +90,28 @@ window.OfflineIndicator = (() => {
|
|||
});
|
||||
}
|
||||
|
||||
// Fehlt die Standort-Kachel? (raw, ohne GL-Stack) — Trigger für die Grundversorgung.
|
||||
function _homeAreaMissing(pos) {
|
||||
return new Promise(res => {
|
||||
try {
|
||||
const r = indexedDB.open('by-offline-tiles', 1);
|
||||
r.onupgradeneeded = () => {
|
||||
const d = r.result;
|
||||
if (!d.objectStoreNames.contains('tiles')) d.createObjectStore('tiles');
|
||||
if (!d.objectStoreNames.contains('meta')) d.createObjectStore('meta');
|
||||
};
|
||||
r.onsuccess = () => {
|
||||
const db = r.result;
|
||||
if (!db.objectStoreNames.contains('tiles')) { db.close(); return res(true); }
|
||||
const tq = db.transaction('tiles', 'readonly').objectStore('tiles').get(_tileKey14(pos.lat, pos.lon));
|
||||
tq.onsuccess = () => { res(!tq.result); db.close(); };
|
||||
tq.onerror = () => { res(true); db.close(); };
|
||||
};
|
||||
r.onerror = () => res(true);
|
||||
} catch (e) { res(true); }
|
||||
});
|
||||
}
|
||||
|
||||
const CHECKS = [
|
||||
{ step: 1, title: 'App-Grundgerüst',
|
||||
detail: 'CSS, Layout und Hauptmodule — die Basis',
|
||||
|
|
@ -323,18 +376,22 @@ window.OfflineIndicator = (() => {
|
|||
_autoFillTimer = setTimeout(async () => {
|
||||
if (!navigator.onLine) return;
|
||||
try {
|
||||
const pos = await _lastKnownPos();
|
||||
const hasZones = await _anyDeadZonesStored();
|
||||
const homeMissing = pos ? await _homeAreaMissing(pos) : false;
|
||||
let routes = [];
|
||||
try { routes = (await API.routes.list()) || []; } catch {}
|
||||
routes = routes.filter(r => (r.preview_track || []).length >= 2);
|
||||
if (!hasZones && !routes.length) return; // nichts zu tun → GL-Stack nicht laden
|
||||
const pos = await _lastKnownPos();
|
||||
if (!hasZones && !routes.length && !homeMissing) return; // nichts zu tun → GL-Stack nicht laden
|
||||
const o = pos ? { lat: pos.lat, lon: pos.lon } : {};
|
||||
await UI.loadMapLibreUI();
|
||||
// Standort-Grundversorgung zuerst (René: das Gebiet am aktuellen Standort ist IMMER da)
|
||||
const h = (homeMissing && pos) ? (await window.MapOffline?.ensureHomeArea?.(pos.lat, pos.lon) || 0) : 0;
|
||||
const n = await window.MapOffline?.autoFillDeadZones?.(o) || 0;
|
||||
const k = routes.length ? (await window.MapOffline?.ensureRouteCorridors?.(routes, o) || 0) : 0;
|
||||
if (n || k) {
|
||||
if (h || n || k) {
|
||||
const parts = [];
|
||||
if (h) parts.push('Standort-Gebiet');
|
||||
if (n) parts.push(`${n} Funkloch-${n === 1 ? 'Gebiet' : 'Gebiete'}`);
|
||||
if (k) parts.push(`${k} Routen-${k === 1 ? 'Korridor' : 'Korridore'}`);
|
||||
UI.toast?.info(`${parts.join(' + ')} automatisch offline gespeichert.`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue