Files
GPS2Audio/app/build.gradle.kts
T
2026-06-22 11:07:32 +00:00

532 lines
35 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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/<tour>.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.7v2.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)
}