diff --git a/VERSION b/VERSION
index 5ec4258..a899ac6 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1159
\ No newline at end of file
+1160
\ No newline at end of file
diff --git a/backend/static/index.html b/backend/static/index.html
index a934541..1689eef 100644
--- a/backend/static/index.html
+++ b/backend/static/index.html
@@ -86,14 +86,14 @@
Ban Yaro
-
+
-
-
-
-
-
+
+
+
+
+
@@ -617,11 +617,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -631,7 +631,7 @@
-
+
diff --git a/backend/static/js/app.js b/backend/static/js/app.js
index 7a0fa2b..4e69472 100644
--- a/backend/static/js/app.js
+++ b/backend/static/js/app.js
@@ -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;
diff --git a/backend/static/js/pages/routes.js b/backend/static/js/pages/routes.js
index bf3ccaa..1632259 100644
--- a/backend/static/js/pages/routes.js
+++ b/backend/static/js/pages/routes.js
@@ -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;
diff --git a/backend/static/landing.html b/backend/static/landing.html
index ca06f56..b1d6c7b 100644
--- a/backend/static/landing.html
+++ b/backend/static/landing.html
@@ -4,7 +4,7 @@
-
+
Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz
diff --git a/backend/static/sw.js b/backend/static/sw.js
index 31c38a3..733cb37 100644
--- a/backend/static/sw.js
+++ b/backend/static/sw.js
@@ -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