import java.util.Properties import java.io.FileInputStream plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) } val keystorePropertiesFile = rootProject.file("keystore.properties") val keystoreProperties = Properties().apply { if (keystorePropertiesFile.exists()) { load(FileInputStream(keystorePropertiesFile)) } } fun resolveSigningValue(propsKey: String, envKey: String): String? { val fromProps = keystoreProperties.getProperty(propsKey) if (!fromProps.isNullOrBlank()) return fromProps val fromEnv = System.getenv(envKey) if (!fromEnv.isNullOrBlank()) return fromEnv return null } android { namespace = "de.waypointaudio" compileSdk = 35 buildToolsVersion = "35.0.0" defaultConfig { applicationId = "de.waypointaudio" minSdk = 26 targetSdk = 35 // v2.5.18 — Bugfix: GPX-Import ist jetzt strikt additiv. // - Datenverlust-Schutz: Der GPX-Import in v2.5.17 hat über // `repository.saveAll(imported)` versehentlich alle bestehenden // Wegpunkte in sämtlichen Touren ersetzt. Ab v2.5.18 löscht ein // GPX-Import nie bestehende Daten. // - Neuer Import-Dialog mit zwei Optionen: // (A) Als neue Tour importieren (editierbarer Name, Default aus // GPX-Dateiname). // (B) Zu bestehender Tour hinzufügen (Auswahl der Tour). // Abbrechen verändert nichts. // - JSON-Import/-Export in der sichtbaren UI entfernt; das ZIP-Backup // übernimmt diese Rolle. Interne JSON-Parser/-Modelle bleiben für // Backup-Kompatibilität erhalten. // - v2.5.17 Lizenz/Pro/About bleibt unverändert. // - Alle weiteren Funktionen (Multi-Clip, Sequenzplayer, Countdown, // maximierbarer Player, Tour duplizieren, Waypoint kopieren, // Explorer/MapLibre/Routing, Backup ZIP, PTT/Atmo, Hintergrund, // Tourcover) bleiben unverändert. // // v2.5.19 — Menü- und UX-Politur: // • „Track Editor" aus dem Hauptmenü entfernt (über Explorer // erreichbar). Funktionalität (TrackDraftListScreen/-Editor) // bleibt vollständig im Code. // • „Klassische Ansicht" umbenannt zu „Bearbeitungsmodus" — bessere // UX-Begriffswahl auf Deutsch. // • „Touren ordnen" aus der einzelnen Touransicht in das Menü der // Audio-Bibliothek (HomeScreen) verschoben. Sortier-Funktion // (TourReorderDialog + WaypointViewModel.moveTour) unverändert. // • Backup: Tour-Cover (Icon + Palette + Bild) sind ab v2.5.7 // bereits Teil des ZIP-Backups (media/covers/.jpg) und // werden beim Import wiederhergestellt. v2.5.19 ist hierbei // inhaltlich unverändert; dieser Eintrag dient der Klarstellung // in der Versionshistorie. // // v2.5.20 — Phase 2 des Lizenzsystems: // • Echter Import einer .gps2audio-license-Datei über das Android // Storage Access Framework (ACTION_OPEN_DOCUMENT). // • Offline-Signaturprüfung (ECDSA P-256 SHA-256) gegen den bereits // in res/raw eingebetteten Public Key, kanonisches JSON wie im // Python-Tool (sortierte Keys, kein Whitespace). // • Lokale Ablage der validierten Lizenz in filesDir/license/ // inkl. Backup-Ausschluss (data_extraction_rules + backup_rules). // • Anzeige im About-Dialog: Status (Keine/Gültig/Ungültig/Abgelaufen), // Lizenztyp, Lizenznehmer, Gültigkeit, Lizenz-ID, Bindung, // Permissions (deutsch beschriftet). // • Buttons „Lizenz importieren / exportieren / entfernen" inkl. // Bestätigungsdialog. Keine Feature-Sperren, alle bestehenden // Funktionen bleiben unverändert nutzbar. // v2.5.21 — Re-Import-Bugfix + Geräte-ID: // • Behebt: Lizenzdatei konnte nach Entfernen + Re-Import nicht mehr // gelesen werden. Ursache: LicenseStatusProvider.initialized-Flag // wurde nach remove() nicht zurückgesetzt; kombiniert mit // transienten SAF-URI-Permissions führte das zu "Lizenzdatei konnte // nicht gelesen werden" beim zweiten Import-Versuch. // • Fix: initialized wird in remove() auf false gesetzt. import() // liest Bytes immer frisch, ohne gecachte URIs. // • Geräte-ID: app-spezifische UUID (SharedPreferences, kein Backup), // SHA-256-Hash "GPS2AudioDevice:"+uuid für Lizenz-Tool-Kompatibilität. // Anzeige + Kopier-Button im Über-Dialog. Keine harte Bindung aktiv. // v2.5.23 — Lizenzimport-Regression-Fix: // • v2.5.22 wechselte zu GetContent(), was auf manchen OEM-Geräten // (Huawei/EMUI, MIUI-Galerie-Modus) nur Medien anzeigt — .gps2audio- // license-Dateien unsichtbar, Erstimport unmöglich. // • Fix: Zurück zu OpenDocument() mit breiten MIME-Typen (json/text/ // octet-stream/*). Echter SAF-Datei-Browser zeigt alle Dateien. // • importNonce-Mechanismus: Key-basierter Launcher-Slot-Reset erzwingt // frischen SAF-Picker auch bei Wiederwahl derselben URI. // • Robustes Lesen (copyTo statt readBytes), differenzierte // Fehlermeldungen und reloadTrigger aus v2.5.22 beibehalten. // v2.5.24 — Lizenzimport-Fallbacks: // • readLicenseBytes(): drei Lesestrategien (openInputStream, openFileDescriptor, // File-Fallback) mit separater Fehlersammlung. // • Diagnose-Dialog bei Totalausfall: technische Fehlermeldungen statt generisches Toast. // • Textimport-Fallback: Button "Lizenz aus Zwischenablage / Text einfügen" öffnet // AlertDialog mit großem Textfeld + Zwischenablage-Schaltfläche. // • OpenDocument() mit nur "*/*" (keine MIME-Liste, verhindert Galerie-Modus auf MIUI). // • importNonce-Mechanismus aus v2.5.23 unverändert beibehalten. // v2.5.25 — License-Import-Thread-Fix: // • Alle blockierenden I/O-Operationen (contentResolver.openInputStream, // openFileDescriptor, FileInputStream, ByteArrayOutputStream.copyTo, // LicenseStatusProvider.import inkl. JSON/Signaturvalidierung) auf // Dispatchers.IO verschoben. Root Cause: NetworkOnMainThreadException // auf Android 9+ (StrictMode blockiert Netzwerk-/Disk-I/O auf Main-Thread). // • ActivityResult-Callback startet Coroutine (rememberCoroutineScope); // withContext(Dispatchers.IO) für readLicenseBytes + import(); // danach UI-State/Toast/reloadTrigger auf Main-Thread. // • isImporting-Flag verhindert Doppelauslösung des Import-Buttons. // • Export-Callback (openOutputStream) ebenfalls auf IO. // • Textimport: import() ebenfalls auf IO. // • Alle v2.5.24-Fallbacks (drei Lesestrategien, Diagnose-Dialog, // Textimport, OpenDocument */*, importNonce) unverändert. // v2.5.29 — Lizenz-Persistenz-Fix: Update-sichere Lizenzablage. // v2.5.30 — Home Atmo-Modul entfernt; Playback-Persistenz beim Tour-Wechsel. // • Atmo-Modul/-Toggle auf der Startseite (HomeScreen) entfernt. // Atmo bleibt vollständig in der Tour-Ansicht (WaypointListScreen) verfügbar. // • selectTour() stoppt keine laufende Wiedergabe mehr beim Tour-Wechsel. // Stop nur noch bei expliziten Nutzeraktionen: Play in anderer Tour, // Stop-Button, GPS-Dienst bewusst stoppen. // // v2.5.31 — Tourcover-Backup-Fix: frei gewählte Bilder werden jetzt // zuverlässig gesichert und beim Import wiederhergestellt. // • BackupExportManager: ZIP-Entry-Pfade für Cover-Bilder erhalten // einen eindeutigen Index-Präfix ("media/covers/001_tourname.jpg"), // damit Touren mit gleichem sanitisierten Namen nicht kollidieren. // • BackupExportManager: Fallback-Lesestrategie für Cover-Bilder: // absoluter Dateipfad → ContentResolver → file://-URI. // • BackupImportManager: Verbesserte Fehlerprotokollierung beim // Cover-Bild-Import; Rückwärtskompatibel mit v2.5.7–v2.5.30-Backups. // • Kein Änderungen am Lizenzsystem, Feature-Gates, Touren/Waypoints. // v2.5.34 — Explorer-Kontext-Fix: selectDefaultTour() beim Einstieg aus // der Audio-Bibliothek/Home verhindert das Übernehmen des zuletzt aktiven // Tour-Kontexts. Einstieg aus konkreter Tour behält Tour-Karte. // v2.5.38 — Kartenattribution, POI-Layer, Kartenstil-Persistenz. // • Kartenattribution rechtlich sauber: kompaktes Badge bottom-left // (anklickbar → openstreetmap.org/copyright), vollständiger Karteninfo- // Dialog aus dem Ebenen-Sheet (OpenFreeMap, OpenMapTiles, OSM, ODbL). // • POI-Layer-Kategorien im Ebenen-Sheet: Sehenswürdigkeiten (default an), // Infrastruktur, Gastronomie, Mobilität (default aus). Symbol-Layer des // geladenen MapLibre-Styles werden per Layer-ID-Heuristik ein-/ausgeblendet. // Auswahl wird persistent gespeichert (DataStore). Kein Crash wenn Layer fehlt. // • Kartenstil-Persistenz: baseStyle zuverlässig beim Neustart wiederhergestellt. // POI-Auswahl ebenfalls persistent. Alle MapStyleStore-Keys unverändert. // • Stylewechsel stellt Overlays, Attribution und POI-Sichtbarkeit wieder her. // • Keine Regressionen: Phantom-Layer-Fix, Lizenzsystem, Multi-Clip, // PTT, Tour-Zähler, Backup/Cover, GPX-Import, Explorer/Routing, // Tour-/Waypoint-Kopien, Hintergrundwiedergabe. // v2.6.0 — Tourverlauf/Storyboard-Konsolidierung: // • Routenplaner → "Tourverlauf" (deutsch, klar, kein Auto-Navi-Gefühl). // • Storyboard-Panel übersichtlicher beschriftet und mit Erklärtext versehen. // • Routepunkt vs. Wegpunkt (Audio) klar unterschieden in Labels. // • Online-Routing als optional/sekundär markiert, nicht ausgebaut. // • Keine Änderung an Logik, Backup, Lizenz, Playback, GPS-Aufzeichnung. // v2.6.1 — Waypoint-Dialog-Polish: Formatierungsfehler RoutePlannerSheet // behoben, WaypointEditDialog neu gestaltet (freundlichere Cards). // Keine Logik-/Datenmodell-Änderungen. // v2.7.0 — Tourverlauf-Editor: // • Neues TourverlaufEditorSheet als dedizierter Bearbeitungsmodus. // • Verlaufspunkte über Kartenmitte oder Tipp-Modus setzen. // • "Als Audio-Wegpunkt erstellen" aus Verlaufspunkt heraus. // • Online-Routing in RoutePlannerSheet sekundär (OutlinedButton). // • Status-Bar zeigt Verlaufspunkt-Anzahl im Editor-Modus. // • Persistenz/Speicherung über bestehende TourRoute/MANUAL-Infrastruktur. // • Keine Regressionen: Playback, Backup, Lizenz, GPS-Aufzeichnung unverändert. // v2.7.1 — Tourverlauf-Linie-Fix: // • Behebt: Manuelle Tourverlauf-Linie wurde dauerhaft nicht angezeigt bzw. // verschwand nach Öffnen/Schließen des Editors, Workspace-Wechsel oder // Kartenstil-Reload. // • Root Cause 1 (Race-Condition): Beim initialen Laden der Composable feuerte // der Auto-Save-LaunchedEffect mit leerem manualRoutePoints, bevor der // Load-Effekt die Punkte aus der DB geladen hatte. Bei leerem Liste UND // wasManual=true wurde deleteTourRouteForCurrent() aufgerufen — die // gespeicherte Route wurde gelöscht. Fix: manualRouteInitialized-Guard. // • Root Cause 2 (Zeichnungs-LaunchedEffect verpasst Map-Init): // mapLibreMap als Key im Drawing-LaunchedEffect fehlte. Wenn die Karte nach // einem Workspace-Wechsel asynchron initialisiert wurde, feuerte das Effect // nicht erneut (manualRoutePoints unverändert). Fix: mapLibreMap als // zusätzlicher Key. // • Root Cause 3 (Load-Effect-Keys zu breit): // activeTourRoute?.id im Load-Effect führte dazu, dass jedes Auto-Save // (neue updatedAtMillis) den Load neu auslöste. Fix: nur source als Key, // kein id. // • Verbesserung: Strichstärke der manuellen Tourverlauf-Linie erhöht // (10/7 statt 8/5) für bessere Sichtbarkeit. // • Keine Regressionen: v2.7.0 Editor, v2.6.2 Route-Persistenz, v2.6.1 // Wegpunktdialog, v2.5.48 TrackDraft-Backup, POI, 3D, Playback, Backup, // Lizenzsystem unverändert. // v2.7.3 — Planlinie Auto-Show-Fix: // • Root Cause: "Planlinie zeigen" persistierte die Planroute nur in die // ViewModel-Session (RAM), nicht in die DB. Nach App-Neustart (Prozess-Kill) // war kein activeTourRoute-Eintrag vorhanden, savedRouteLine blieb leer → // keine Linie sichtbar, Button erneut nötig. // • Fix 1 (Persistenz): onShowPlanline ruft jetzt zusätzlich // viewModel.saveTourRouteFor() auf. PLANLINE wird in der DB gespeichert. // activeTourRoute.polyline ist ab dem nächsten App-Start verfügbar. // • Fix 2 (Zeichnungs-Priorität): savedRouteLine hat jetzt Vorrang vor // routePlanline. routeLine > savedRouteLine > routePlanline. Doppelte // Überlagerung (PLANLINE-Quelle) beseitigt. // • Fix 3 (Clear-Symmetrie): onClear löscht die DB-PLANLINE-Route, wenn // der Nutzer explizit den Planer leert. OSRM/MANUAL bleiben unangetastet. // • Keine Änderungen an Datenmodell, Backup, Playback, Lizenz. // v2.7.4 — Planlinie Auto Render: // • Root Cause 1 behoben: savedRouteLine-Phantom-Guard schloss PLANLINE-Routen auf // der Standardtour aus (isNeutralStandard). PLANLINE ist bewusste Nutzeraktion, // kein Phantom — Ausnahme eingefügt. // • Root Cause 2 behoben: mapLibreMap fehlte als Key im route-drawing-LaunchedEffect. // Nach Map-Neuinitialisierung (Stylewechsel, Workspace-Rückkehr) wurde die Linie // nicht neu gezeichnet, obwohl routePlanline befüllt war. // • Auto-Persistenz: routePlanline ≥ 2 Stopps → automatisch als PLANLINE-TourRoute // in DB gespeichert, ohne Button-Druck. Button „Planlinie zeigen“ ist nur noch // Kamera-Fokus. // • Zeichnungsfarbe: PLANLINE aus savedRouteLine erhält orangene Farbe (wie routePlanline), // kein falsches Grün mehr. // • Priorität v2.7.4: routeLine (OSRM) > routePlanline (wenn PLANLINE-Quelle) > // savedRouteLine (OSRM/andere) > routePlanline (fallback) > keine Linie. // • Keine Änderungen an Datenmodell, Backup, Playback, Lizenz. // // v2.7.5 — Standard-Tour intern (Konzeptkorrektur): // • Root Cause: DEFAULT_TOUR_NAME="Standard" war bisher in der Audio-Bibliothek // als vollwertige bearbeitbare Tour sichtbar, was Phantom-/Kontextprobleme // erzeugen konnte. Standard-Tour ist eine System-Blaupause, kein Nutzerdatensatz. // • visibleTourList (neu im ViewModel): filtert Standard-Tour aus der UI-Liste, // sobald mindestens eine echte Tour existiert. tourList intern unverändert. // • Audio-Bibliothek (HomeScreen): zeigt Standard-Tour nicht mehr im Cover-Grid. // • Menü (WaypointListScreen): Umbenennen + Duplizieren für Standard-Tour deaktiviert. // Löschen war bereits gesperrt (unverändert). // • Auto-Selektion: Beim App-Start mit echten Touren wird automatisch die erste // echte Tour gewählt statt "Standard". // • Explorer isNeutralStandard, Backup, Datenmodell, Lizenz: unverändert. // v2.7.7 — Spontane Tour Autocreate: // • Root Cause: ExplorerScreenMapLibre.kt zeigte in der Topbar weiterhin // "Standard" (selectedTour direkt), da die UI-Entkopplung aus v2.7.6 // (displayTourLabel) dort nicht übernommen wurde. Fix: displayTourLabel // analog zu ExplorerScreen.kt implementiert. // • Automatische Tourerstellung beim ersten Wegpunkt im neutralen Explorer: // upsertFromNeutralExplorer() im ViewModel prüft, ob tourName == // DEFAULT_TOUR_NAME. Falls ja, erzeugt createSpontaneousTour() eine // eindeutige "Spontane Tour" (mit Suffix falls Name existiert), ruft // addTour() auf (inkl. selectedTour-Wechsel) und speichert den Wegpunkt // in der neuen Tour. Keine DB-Migration, keine neue Tabelle. // • Betroffen: neuer Wegpunkt per Tap (PlaceNew), POI als Wegpunkt, // POI zu Storyboard, Explorer-POI-Karte. Bearbeiten bestehender // Wegpunkte: normaler upsert-Pfad (keine Auto-Tour). // • Standard-Tour bleibt intern; visibleTourList (v2.7.5) blendet // sie weiterhin aus, sobald echte Touren existieren. // • Keine Änderungen an Backup, Lizenz, Playback, PTT, Atmo, GPS-Track. // v2.7.8 — Unbenannte Tour + Planlinie Auto-Render: // • 'Spontane Tour' → 'Unbenannte Tour': UI-String explorer_spontane_tour // und createSpontaneousTour()-Basisname geändert. Schlüssel bleibt für // risikoarmes Deployment; Funktionsname intern unverändert. // • Root Cause Planlinie: Beim ersten Rendern nach App-Neustart oder // Workspace-Rückkehr war savedRouteLine befüllt, wurde aber nicht in // routeLine übertragen. routeLine ist die primäre Zeichnungsquelle. // Folge: LaunchedEffect-Zeichnung lief, zog aber savedRouteLine nur // als sekundären Fallback (grüne Linie). Die sichtbarkeitsblockierende // Hürde: manuelle Sitzung (Session-Route) fehlte bei Kaltstart. // • Fix 1: Neues LaunchedEffect(savedRouteLine, selectedTour) überträgt // savedRouteLine → routeLine, wenn routeLine leer und keine Session-Route // vorhanden. Damit ist routeLine immer die aktive Zeichnungsquelle. // • Fix 2: Auto-Persistenz (LaunchedEffect routePlanline) ruft nun // viewModel.setCurrentSessionRoute() auf, statt nur saveTourRouteFor(). // Das füllt currentSessionRoute für Workspace-Rückkehr ohne Button-Druck. // • Fix 3: activeTourRoute als zusätzlicher Key im Zeichen-LaunchedEffect // (belt-and-suspenders gegen strukturgleiche List-Vergleiche). // • Keine Regressionen: Lizenz, Backup, Multiclip, PTT, Atmo, Bibliothek, // MapLibre, POIs, Tourverlauf, GPS-Track, Spontane-Tour-Autocreate. // v2.7.10 — Waypoint-Persistence-Fix (Unbenannte Tour bleibt nach Verlassen der Karte): // • Root Cause: selectDefaultTour() wurde bei jedem Einstieg in den Explorer // aus der Audio-Bibliothek/Home blind auf DEFAULT_TOUR_NAME („Standard“) // gesetzt. Wenn zuvor eine spontane „Unbenannte Tour“ angelegt worden war, // filterten Waypoints und Explorer-Karte nach „Standard“ → leere Ansicht. // • Fix: selectDefaultTour() prüft jetzt vor dem Reset, ob echte (nicht-Standard) // Touren in _tourList vorhanden sind. Ist das der Fall, wird sofort synchron // zur ersten echten Tour gewechselt – statt auf DEFAULT zu fallen und auf den // asynchronen combine-Kollektor (v2.7.5) zu warten, der den Reset dann ggf. // rückabwickelt. Das vermeidet die Race-Condition, bei der die Explorer-UI // in einem Recomposition-Zyklus mit leerem Waypoint-Filter gerendert wurde. // • Keine Regressionen: Lizenz, Backup, Multiclip, PTT, Atmo, Bibliothek, // MapLibre, POIs, Tourverlauf, GPS-Track, Explorer-State-Isolation (v2.7.9). // Bestehende echte Touren werden beim Explorer-Öffnen korrekt vorausgewählt // (war bereits so via async combine-Autoswitch – jetzt deterministisch/synchron). // v2.7.14 — Explorer Entry Context Fix (Navigations-Bug): // • Bug: Übersicht → Explorer öffnete nicht neutral, sondern die zuletzt // bekannte echte Tour. Grund: selectDefaultTour() wählte bei vorhandenen // echten Touren die erste echte Tour statt DEFAULT_TOUR_NAME. // • Fix: Neue Funktion selectNeutralTourForNewExplorer() mit _neutralExplorerMode- // Flag verhindert den automatischen Upgrade durch den combine-Kollektor (v2.7.5) // und erzwingt bewusst einen leeren Explorer-Kontext aus der Übersicht. // • Touransicht → Explorer: bleibt unverändert bei der aktiven Tour. // • selectDefaultTour() für Legacy-Pfade erhalten. Keine Regressionen. // v2.7.13 Planlinie, v2.7.12 overlayRenderNonce, v2.7.11 waypointRenderKey, // v2.7.10 Persistenz, v2.7.9 State Isolation alle unberührt. // v2.7.20 — Flexible Routenformung: // • Route formen = Start/Ziel/Zwischenpunkte setzen, dann Planlinie oder Online-Route. // • Neu: Zwischenpunkt direkt per Karten-Tap setzen (neuer AddViaPoint-TapMode). // • Intuitiver Fallback: 1. Tap = Start, 2. Tap = Ziel, weitere = Zwischenpunkte. // • Via-Sektion im Tourplaner klar als "Zwischenpunkte (Route formen)" bezeichnet. // • Freie Linie klar als Fallback gekennzeichnet (UI-Text, kein Verhaltensänderung). // • Keine Regressionen: v2.7.19 Start/Via/Ziel-Persistenz, v2.7.18 Doppellinie-Fix, // Audio-Waypoints, PTT, Atmo, Backup, Lizenz, MapLibre-Render-Fixes unverändert. // v2.7.21 — Waypoint Preservation Fix: // • Root Cause: Race-Condition in duplicateTour()/deleteTour()/renameTour() liest // _waypoints.value (könnte noch emptyList() sein vor DataStore-Erstladen) und ruft // saveAll(leere_liste + newWps) auf — überschreibt alle bestehenden Wegpunkte. // • Fix 1: saveAll() hat jetzt Preservation-Guard: leere Liste überschreibt niemals // nicht-leere DataStore-Liste (atomarer Check innerhalb dataStore.edit). // • Fix 2: saveAllForced() für explizite Lösch-/Restore-Operationen (deleteTour, // renameTour, Backup-Restore) — bewusster Vollersatz. // • Fix 3: duplicateTour/deleteTour/renameTour lesen jetzt mit repository.waypoints.first() // direkt aus DataStore statt aus _waypoints.value. // • Planlinie/Route-Speicherpfade (saveTourRouteFor) berhren KEY_WAYPOINTS nie. // • AddViaPoint (v2.7.20) bestätigt sicher: kein Waypoint-Speicherpfad wird ausgelöst. // • Keine Regressionen: v2.7.20 AddViaPoint, v2.7.19 Start/Via/Ziel-Persistenz, // v2.7.18 Doppellinie-Fix, Audio-Waypoints, PTT, Atmo, Backup, Lizenz unverändert. // v2.7.22 — Saved Route Render Fix: // • Root Cause: savedRouteLine schloss MANUAL-Routen explizit aus (emptyList()), // damit der v2.7.18 Doppellinien-Fix keine Konflikte erzeugt. Da aber // manualRoutePolylines (Bearbeitungsvorschau) nur bei manualRouteMode=true // gezeichnet wird, war das Ausschluss-Kriterium in savedRouteLineüberfüssig // und verhinderte die Darstellung gespeicherter MANUAL-Routen. // • Fix 1: MANUAL-Quellen in savedRouteLine eingeschlossen (wie OSRM); Phantom-Guard // auf Standardtour bleibt. // • Fix 2: LaunchedEffect(savedRouteLine) überspringt MANUAL (wie PLANLINE), damit // MANUAL via hasSavedRoute-Pfad grün gezeichnet wird (nicht blau als OSRM). // • Fix 3: hasRoute im RoutePlannerSheet-Aufruf berücksichtigt savedRouteLine.size, // damit "Noch keine Route" nicht erscheint wenn eine gespeicherte Route vorhanden ist. // • Keine Regressionen: v2.7.21 Waypoint-Preservation-Guard, v2.7.18 Doppellinie-Fix, // PLANLINE, OSRM, AddViaPoint, Audio-Waypoints, PTT, Atmo, Backup, Lizenz unverändert. // v2.7.26 — Persistent Map Preferences: // • Globale Kartenpräferenzen dauerhaft gespeichert: Wegpunkt-Marker, Audio-Radius, // GPS-Track/Draft-Linien, POIs-automatisch-nachladen (autoPoiLoad) jetzt persistent. // • Bestehende Persistenz (baseStyle, showAudioLength, showAudioLines, POI-Kategorien, // POI-Namen, Standort-Folgen, perspectiveTilt) unverändert beibehalten und erweitert. // • Standort-Folgen entschärft: Jede manuelle Kartenverschiebung deaktiviert Standort // folgen sofort (statt nur bei >40m Distanz). Kein Auto-Rücksprung beim nächsten // GPS-Fix. Explizite Aktivierung nur per Toggle-Switch oder MyLocation-Button. // • Beim Öffnen des Explorers mit Tourlinie/Wegpunkten: Kamera auf Tour zentriert, // nicht auf Live-Standort (sofern Standort folgen aus). // • Keine Regressionen: v2.7.25 Initial-Render-Fix, v2.7.24 UX Polish, v2.7.23 // Tourverlauf übernehmen, v2.7.22 Saved Route Render, v2.7.21 Waypoint // Preservation Guard alle unberührt. // v2.7.29 — Overlay Rehydrate Fix: // • Root Cause: Nach setStyle() loescht MapLibre alle Annotations (Marker, // Polylines, Polygons). overlayRenderNonce++ loest Waypoint-Redraw aus, // aber myLocationMarker/accuracyPolygon wurden auf null gesetzt und nur durch // eingehende GPS-Updates (LocationCallback) neu gesetzt — fehlende Interaktion // bis zum naechsten GPS-Fix fuehrte zu fehlendem/hellem Default-Marker. // • Fix 1 (Live-Standort): Neuer LaunchedEffect(overlayRenderNonce, styleReady, // mapLibreMap) zeichnet den Puck sofort aus lastLat/lastLng neu, ohne auf // naechsten GPS-Fix zu warten. Genauigkeitskreis wird ebenfalls rehydriert. // • Fix 2 (POI-Marker): overlayRenderNonce als Key im explorerPoiResults- // LaunchedEffect sichert POI-Redraw nach Style-Load. // • Alle v2.7.28 Fixes (Map Style Apply Fix, appliedBaseStyle/appliedPerspectiveTilt) // bleiben vollstaendig erhalten. // • Keine Regressionen: v2.7.27 Kartenpraeferenz-Persistenz, v2.7.26 // Standort-Folgen-Fix, v2.7.25 Initial-Render-Fix, v2.7.24 UX Polish, // v2.7.23 Tourverlauf uebernehmen, v2.7.21 Waypoint Preservation Guard, // Routenplanung, POIs, Kartenstile, Audio-Waypoints, Multiclip, PTT, Atmo, // Lizenzsystem, Backup/Restore alle unberuehrt. // v2.7.32 — Zwei Regressionsfixes: // • Touren ordnen: Erste und letzte SICHTBARE Tour ließen sich nicht // mehr verschieben. Ursache: TourReorderDialog arbeitet auf // visibleTourList (Standard-Tour ausgeblendet), WaypointViewModel.moveTour // operierte aber auf _tourList inkl. DEFAULT_TOUR_NAME → Off-by-one, // wenn die Standard-Tour an Index 0 lag. Fix: moveTour interpretiert // Indizes im sichtbaren Raum und merged zurück, wobei die ausgeblendete // Standard-Tour ihre relative Position behält. Hidden-Standard-Verhalten // bleibt erhalten; echte Touren sind alle frei sortierbar. // • Audioplayer: Der etablierte GPS2Audio-Player (ClipDetailSheet/ // -Fullscreen) erschien beim manuellen Start eines Tracks/Clips nicht // mehr. Fix: Neuer LaunchedEffect öffnet die Player-Ansicht automatisch // für den aktiv abgespielten Wegpunkt, sobald Wiedergabe beginnt. // • Keine Regressionen: Multi-Clip, Clip-Navigation, Countdown, maximierter // Detailplayer, Hintergrundwiedergabe, PTT-Pause, Tour-Wiedergabe- // Persistenz, Explorer/MapLibre, Routing, POIs, Backup, Lizenz unberührt. // v2.7.33 — UI-Politur Begleitmusik-Dialog (rein gestalterisch): // • Begleitmusik fühlt sich jetzt wie eine integrierte Musik-Karte der // Tour an statt wie ein technisches Formular. // • Neue Status-/Musik-Karte (MusicStatusCard) im Teal/Dark-Stil: // Tour-Kontext, Aktiv-Status, Kurz-Zusammenfassung + Aktivieren-Schalter. // • Kompakte Quellen-Chips (Lokale Playlist / Stream), primäre Aktion // „Musik auswählen" als gefüllter Button, einladender Empty-State // (MusicEmptyState) statt technischem Text. // • Verhaltensoptionen mit Klartext-Titeln („Bei Ansagen pausieren", // „Leiser im Hintergrund", „Weiterlaufen lassen", „Sanft aus-/einblenden") // unter zusammengefasstem Abschnitt „Verhalten & Optionen". // • KEINE Änderung an Datenmodell, Speicherung, Backup/Import, Lizenz, // Playback-Service, PTT, Atmo, Waypoint-/Hintergrundwiedergabe, MapLibre/ // Explorer oder Routing. validateAndSave + alle Optionen unverändert. // • Keine Regression zu v2.7.32 (Player-Auto-Open, Tour-Reihenfolge). // v2.7.34 — UI-Politur „Wegpunkt bearbeiten" (rein gestalterisch): // • Ruhigeres Layout: kompakte Status-/Kopfkarte oben (Name, Tour, // Kurzüberblick Position/Audio). // • „Details" (Name + Tour) immer sichtbar; Position, Audio, Auslösung, // Wiedergabe-Regeln, Zeitplan und „Kopieren & duplizieren" als // einklappbare Abschnitte mit Kurz-Zusammenfassung. // • Kopieren/Duplizieren nach ganz unten verschoben (nicht mehr zwischen // Basisfeldern und Position); Koordinaten nur bei Bedarf aufgeklappt. // • Abschnitte mit Validierungsfehlern öffnen sich automatisch. // • KEINE Änderung an Datenmodell, Speicherung, Backup/Import, Lizenz, // Playback, Multi-Clip, PTT, Atmo, MapLibre/Explorer oder Routing. // Validation + Save (confirmButton) und alle Felder unverändert. // v2.7.35 — UI-Politur Hauptseite/Audio-Bibliothek (rein gestalterisch): // • Abschnittstitel „Meine Touren" mit Anzahl als Chip rechts. // • Tour-Karten: feste Textblock-Höhe (gleichmäßige Karten), klare // Metazeile statt abgeschnittenem Text („Route ge…"). // • Leere Touren wirken bewusst („Noch leer") statt „0 Wegpunkte". // • Chips immer sichtbar: Wegpunkt-Zahl bzw. „Noch leer" + „Route" / // „Keine Route". // • Live/PTT-Modul optisch zurückgenommen (Einrückung/kompakter) – // KEINE Verhaltensänderung an LivePttCard. // • KEINE Änderung an Datenmodell, Speicherung, Backup/Import, Lizenz, // Playback, Multi-Clip, PTT/Atmo-Verhalten, MapLibre/Explorer, Routing, // Tour-Reihenfolge oder Player-Auto-Open. // v2.7.36 — Bugfix: Absturz/ANR nach Backup-Erstellung. // • Ursache: exportBackupZip() führte Flow-Reads, ZIP-Aufbau und das // Kopieren aller Mediendateien im viewModelScope auf dem Main-Thread // aus → ANR ("App reagiert nicht"), obwohl die Datei geschrieben war. // • Fix: schwere IO läuft jetzt auf Dispatchers.IO (wie der Import-Pfad); // State-Updates für Erfolg/Fehler bleiben auf Main. Zusätzliche // Absicherung: unerwartete Fehler werden als nicht-fatale Meldung // gezeigt statt abzustürzen. // • KEINE Änderung am Backup-Format/-Inhalt, an der Import-Logik oder an // anderen Funktionen. // v2.7.39 — Audio-Stabilitätsfix: // • Die in v2.7.37 eingeführte feste Stille-Pause zwischen Clips und // Wegpunkten im manuellen Tour-Play wurde entfernt. // • Manueller Auto-Advance startet den nächsten aktiven Clip/Wegpunkt // wieder direkt. Dadurch gibt es keinen verzögerten Coroutine-Job // mehr, der auf Samsung-Geräten oder nach Tour-/GPS-State-Wechseln in // veraltete Player-Zustände laufen kann. // • Keine Änderung an GPS-Wiedergabe, PTT, Atmo, Einzelclip-Vorschau, // Hintergrund-Playback, Backup/Import, Lizenz, Karten/Explorer oder // Player-Auto-Open. versionCode = 145 versionName = "2.7.39" } val storeFilePath = resolveSigningValue("storeFile", "GPS2AUDIO_RELEASE_STORE_FILE") val storePassword = resolveSigningValue("storePassword", "GPS2AUDIO_RELEASE_STORE_PASSWORD") val keyAliasValue = resolveSigningValue("keyAlias", "GPS2AUDIO_RELEASE_KEY_ALIAS") val keyPasswordValue = resolveSigningValue("keyPassword", "GPS2AUDIO_RELEASE_KEY_PASSWORD") val hasReleaseSigning = storeFilePath != null && storePassword != null && keyAliasValue != null && keyPasswordValue != null signingConfigs { if (hasReleaseSigning) { create("release") { storeFile = file(storeFilePath!!) this.storePassword = storePassword keyAlias = keyAliasValue keyPassword = keyPasswordValue } } } buildTypes { release { if (hasReleaseSigning) { signingConfig = signingConfigs.getByName("release") } isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" } buildFeatures { compose = true } lint { abortOnError = false checkReleaseBuilds = false } } dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) implementation(libs.androidx.material.icons.extended) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.datastore.preferences) implementation(libs.gson) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.coroutines.play.services) implementation(libs.play.services.location) implementation(libs.osmdroid) // v2.2.2 — MapLibre Native Android SDK als Build-Abhängigkeit eingezogen. // Das eigentliche Rendering nutzt weiterhin osmdroid (siehe ExplorerScreen), // damit Stabilität/Größe nicht regressieren. MapLibre dient als Grundlage // für künftige Vektor-/3D-Layer-Schritte (siehe Handoff). implementation(libs.maplibre.android.sdk) implementation(libs.media3.exoplayer) implementation(libs.media3.common) // v2.5.8 — Android Splash Screen API (Backport für API 26+). Wir nutzen // den stabilen Weg via androidx.core.splashscreen, damit Pre-31 dieselbe // Intro-Optik bekommt wie API 31+. implementation(libs.androidx.core.splashscreen) debugImplementation(libs.androidx.ui.tooling) }