Fix: gelaufene km bei Routen-Navigation gehen verloren wenn nicht über
In-App-Zurück geschlossen wird (Angie-Bug) Bisher wurde walked_km NUR in _closeNav (In-App-Zurück-Pfeil) gespeichert. Wer die Navigation anders verlässt (Handy sperren/Home/PWA schließen, oder nur den Dim-Entsperrpfeil + normal schließen), verlor die km. - Fortschritt laufend in localStorage sichern (überlebt App-Kill). - _recordNavWalk() Einmal-Guard, aufgerufen von _closeNav UND pagehide. - _flushPendingNavWalk() trägt beim nächsten App-Start einen nicht gespeicherten Walk nach. - Fehler nicht mehr still verschlucken: bleibt in localStorage → Retry.
This commit is contained in:
parent
684ffa3b46
commit
91624dac25
6 changed files with 70 additions and 26 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1159
|
||||
1160
|
||||
|
|
@ -86,14 +86,14 @@
|
|||
<title>Ban Yaro</title>
|
||||
|
||||
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
||||
<script src="/js/boot-early.js?v=1159"></script>
|
||||
<script src="/js/boot-early.js?v=1160"></script>
|
||||
|
||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1159">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1159">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1159">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1159">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1159">
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1160">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1160">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1160">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1160">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1160">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
@ -617,11 +617,11 @@
|
|||
<div id="modal-container"></div>
|
||||
|
||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||
<script src="/js/api.js?v=1159"></script>
|
||||
<script src="/js/ui.js?v=1159"></script>
|
||||
<script src="/js/app.js?v=1159"></script>
|
||||
<script src="/js/worlds.js?v=1159"></script>
|
||||
<script src="/js/offline-indicator.js?v=1159"></script>
|
||||
<script src="/js/api.js?v=1160"></script>
|
||||
<script src="/js/ui.js?v=1160"></script>
|
||||
<script src="/js/app.js?v=1160"></script>
|
||||
<script src="/js/worlds.js?v=1160"></script>
|
||||
<script src="/js/offline-indicator.js?v=1160"></script>
|
||||
|
||||
<!-- Feature-Seiten werden lazy geladen -->
|
||||
|
||||
|
|
@ -631,7 +631,7 @@
|
|||
|
||||
|
||||
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
||||
<script src="/js/boot.js?v=1159"></script>
|
||||
<script src="/js/boot.js?v=1160"></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '1159'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '1160'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
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_VERSION = APP_VERSION;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ window.Page_routes = (() => {
|
|||
let _navPois = [];
|
||||
let _navMaxIdx = 0;
|
||||
let _navWalkMeta = null; // { routeId, totalKm, trackLen }
|
||||
let _navRecorded = false; // Einmal-Guard pro Navigation
|
||||
const _PENDING_WALK_KEY = 'by_pending_nav_walk'; // localStorage-Sicherheitsnetz
|
||||
let _navOrientCleanup = null;
|
||||
let _navLastBearing = null;
|
||||
let _navCompassHeading = null;
|
||||
|
|
@ -122,6 +124,7 @@ window.Page_routes = (() => {
|
|||
|
||||
_render();
|
||||
UI.loadLeaflet(); // fire & forget — bereit wenn Cards gerendert werden
|
||||
_flushPendingNavWalk(); // nicht gespeicherten Navigations-Walk nachtragen
|
||||
try { _userPos = await API.getLocation(); } catch {}
|
||||
await _loadData();
|
||||
|
||||
|
|
@ -1574,6 +1577,7 @@ window.Page_routes = (() => {
|
|||
if (track.length < 2) return;
|
||||
|
||||
_navMaxIdx = 0;
|
||||
_navRecorded = false;
|
||||
_navLastBearing = null;
|
||||
_navWalkMeta = { routeId: route.id, totalKm: route.distanz_km || 0, trackLen: track.length };
|
||||
|
||||
|
|
@ -1791,7 +1795,15 @@ window.Page_routes = (() => {
|
|||
};
|
||||
|
||||
const _updateStats = (idx, distToRoute, userLat, userLon) => {
|
||||
if (idx > _navMaxIdx) _navMaxIdx = idx;
|
||||
if (idx > _navMaxIdx) {
|
||||
_navMaxIdx = idx;
|
||||
// Fortschritt persistent sichern — überlebt App-Kill / beliebiges Schließen
|
||||
if (_navWalkMeta && _navWalkMeta.trackLen > 1) {
|
||||
const p = Math.round(_navMaxIdx / (_navWalkMeta.trackLen - 1) * 100);
|
||||
const km = Math.round((_navMaxIdx / (_navWalkMeta.trackLen - 1)) * _navWalkMeta.totalKm * 100) / 100;
|
||||
try { localStorage.setItem(_PENDING_WALK_KEY, JSON.stringify({ routeId: _navWalkMeta.routeId, walkedKm: km, pct: p, ts: Date.now() })); } catch {}
|
||||
}
|
||||
}
|
||||
const pct = Math.round(idx / (track.length - 1) * 100);
|
||||
const rem = _remainingKm(idx);
|
||||
document.getElementById('rk-nav-pct').textContent = pct + '%';
|
||||
|
|
@ -1827,6 +1839,7 @@ window.Page_routes = (() => {
|
|||
// GPS-Watch
|
||||
await _navAcquireWakeLock();
|
||||
document.addEventListener('visibilitychange', _navOnVisibility);
|
||||
window.addEventListener('pagehide', _recordNavWalk); // Schließen/Weg-Navigieren → speichern
|
||||
let _navFirstFix = true;
|
||||
_navWatchId = navigator.geolocation.watchPosition(pos => {
|
||||
const { latitude: lat, longitude: lon } = pos.coords;
|
||||
|
|
@ -1989,23 +2002,54 @@ window.Page_routes = (() => {
|
|||
}
|
||||
}
|
||||
|
||||
// Speichert den gelaufenen Walk — egal wie die Navigation verlassen wird
|
||||
// (In-App-Zurück, pagehide/Schließen). Einmal-Guard; bei Fehler bleibt der
|
||||
// Eintrag in localStorage und wird beim nächsten App-Start nachgetragen.
|
||||
function _recordNavWalk() {
|
||||
if (_navRecorded || !_navWalkMeta || _navWalkMeta.trackLen <= 1) return;
|
||||
const pct = Math.round(_navMaxIdx / (_navWalkMeta.trackLen - 1) * 100);
|
||||
if (pct < 50) return;
|
||||
_navRecorded = true;
|
||||
const walkedKm = Math.round((_navMaxIdx / (_navWalkMeta.trackLen - 1)) * _navWalkMeta.totalKm * 100) / 100;
|
||||
API.routes.walked(_navWalkMeta.routeId, walkedKm, pct)
|
||||
.then(res => {
|
||||
try { localStorage.removeItem(_PENDING_WALK_KEY); } catch {}
|
||||
if (res?.new_badges?.length) UI.toast.success(`🏅 Neues Badge: ${res.new_badges[0].name}!`);
|
||||
})
|
||||
.catch(() => {}); // bleibt in localStorage → Nachtrag beim nächsten Start
|
||||
}
|
||||
|
||||
// Beim App-/Seiten-Start: nicht gespeicherten Walk nachtragen (App gekillt /
|
||||
// „wie immer" geschlossen, ohne dass ein Speicher-Event lief).
|
||||
function _flushPendingNavWalk() {
|
||||
if (_navWatchId !== null) return; // läuft gerade eine Navigation
|
||||
let p;
|
||||
try { p = JSON.parse(localStorage.getItem(_PENDING_WALK_KEY) || 'null'); } catch {}
|
||||
if (!p || (p.pct || 0) < 50) return;
|
||||
if (Date.now() - (p.ts || 0) > 7 * 24 * 3600 * 1000) { // zu alt → verwerfen
|
||||
try { localStorage.removeItem(_PENDING_WALK_KEY); } catch {}
|
||||
return;
|
||||
}
|
||||
API.routes.walked(p.routeId, p.walkedKm, p.pct)
|
||||
.then(res => {
|
||||
try { localStorage.removeItem(_PENDING_WALK_KEY); } catch {}
|
||||
UI.toast.success('Gelaufene Tour nachgetragen 🐾');
|
||||
if (res?.new_badges?.length) UI.toast.success(`🏅 Neues Badge: ${res.new_badges[0].name}!`);
|
||||
})
|
||||
.catch(() => {}); // bleibt für den nächsten Versuch
|
||||
}
|
||||
|
||||
function _closeNav() {
|
||||
_recordNavWalk(); // ZUERST speichern (vor jedem Reset)
|
||||
if (_navWatchId !== null) { navigator.geolocation.clearWatch(_navWatchId); _navWatchId = null; }
|
||||
if (_navInactTimer) { clearTimeout(_navInactTimer); _navInactTimer = null; }
|
||||
if (_navWakeLock) { try { _navWakeLock.release(); } catch {} _navWakeLock = null; }
|
||||
document.removeEventListener('visibilitychange', _navOnVisibility);
|
||||
if (_navWalkMeta && _navWalkMeta.trackLen > 1) {
|
||||
const pct = Math.round(_navMaxIdx / (_navWalkMeta.trackLen - 1) * 100);
|
||||
if (pct >= 50) {
|
||||
const walkedKm = Math.round((_navMaxIdx / (_navWalkMeta.trackLen - 1)) * _navWalkMeta.totalKm * 100) / 100;
|
||||
API.routes.walked(_navWalkMeta.routeId, walkedKm, pct)
|
||||
.then(res => { if (res.new_badges?.length) UI.toast.success(`🏅 Neues Badge: ${res.new_badges[0].name}!`); })
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
window.removeEventListener('pagehide', _recordNavWalk);
|
||||
if (_navOrientCleanup) { _navOrientCleanup(); _navOrientCleanup = null; }
|
||||
_navWalkMeta = null;
|
||||
_navMaxIdx = 0;
|
||||
_navRecorded = false;
|
||||
_navLastBearing = null;
|
||||
_navCompassHeading = null;
|
||||
_navHeadingSmoothed = null;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script src="/js/landing-init.js?v=1159"></script>
|
||||
<script src="/js/landing-init.js?v=1160"></script>
|
||||
<title>Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz</title>
|
||||
<meta name="description" content="Ban Yaro: Die kostenlose All-in-One Hunde-App für DACH. Tagebuch, Giftköder-Alarm, Training mit KI, Forum, Wurfbörse, Stammbaum, Inzucht-Check — DSGVO-konform, offline-fähig, ohne App Store.">
|
||||
<meta name="keywords" content="Hunde App, Hunde Community, Wurfbörse, Züchter, Welpen kaufen, Stammbaum Hund, Inzuchtkoeffizient, Hundezucht, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundetraining App, Hunde Forum, Hunde KI, Hundefilm Datenbank, Welpen Marktplatz">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
============================================================ */
|
||||
|
||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||
const VER = '1159';
|
||||
const VER = '1160';
|
||||
const CACHE_VERSION = `by-v${VER}`;
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue