532 lines
35 KiB
Kotlin
532 lines
35 KiB
Kotlin
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.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)
|
||
}
|