# GPS2Audio v2.5.15 — Player Maximize + Tour-/Wegpunkt-Varianten Interne Release, **nicht** für Gitea/Public. ## Ausgangsbasis - Quelle: `GPS2Audio_v2_5_14_multiclip_playback_navigation_source.zip` aus `/home/user/workspace/` (frisch in `/home/user/workspace/v2_5_15_work/` entpackt; **kein** altes Repo-Skeleton verwendet). - Vorherige Release: v2.5.14 (Multi-Clip-Playback-Fix + Clip-Navigation + Countdown). Alle Vorgänger-Features (Xiaomi/HyperOS-Hintergrundhilfe, Multi-Clip-Speicherung/Backup, Foreground-Service/WakeLock, Terms/Lizenz, PTT, Atmo, Explorer/MapLibre, Routing, Tourcover, Datensicherung, OSM Attribution) sind unverändert übernommen. ## Versionierung - `versionCode` 68 → **69** - `versionName` `2.5.14` → **`2.5.15`** ## Signatur - Keystore: `/home/user/workspace/GPS2Audio_release_keystore_v2.jks` (identische v2-Linie wie 2.5.11–2.5.14). - Alias: `gps2audio_release_v2` - Signaturschema v2 verifiziert (`apksigner verify --verbose`): - `CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE` - RSA 4096 - SHA-256: `490511f350557083808cdf9e39fdb0a2d4d76d2224726b56018d1ac0dd9ed4e5` - **Updatefähig** als In-Place-Update aller v2.5.11+ Builds (gleiche Signaturlinie). - Keystore/Passwörter sind **nicht** im Source-Zip enthalten (`keystore.properties` und `local.properties` wurden vor dem Zippen entfernt; nur `keystore.properties.example` bleibt als Template). ## Artefakte | Pfad | Beschreibung | | ---- | ------------ | | `/home/user/workspace/GPS2Audio_v2_5_15_player_maximize_tour_variants_signed.apk` | Signiertes Release-APK, ~56 MB | | `/home/user/workspace/GPS2Audio_v2_5_15_player_maximize_tour_variants_source.zip` | Bereinigter Source-Stand (ohne `build/`, `.gradle/`, Secrets) | | `/home/user/workspace/GPS2Audio_v2_5_15_player_maximize_tour_variants_handoff.md` | Dieses Dokument | ## Was ist neu in v2.5.15 ### 1) Player-Detailansicht maximierbar (Vollbild) - `ClipDetailSheet` (Bottom-Sheet) bekommt einen zusätzlichen Maximize-Button (`Icons.Filled.OpenInFull`) links neben dem Schließen-Button. Tap → öffnet `ClipDetailFullscreen`. - Neue Composable `ClipDetailFullscreen` in `app/src/main/kotlin/de/waypointaudio/ui/ClipDetailSheet.kt`: - Modaler `Dialog` mit `usePlatformDefaultWidth = false` + `Surface` + `Scaffold` → echte Vollbild-Optik. - TopAppBar mit: - links **Minimize** (`Icons.Filled.CloseFullscreen`) → zurück zum Bottom-Sheet, Player-Zustand bleibt erhalten. - rechts **Close** (`Icons.Filled.Close`) → Player komplett schließen. - Größere Waveform (200 dp statt 108 dp), eigene "Clips"-Sektion mit scrollbarer `LazyColumn` für viele Clips, identische Transport- Steuerung mit `buttonScale = 1.25f` (größere Tap-Targets). - Wiederverwendete Bausteine (`ClipDetailStatusRow`, `ClipDetailRemainingRow`, `ClipDetailEmptyTracksRow`, `ClipTrackRow`, `ClipDetailTransport`, `ClipWaveform`) als private Composables – Sheet und Vollbild bleiben **inhaltlich konsistent** (Statustext, "Clip N von M", "Verbleibend mm:ss", Play/Pause/Prev/Next/Stop). - State-Übergang in `WaypointListScreen` über neues `clipDetailFullscreen: Boolean`. Minimize lässt Player-Zustand intakt; Close (Dismiss) setzt sowohl `clipDetailWaypointId = null` als auch `clipDetailFullscreen = false`. ### 2) Wegpunkt in andere Tour kopieren - Neue ViewModel-Funktion `WaypointViewModel.copyWaypointToTour(sourceWaypointId, targetTourName, newName?)`. - Lädt den Quell-Waypoint, vergibt **frische UUIDs** für Wegpunkt und alle (über `effectiveClips()` ermittelten) Clips. - **Audio-URIs werden referenziert**, nicht physisch dupliziert → minimaler Speicherbedarf, Backup/Export greift weiterhin via URI. - `playCount` wird auf 0 zurückgesetzt; Zeitplan-/Modus-Felder bleiben erhalten, damit die Kopie 1:1 weiterläuft. - `withClips()` spiegelt den primary-Clip in die Legacy-Felder (`soundUri`/`soundName`) zurück, damit alte Lese-Pfade unverändert funktionieren. - Zieltour wird, falls noch nicht in `_tourList` enthalten, automatisch persistiert. Erfolg → `_infoMessage`-Snackbar. - UI: neue Sektion **„Wegpunkt kopieren"** im `WaypointEditDialog` (nur bei vorhandenem Waypoint sichtbar). Enthält einen `ExposedDropdownMenuBox` mit allen weiteren Touren und einen `OutlinedButton "Kopieren"`. Wenn keine weitere Tour existiert, wird ein freundlicher Hinweis statt der Auswahl gezeigt. - Verkabelung: `WaypointListScreen` übergibt `onCopyToOtherTour = { tour -> viewModel.copyWaypointToTour(wp.id, tour) }` beim Bearbeiten eines bestehenden Wegpunkts. ### 3) Tour duplizieren / Tourvariante - Neue ViewModel-Funktion `WaypointViewModel.duplicateTour(sourceTourName, newTourName, selectAfter = true)`. - Validiert Name (leer / Duplikat). - Tourliste wird optimistisch erweitert und (wenn `selectAfter = true`) sofort aktiv. - Für jeden Wegpunkt der Quelltour: neue UUIDs für Waypoint **und** Clips, `playCount = 0`, ansonsten 1:1 (Koordinaten, Radius, Aktivstatus, Beschreibung, Routing-/Schedule-Felder, Multi-Clip-Liste, Reihenfolge). - **Medien werden nicht physisch dupliziert** (URIs referenziert). - Tour-Cover, Tour-Route und Tour-Defaults werden mit dem neuen Tournamen mitkopiert (`firstOrNull()` auf den Flows + `save…()`). `tourRoute.updatedAtMillis` wird auf `now()` gesetzt, damit die Variante im Routing-Cache nicht versehentlich mit der Quelle teilt. - UI: neuer Menüeintrag **„Tour duplizieren…"** im Overflow-Menü der WaypointList-TopAppBar (zwischen „Tour umbenennen" und Löschen). Öffnet `DuplicateTourDialog` mit Default-Name ` – Variante` (bzw. `… – Variante (n)` bei Kollision). Bestätigen ruft `viewModel.duplicateTour()`; die neue Tour ist anschließend automatisch der ausgewählte Tab. ### 4) Daten-/Backup-Kompatibilität - Keine Datenmigration. Alle neuen Aktionen schreiben über die bestehenden `WaypointRepository`/`WaypointStore`-Pfade (`upsert`, `saveAll`, `saveTours`, `saveTourRoute`, `saveTourCover`, `saveTourDefaults`) → bestehende DataStore-JSON-Layouts bleiben gültig. - Kopierte Wegpunkte/Touren sind ganz normale Einträge in `waypoints_json` / `tours_json` / `tour_routes_json` / `tour_covers_json` / `tour_playback_defaults_json` und werden vom Backup-/Export-Pfad ohne Sonderbehandlung mitgesichert. - Bestehende Backups (v2.5.11 – v2.5.14) lassen sich unverändert importieren. ### 5) Keine Regressionen Alle bestehenden v2.5.x-Features sind intakt – unverändert eingesetzt: - v2.5.14 Multi-Clip-Playback + Clip-Navigation + Countdown (`PlayableItem`-Sequenz, `manualPrevious`/`manualNext`, "Clip N von M", "Verbleibend mm:ss") – Vollbild zeigt identische Werte über gemeinsamen Status-/Remaining-Composable. - v2.5.13 Xiaomi/HyperOS-Hintergrundhilfe (`BackgroundReliability…`) - v2.5.12 Multi-Clip-Speicherung + Backup - v2.5.11 Foreground-Service/WakeLock, Terms/Lizenz - PTT, Atmo, Explorer/MapLibre, Routing, Tourcover, Datensicherung, OSM Attribution ## Geänderte Dateien ``` app/build.gradle.kts (versionCode/Name + Versionsnotiz) app/src/main/kotlin/de/waypointaudio/ui/ClipDetailSheet.kt – Refactor in private Composables, neuer ClipDetailFullscreen, Maximize-Button, parametrisierte Waveform-Höhe. app/src/main/kotlin/de/waypointaudio/ui/WaypointEditDialog.kt – neuer optionaler Parameter onCopyToOtherTour, UI-Sektion "Wegpunkt kopieren". app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt – neue States clipDetailFullscreen, showDuplicateTourDialog, Maximize/Minimize-Wiring, "Tour duplizieren…"-Menüeintrag, DuplicateTourDialog-Composable, onCopyToOtherTour-Wiring. app/src/main/kotlin/de/waypointaudio/viewmodel/WaypointViewModel.kt – copyWaypointToTour(), duplicateTour(), zwei neue Imports (effectiveClips, withClips, flow.firstOrNull). ``` Es gibt **keine** Datenmodell-Änderungen (kein neues Feld in `Waypoint`/`AudioClip`/`TourRoute`/`TourCover`). ## Manueller Testplan ### Player-Vollbild 1. Wegpunkt mit mindestens drei Clips antippen → Bottom-Sheet öffnet sich. 2. Maximize-Icon (links neben dem X) tippen → Vollbild-Dialog erscheint. 3. Im Vollbild Play/Pause, Prev/Next, Stop testen – "Clip N von M" und "Verbleibend mm:ss" müssen sich live wie im Sheet aktualisieren. 4. Während Wiedergabe Minimize tippen → zurück zum Bottom-Sheet, Wiedergabe läuft ohne Unterbrechung weiter. 5. Aus dem Sheet erneut maximieren → Vollbild, dann X tippen → Player schließt komplett. 6. Tour mit > 6 Clips: im Vollbild prüfen, dass die Clipliste (LazyColumn) scrollt, ohne dass die Transport-Buttons abgeschnitten werden. ### Wegpunkt in andere Tour kopieren 1. Mindestens zwei Touren mit je ≥ 1 Wegpunkt anlegen. 2. Wegpunkt mit Multi-Clip-Liste (z. B. 3 Clips, einer inaktiv) editieren. 3. Sektion „Wegpunkt kopieren" → Ziel-Tour wählen → „Kopieren". 4. In Zieltour öffnen: Wegpunkt mit identischem Namen, allen 3 Clips, identischer Reihenfolge/Aktivstatus, identischen URIs. 5. Den kopierten Wegpunkt editieren (z. B. einen Cliptitel ändern, Clip löschen). Zur Quelltour zurück → Original ist **unverändert**. 6. Backup-Erstellung über Datensicherung → kopierten Wegpunkt im Backup-Inhalt wiederfinden; auf einem zweiten Gerät importieren → identisch wiederhergestellt. 7. Wegpunkt-Editor in Standard-Tour öffnen, wenn keine zweite Tour existiert: Hinweistext erscheint statt Auswahl. ### Tour duplizieren 1. Tour mit ≥ 3 Wegpunkten (mind. einer mit Multi-Clip), Cover und gespeicherter Route auswählen. 2. Overflow-Menü → „Tour duplizieren…" → Default-Name akzeptieren. 3. Tabs scrollen automatisch auf die neue Tour. Wegpunkte vorhanden mit identischer Reihenfolge, Clips, Cover, Route. 4. In der Variante einen Wegpunkt löschen, einen Clip umsortieren. Zur Quelltour zurückwechseln → Quelltour unverändert. 5. Backup-Datensicherung erstellen → beide Touren mit unterschiedlichen UUIDs enthalten; Import auf zweitem Gerät → beide Touren wiederhergestellt. 6. Bei Namenskonflikt (gleicher Name wie bestehende Tour) erscheint Validierungsfehler im Dialog statt stiller Übernahme. ### Smoke-Tests bestehender Features - PTT-Aufnahme starten/stoppen, abspielen. - Atmo abspielen, Wegpunkt-Trigger lässt Atmo dimmen (wie bisher). - Xiaomi/HyperOS-Hinweis öffnet sich beim ersten Start korrekt (`BackgroundReliabilityDialog`). - Foreground-Service / Benachrichtigung beim Start des Tracking-Modus. - Tour-Cover anzeigen, Tour umbenennen → Cover bleibt erhalten. - JSON-Export & GPX-Export, anschließend Re-Import (merge): keine Duplikate, keine Verluste. - Routing-/Storyboard-Sheet öffnet sich und behält Marker. ## Build-Reproduktion ```bash cd /home/user/workspace rm -rf v2_5_15_work mkdir v2_5_15_work && cd v2_5_15_work unzip -q /home/user/workspace/GPS2Audio_v2_5_15_player_maximize_tour_variants_source.zip cat > keystore.properties <<'EOF' storeFile=/home/user/workspace/GPS2Audio_release_keystore_v2.jks storePassword= keyAlias=gps2audio_release_v2 keyPassword= EOF cat > local.properties <<'EOF' sdk.dir=/home/user/tools/android-sdk EOF /home/user/tools/gradle/bin/gradle :app:assembleRelease --no-daemon # Output: app/build/outputs/apk/release/app-release.apk ``` `apksigner verify --verbose` muss den Signer-DN `CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE` und Schema v2 ausweisen. ## Notiz zu Gitea / Veröffentlichung Dieses Release ist explizit **intern**. Es wurde **nicht** auf Gitea gepusht und **nicht** im Netz veröffentlicht. APK + Source-Zip liegen ausschließlich unter `/home/user/workspace/`.