Offline-Karten Runde 5: Geraetetest-Feedback (Indikator, Flugmodus-Signal, Ent-Funklochen, Warnungs-Aktualitaet, Routen-Start-Check)
- Indikator links unter die Zoom-Regler (rechts verdeckte Legenden-Chips) - Flugmodus bei offener App -> Position raw als Funkloch-Zone (offline-Event) - Ent-Funklochen: Zonen-Liste im Offline-Modal mit X (removeDeadZone) - Warnungs-Aktualitaet: _mergeStore Bbox-Replace (aufgehobene Giftkoeder/ gefundene Hunde verschwinden; Fetch-Kreis deckt Bbox via sqrt2 ab; fresh=null merged nie) + 24h-Refresh im 50km-Umkreis beim Start - Routen offline nutzbar halten: ensureRouteCorridors beim Start-Check (Stichproben-Verify, Re-Download aus preview_track, Region-Dedupe) - Stub-Tests ins Repo: tests/js/ (r1/r3/r4/r5, alle gruen) Bump v1231
This commit is contained in:
parent
53bc27faa3
commit
6c313aca05
15 changed files with 606 additions and 52 deletions
|
|
@ -278,9 +278,44 @@ window.OfflineIndicator = (() => {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Funkloch-Zonen automatisch füllen/verifizieren, sobald Netz da ist — das Gerät lernt
|
||||
// selbst, wo Offline-Karten nötig sind. Mit Position werden nur Zonen im Umkreis
|
||||
// (50 km) geladen → Speicher bleibt minimal, ferne Zonen kommen, wenn man dort ist.
|
||||
// Flugmodus/Netzverlust bei OFFENER App = klares Funkloch-Signal (René 2026-06-08):
|
||||
// aktuelle Position direkt als Zone merken — raw in IndexedDB, denn der GL-Stack ist
|
||||
// offline evtl. nicht ladbar. Dedupe 2 km wie MapOffline.markDeadZone; Cap 50.
|
||||
function _markDeadZoneRaw(lat, lon) {
|
||||
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('meta')) { db.close(); return; }
|
||||
const store = db.transaction('meta', 'readwrite').objectStore('meta');
|
||||
const rq = store.get('deadzones');
|
||||
rq.onsuccess = () => {
|
||||
let zones = rq.result || [];
|
||||
const near = zones.some(z => {
|
||||
const dLat = (z.lat - lat) * 111, dLon = (z.lon - lon) * 111 * Math.cos(lat * Math.PI / 180);
|
||||
return Math.sqrt(dLat * dLat + dLon * dLon) < 2;
|
||||
});
|
||||
if (!near) {
|
||||
zones.push({ lat, lon, ts: Date.now(), filled: false });
|
||||
if (zones.length > 50) zones = zones.slice(-50);
|
||||
store.put(zones, 'deadzones');
|
||||
}
|
||||
db.close();
|
||||
};
|
||||
rq.onerror = () => db.close();
|
||||
};
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Start-Check (auch bei Netz-Rückkehr): Funkloch-Zonen UND Routen-Korridore in
|
||||
// Positionsnähe (50 km) füllen/verifizieren — das Gerät hält selbst aktuell, was
|
||||
// offline nötig ist (René 2026-06-08: gespeicherte Routen müssen offline nutzbar
|
||||
// bleiben, auch nach „Alles löschen"/Eviction). Ferne Gebiete kommen, wenn man dort ist.
|
||||
let _autoFillTimer = null;
|
||||
function _scheduleAutoFill(delayMs) {
|
||||
if (!_offlineTilesMode()) return;
|
||||
|
|
@ -288,12 +323,21 @@ window.OfflineIndicator = (() => {
|
|||
_autoFillTimer = setTimeout(async () => {
|
||||
if (!navigator.onLine) return;
|
||||
try {
|
||||
if (!(await _anyDeadZonesStored())) return; // nichts zu tun → GL-Stack nicht laden
|
||||
const hasZones = await _anyDeadZonesStored();
|
||||
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();
|
||||
const o = pos ? { lat: pos.lat, lon: pos.lon } : {};
|
||||
await UI.loadMapLibreUI();
|
||||
const n = await window.MapOffline?.autoFillDeadZones?.(pos ? { lat: pos.lat, lon: pos.lon } : {});
|
||||
if (n) {
|
||||
UI.toast?.info(`${n} Funkloch-${n === 1 ? 'Gebiet' : 'Gebiete'} automatisch offline gespeichert.`);
|
||||
const n = await window.MapOffline?.autoFillDeadZones?.(o) || 0;
|
||||
const k = routes.length ? (await window.MapOffline?.ensureRouteCorridors?.(routes, o) || 0) : 0;
|
||||
if (n || k) {
|
||||
const parts = [];
|
||||
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.`);
|
||||
refresh();
|
||||
}
|
||||
} catch (e) {}
|
||||
|
|
@ -471,6 +515,13 @@ window.OfflineIndicator = (() => {
|
|||
// Funkloch-Zonen nachladen: verzögert beim Start + sobald die Verbindung zurückkommt.
|
||||
_scheduleAutoFill(30_000);
|
||||
window.addEventListener('online', () => _scheduleAutoFill(8_000));
|
||||
// Flugmodus/Netzverlust bei offener App → Standort als Funkloch-Zone merken
|
||||
// (wird beim nächsten Online-Sein automatisch geladen und künftig aktuell gehalten).
|
||||
window.addEventListener('offline', async () => {
|
||||
if (!_offlineTilesMode()) return;
|
||||
const pos = await _lastKnownPos();
|
||||
if (pos) _markDeadZoneRaw(pos.lat, pos.lon);
|
||||
});
|
||||
_checkStorageQuota(); // beim Init prüfen
|
||||
setInterval(() => { _prefetchData(); refresh(); _checkStorageQuota(); }, 60_000);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue