diff --git a/VERSION b/VERSION
index 0e7f8bf..f704a68 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1203
\ No newline at end of file
+1204
\ No newline at end of file
diff --git a/backend/static/index.html b/backend/static/index.html
index c5f862e..9f95228 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 517c478..1a4ffcf 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 = '1203'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
+const APP_VER = '1204'; // ← 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/map-gl-mini.js b/backend/static/js/map-gl-mini.js
index e0608a5..820f846 100644
--- a/backend/static/js/map-gl-mini.js
+++ b/backend/static/js/map-gl-mini.js
@@ -28,7 +28,8 @@
// Nur fitten wenn Bounds gültig UND der Container eine Größe hat (im Modal
// ist er beim Erstellen 0×0 → fitBounds würde NaN werfen; der Re-Fit nach
// Modal-Animation greift dann).
- if (bb && !isNaN(bb.getWest()) && map.getContainer().clientWidth > 0) {
+ var _c = map.getContainer();
+ if (bb && !isNaN(bb.getWest()) && _c.clientWidth > 0 && _c.clientHeight > 0) {
var pad = 30;
if (opts && opts.padding) pad = Array.isArray(opts.padding) ? opts.padding[0] : opts.padding;
try { map.fitBounds(bb, { padding: pad, maxZoom: opts && opts.maxZoom, duration: 0 }); } catch (e) {}
diff --git a/backend/static/js/pages/routes.js b/backend/static/js/pages/routes.js
index f25a4bc..3ac5dc6 100644
--- a/backend/static/js/pages/routes.js
+++ b/backend/static/js/pages/routes.js
@@ -617,8 +617,7 @@ window.Page_routes = (() => {
UI.map.circleMarker(lls[0], { radius:7, color:'#22C55E', fillColor:'#22C55E', fillOpacity:1, weight:2 }).addTo(_suggestMap);
UI.map.circleMarker(lls.at(-1), { radius:7, color:'#EF4444', fillColor:'#EF4444', fillOpacity:1, weight:2 }).addTo(_suggestMap);
_addRouteArrows(_suggestMap, track, '#3b82f6');
- const _sfit = () => { _suggestMap?.invalidateSize(); _suggestMap?.fitBounds(poly.getBounds(), { padding: [16, 16] }); };
- _sfit(); setTimeout(_sfit, 200); setTimeout(_sfit, 500);
+ _fitRouteMap(_suggestMap, mapEl, () => poly.getBounds());
};
_initMap();
@@ -1713,14 +1712,25 @@ window.Page_routes = (() => {
stroke-linejoin="round"
stroke-linecap="round"/>
-
-
-
2 Sek. halten
+
+
`;
document.body.appendChild(ovl);
@@ -1936,23 +1946,32 @@ window.Page_routes = (() => {
_navResetInactTimer();
const dim = document.getElementById('rk-nav-dim');
+ // Entsperren reagiert NUR auf den Fingerabdruck-Knopf (2 Sek. halten) — nicht mehr
+ // auf das ganze Dim-Overlay. Tippen daneben lässt den Bildschirm bewusst gedimmt.
+ const navUnlock = document.getElementById('rk-nav-unlock-btn');
let _lpTimer = null;
const cancelLp = () => {
clearTimeout(_lpTimer);
const prog = document.getElementById('rk-nav-dim-prog');
if (prog) { prog.style.transition = 'none'; prog.style.strokeDashoffset = '150.8'; }
};
- dim.addEventListener('pointerdown', e => {
+ navUnlock.addEventListener('pointerdown', e => {
e.stopPropagation();
+ try { navUnlock.setPointerCapture(e.pointerId); } catch (err) {}
const prog = document.getElementById('rk-nav-dim-prog');
if (prog) { prog.style.transition = 'stroke-dashoffset 2s linear'; prog.style.strokeDashoffset = '0'; }
_lpTimer = setTimeout(() => {
dim.style.display = 'none'; _navDimmed = false; _navResetInactTimer();
}, 2000);
});
- dim.addEventListener('pointerup', cancelLp);
- dim.addEventListener('pointercancel', cancelLp);
- dim.addEventListener('pointerleave', cancelLp);
+ navUnlock.addEventListener('pointerup', cancelLp);
+ navUnlock.addEventListener('pointercancel', cancelLp);
+ // Verlässt der Finger den Knopf während des Haltens → abbrechen (sonst entsperrt
+ // ein wegrutschender Finger weiter). pointerleave reicht dank setPointerCapture.
+ navUnlock.addEventListener('pointerleave', cancelLp);
+ // Sicherheitsnetz: ein Tipp aufs Dim-Overlay (nicht auf den Knopf) tut nichts,
+ // aber wir schlucken ihn, damit darunterliegende Buttons nicht reagieren.
+ dim.addEventListener('pointerdown', e => { if (e.target === dim) e.stopPropagation(); });
// Aktions-Buttons
document.getElementById('rk-nav-back').addEventListener('click', _closeNav);
@@ -2655,6 +2674,23 @@ window.Page_routes = (() => {
}
}
+ // Karte robust auf die ganze Route fitten — auch wenn der Container beim Erstellen
+ // noch 0×0 ist (Modal-Animation / spätes Layout auf iOS). Feste Timeouts greifen dort
+ // oft zu früh; der ResizeObserver fittet erneut, SOBALD der Container seine endgültige
+ // Größe hat. Das war der Grund, warum die Detail-/Vorschlag-Karte auf dem Gerät beim
+ // Start-Zoom (zoom 14, center=Start) hängen blieb statt auf die Route zu zoomen.
+ function _fitRouteMap(m, el, getBounds, opts) {
+ opts = opts || { padding: [16, 16] };
+ const fit = () => { try { m.invalidateSize(); m.fitBounds(getBounds(), opts); } catch (e) {} };
+ fit();
+ setTimeout(fit, 150); setTimeout(fit, 400);
+ if (window.ResizeObserver && el) {
+ const ro = new ResizeObserver(() => { if (el.clientWidth > 0 && el.clientHeight > 0) fit(); });
+ ro.observe(el);
+ setTimeout(() => { try { ro.disconnect(); } catch (e) {} }, 4000);
+ }
+ }
+
async function _buildDetailMap(el, track) {
const lls = track.map(p => [p.lat, p.lon]);
const m = await UI.map.create(el, {
@@ -2665,11 +2701,7 @@ window.Page_routes = (() => {
_addRouteArrows(m, track, '#3b82f6');
UI.map.circleMarker(lls[0], { radius:7, color:'#22C55E', fillColor:'#22C55E', fillOpacity:1 }).addTo(m);
UI.map.circleMarker(lls.at(-1), { radius:7, color:'#EF4444', fillColor:'#EF4444', fillOpacity:1 }).addTo(m);
- // Mehrfach fitten: beim Erstellen ist der Modal-Container evtl. noch 0×0 → nach
- // der Animation (resize) erneut auf die ganze Route zoomen.
- const _fit = () => { m.invalidateSize(); m.fitBounds(poly.getBounds(), { padding:[16,16] }); };
- _fit();
- setTimeout(_fit, 200); setTimeout(_fit, 500);
+ _fitRouteMap(m, el, () => poly.getBounds());
return m;
}
diff --git a/backend/static/landing.html b/backend/static/landing.html
index d6a841b..ef1a7ff 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 d77c914..6ea395b 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 = '1203';
+const VER = '1204';
const CACHE_VERSION = `by-v${VER}`;
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten