• v2.1.2 b2aa1c167c

    marcel released this 2026-05-15 14:32:59 +02:00 | 7 commits to main since this release

    GPS2Audio v2.1.2 – PTT‑Aufnahmen: Löschen + Hintergrund‑Autosave

    Build: versionName 2.1.2, versionCode 39
    Basis: v2.1.1 (versionCode 38) aus GPS2Audio_v2_1_1_ptt_recorder_play_assign_source.zip
    applicationId: de.waypointaudio (Update‑kompatibel zu v2.1.1)
    Signatur: Release‑Keystore GPS2Audio_release_keystore.jks, Alias gps2audio_release
    Signaturschema: APK Signature Scheme v2 (verifiziert via apksigner verify)
    Zertifikat SHA‑256: 7B:0E:A4:D5:52:86:05:17:3D:29:9D:7B:26:8E:7A:B8:76:8D:D5:04:EC:15:B6:6A:52:D4:7B:42:57:B3:BB:46 – identisch zu allen vorherigen Releases, daher updatefähig.

    Lieferumfang

    • GPS2Audio_v2_1_2_ptt_recorder_delete_autosave_signed.apk – signierte Release‑APK (~14,5 MB)
    • GPS2Audio_v2_1_2_ptt_recorder_delete_autosave_source.zip – vollständiger Quellbaum ohne Secrets (keine .jks, keine keystore.properties, kein local.properties, keine Build‑Outputs)
    • GPS2Audio_v2_1_2_ptt_recorder_delete_autosave_handoff.md – dieses Dokument

    Nutzerfeedback (v2.1.1)

    „ja fast perfekt, aufnahmen sollten sich wieder löschen lassen, außerdem stört die Abfrage nach beenden der PTT, es soll einfach im Hintergrund gespeichert werden"

    Daraus zwei klare Anforderungen:

    1. Löschen der PTT‑Aufnahmen wieder verfügbar.
    2. Kein blockierender Dialog mehr nach dem Loslassen der PTT‑Taste. Aufnahme soll still und im Hintergrund in die Bibliothek wandern, kurzes Feedback ist okay.

    Ursachenanalyse

    Ursache 1 – „Aufnahmen lassen sich nicht mehr löschen"

    Die Löschen‑Logik existierte in v2.1.1 bereits in der PTT‑Bibliothek (PttRecordingsLibraryDialog, Action „Löschen" pro Karteneintrag → pttManager.deleteRecording(rec)). Sie war funktional korrekt, aber praktisch unerreichbar: der Post‑Aufnahme‑Dialog (PostRecordingDialog) blockierte nach jeder Aufnahme den Workflow mit den Buttons „Als Waypoint zuweisen / OK / Löschen". Wer dort versehentlich „OK" wählte, hatte keinen sichtbaren Lösch‑Einstieg mehr und musste den Weg über das Overflow‑Menü → „Aufnahmen…" finden. In der Wahrnehmung war Löschen damit „verschwunden". → Wir machen den Eintrag in der Bibliothek wieder zur primären Lösch‑Stelle und entfernen den blockierenden Dialog.

    Ursache 2 – „Die Abfrage nach Beenden der PTT stört"

    In v2.1.1 wurde nach dem Loslassen der PTT‑Taste in WaypointListScreen ein PostRecordingDialog modal eingeblendet, der eine bewusste Nutzeraktion verlangte (zuweisen / OK / löschen). Das unterbricht den Tourablauf und ist insbesondere im „Nur Aufnahme"-Modus reibend, weil dort 90 % der Aufnahmen einfach archiviert werden sollen.

    Umsetzung

    1) PTT‑Aufnahme: Hintergrund‑Autosave

    app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt

    • Der modale PostRecordingDialog wird nicht mehr gerendert.
    • Stattdessen reagiert ein LaunchedEffect(lastRecording?.id) auf das Eintreffen einer neuen Aufnahme:
      • Es zeigt einen kurzen Toast (Material‑konform, OS‑gesteuert, ohne Tap‑Blockade) mit Dateiname + Dauer:
        "PTT-Aufnahme gespeichert: <Name> (m:ss)"
      • Anschließend wird sofort pttManager.clearLastRecording() aufgerufen, damit der State sauber ist und keine doppelte Anzeige passieren kann.
    • Der Speichervorgang selbst (Datei + Metadaten in PttRecordingStore) bleibt unverändert aus LivePttManager.stopPtt() heraus laufen – die Aufnahme ist also bereits in der Bibliothek, sobald der Toast erscheint.
    • Toast.LENGTH_SHORT (~2 s) erfüllt „kurzes, unaufdringliches Feedback".
    • Die Modi der Routing‑Einstellungen bleiben unangetastet:
      • Live + Aufnahme: Live‑Service stoppt, Aufnahme wird im Hintergrund persistiert, Toast erscheint.
      • Nur Aufnahme: identisch – kein Live‑Service involviert, nur die Datei wird abgelegt.
      • Nur Live: kein Toast (kein lastRecording‑Event, weil _recordingActive.value == false).

    app/src/main/res/values/strings.xml

    • Neuer String ptt_recording_autosaved_toast (Deutsch):
      PTT-Aufnahme gespeichert: %1$s (%2$s)
    • Alte Strings (ptt_recording_saved_title, ptt_recording_ok, …) bleiben bestehen für Resourcen‑Kompatibilität (kein Resource‑Stripping).

    2) Löschen in der PTT‑Aufnahmen‑Bibliothek

    app/src/main/kotlin/de/waypointaudio/ui/PttRecordingDialogs.kt

    • Der Löschen‑Button in PttRecordingsLibraryDialog (Eintrags‑Action neben „Anhören" und „Zuweisen") war bereits implementiert und wurde bewusst nicht doppelt gebaut:
      • Klick öffnet die Bestätigung „Aufnahme löschen?".
      • Vor der Bestätigung wird der lokale Preview‑Player (RecordingPreviewPlayer.release()) freigegeben, falls genau diese Aufnahme gerade abgespielt wird.
      • Bestätigtes Löschen ruft pttManager.deleteRecording(rec) auf, was die Datei vom Speicher entfernt (File.delete()) und den Eintrag aus PttRecordingStore löscht.
      • Die Bibliotheksliste ist ein StateFlow (recordings.collectAsState) → UI aktualisiert sich automatisch nach dem prefs[...]-Edit.
    • Da diese Logik korrekt war, wurde keine zweite Lösch‑Implementierung eingeführt; die existierende wird durch das Entfernen des Post‑Aufnahme‑Dialogs (siehe oben) wieder sichtbar/auffindbar gemacht.

    3) Versions‑Bump

    app/build.gradle.kts

    • versionCode = 39 (vorher 38)
    • versionName = "2.1.2" (vorher „2.1.1")

    Der AboutDialog zieht die Version zur Laufzeit aus dem PackageManager (AppVersion.kt), daher ist keine weitere Code‑Änderung nötig.

    Geänderte Dateien

    Datei Änderung
    app/build.gradle.kts versionCode 38 → 39, versionName 2.1.1 → 2.1.2
    app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt Toast‑Import; PostRecordingDialog-Rendering durch LaunchedEffect + Toast + clearLastRecording() ersetzt
    app/src/main/res/values/strings.xml Neuer String ptt_recording_autosaved_toast

    Die Composable PostRecordingDialog wurde absichtlich nicht aus PttRecordingDialogs.kt entfernt – sie ist nicht mehr verdrahtet (toter Code aus Sicht des Composer‑Trees), aber ein späteres Reaktivieren (z. B. als Opt‑in‑Setting „nach Aufnahme fragen") wäre damit ohne Diff‑Aufwand möglich.

    Build‑ und Signatur‑Status

    • Build: gradle :app:assembleRelease --no-daemon --offline
    • Build host: Java 21 (Debian), Gradle 8.9, Android SDK Build‑Tools 35.0.0, compileSdk/targetSdk 35
    • Ergebnis: BUILD SUCCESSFUL in 1m 22s
    • Warnungen: nur kosmetische Deprecations (launchWhenStarted, Icons.Filled.Assignment, menuAnchor()) – nicht durch v2.1.2 verursacht, aus dem v2.1.1‑Stand übernommen.
    • Signatur‑Check (apksigner verify -v --print-certs):
      • Verifies
      • APK Signature Scheme v2: true
      • Signer #1 certificate DN: CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE
      • SHA-256: 7b0ea4d5528605173d299d7b268e7ab8768dd504ec15b66a52d47b4257b3bb46 ← identisch zum bekannten Release‑Zertifikat.
    • APK‑Größe: 15.208.468 Byte (~14,5 MB).

    Tests (manuell, am Build‑Host)

    Da kein Geräte‑/Emulator‑Lauf möglich ist, wurden statisch / per Code‑Pfad‑Inspektion folgende Punkte abgesichert:

    • Aufnahme in „Nur Aufnahme"-Modus: stopPtt()recorder.stoprecordingStore.add(meta)_lastRecording.value = meta → in der UI: LaunchedEffect(lastRecording?.id) zeigt Toast, ruft clearLastRecording(). Kein modaler Dialog wird mehr gerendert.
    • Aufnahme in „Live + Aufnahme": identischer Pfad; LivePttService läuft parallel und wird sauber gestoppt; Atmo wird über restoreAtmo() fortgesetzt.
    • Aufnahme in „Nur Live": _recordingActive.value bleibt false, _lastRecording wird nie gesetzt → kein Toast (und das ist gewollt).
    • Bibliothek‑Löschen, während eine andere Aufnahme spielt: Preview‑Player wird in der Lösch‑Bestätigungs‑Vorbereitung nur freigegeben, wenn die zu löschende Aufnahme die spielende ist; andere Wiedergaben bleiben unberührt.
    • Bibliothek‑Löschen der gerade spielenden Aufnahme: previewPlayer.release() + playingId = null vor pendingDelete = rec; danach pttManager.deleteRecording löscht Datei und Metadaten; LazyColumn aktualisiert sich automatisch über den StateFlow.
    • apksigner verify bestätigt die Signatur mit dem Release‑Zertifikat (s. o.).

    Regression‑Checkliste (alle aus v2.1.1 übernommenen Fixes)

    • Anhören/Pause pro AufnahmeRecordingPreviewPlayer.toggle() unverändert.
    • Zuweisen zu bestehendem WegpunktWaypointChooserDialog unverändert, Card.onClick → viewModel.upsert(updated).
    • Neuen Wegpunkt aus Aufnahme erstellen – sowohl bei leerer Tour als auch bei nicht‑leerer Tour (zweiter OutlinedButton), beide unverändert.
    • Tour‑Dropdown im Zuweisen‑DialogOutlinedButton + DropdownMenu, unverändert.
    • Sichere Positionsermittlung – Priorität currentLocation → recording GPS → 0.0/0.0 unverändert.
    • Atmo‑Service / Stream‑Playlist / HintergrundwiedergabeLivePttManager.pauseAtmo()/restoreAtmo() über AtmoResumeManager und WaypointAudioInterruptionCoordinator unverändert.
    • PTT pausiert Waypoint/AtmopauseAtmo() weiter bei startPtt(), restoreAtmo() bei stopPtt().
    • Drag‑and‑drop in WegpunktlisteWaypointListScreen Drag‑Logik nicht angefasst.
    • KarteneditorMapScreen.kt, TrackDraftEditorScreen.kt nicht verändert.
    • Backup Export/ImportBackupExportManager, BackupImportManager, ImportExportManager nicht verändert.
    • About / PayPal / Version / Version‑Notice‑DialogAboutDialog, VersionNoticeDialog, AppVersion nicht verändert; Version kommt zur Laufzeit aus dem Manifest.
    • Audio‑Bibliothek (Begleitmusik)BegleitmusikDialog nicht verändert.
    • OSM AttributionMapScreen Attribution‑Overlay nicht verändert.
    • ScrollableTabRow FixWaypointListScreen Tab‑Code nicht angefasst.
    • Touren ordnen – Sort‑Logik nicht angefasst.
    • BerechtigungenAndroidManifest.xml nicht verändert; Aufnahme‑Permission‑Pfad identisch.
    • WakeLock‑EinstellungenWakeLockSettingsDialog nicht verändert.

    Keystore‑Hinweis

    • Der Release‑Keystore liegt unter /home/user/workspace/GPS2Audio_release_keystore.jks, Alias gps2audio_release. Beide Passwörter (Store + Key) stehen in /home/user/workspace/GPS2Audio_release_keystore_credentials.txt (PKCS12, identisch).
    • Für den Build wurde temporär keystore.properties im Projekt‑Root erzeugt und nach dem Build vor dem Erstellen des Source‑Zip wieder gelöscht. Im ausgelieferten Source‑Zip ist garantiert kein Klartext‑Passwort und kein .jks enthalten (verifiziert per unzip -l):
      • enthalten: nur keystore.properties.example
      • nicht enthalten: keystore.properties, local.properties, *.jks, app/build/*, .gradle/*
    • Reproduzierbarer Build aus dem Source‑Zip:
      1. Auspacken
      2. Eigene keystore.properties mit storeFile=, storePassword=, keyAlias=, keyPassword= anlegen oder die vier GPS2AUDIO_RELEASE_*‑Env‑Vars setzen
      3. local.properties mit sdk.dir=… setzen
      4. gradle :app:assembleRelease
    • Wichtig: Geht der Keystore verloren, sind zukünftige Updates der App nicht mehr installierbar, ohne dass Nutzer deinstallieren. Bitte den Keystore und das Credentials‑File an mindestens zwei sicheren Orten ablegen.
    Downloads