# GPS2Audio v2.5.32 — Professional Feature Gates — Handoff ## Versionsinfo - **versionName**: 2.5.32 - **versionCode**: 86 - **Basis**: GPS2Audio_v2_5_31_tourcover_backup_fix_source.zip --- ## Geänderte Dateien | Datei | Art der Änderung | |---|---| | `app/src/main/kotlin/de/waypointaudio/license/LicenseFeatureAccess.kt` | **NEU** — Zentrale Feature-Abfrage | | `app/src/main/kotlin/de/waypointaudio/ui/WaypointEditDialog.kt` | Multi-Clip-Gate (Import + 2 Zeilen) | | `app/src/main/kotlin/de/waypointaudio/ui/HomeScreen.kt` | PTT-Gate (Modul + Customize-Dialog + ToggleRow) | | `app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt` | PTT- + Tour-Zähler-Gate (Modul + Customize-Dialog + CustomizeRow) | | `app/build.gradle.kts` | versionCode 85→86, versionName 2.5.31→2.5.32 | Alle anderen Dateien (Lizenzsystem, Signaturprüfung, CanonicalJson, Public Key, Picker, Dispatchers.IO, Geräte-ID, Backup-Regeln, Persistenz) sind **unverändert**. --- ## Zentrale Entitlement-Logik ### `LicenseFeatureAccess.kt` (neu) ```kotlin object LicenseFeatureAccess { private val PRO_LICENSE_TYPES = setOf("pro", "profi", "commercial", "developer", "trial") fun hasProfessionalAccess(status: LicenseStatus): Boolean { if (status.state != LicenseStatus.State.VALID) return false val typeRaw = status.licenseTypeRaw?.lowercase()?.trim() ?: "" if (typeRaw in PRO_LICENSE_TYPES) return true // Fallback: explizite Permissions (commercial_use, paid_tours etc.) return status.permissions.any { (_, v) -> v } } fun canUseMultiClip(status: LicenseStatus): Boolean = hasProfessionalAccess(status) fun canUsePtt(status: LicenseStatus): Boolean = hasProfessionalAccess(status) fun canUseTourCounter(status: LicenseStatus): Boolean = hasProfessionalAccess(status) } ``` Die Abfrage liest ausschließlich aus `LicenseStatus` (Compose MutableState aus `LicenseStatusProvider`). Kein Netzwerk, kein Clock-Check — das `valid_until`-Handling liegt bereits in `LicenseValidator`. --- ## Verhalten nach Lizenztyp ### Ohne Lizenz (state = NONE) - App vollständig nutzbar: Touren, Hauptclip, Wiedergabe, Explorer, GPX, Backup, Lizenzimport, Geräte-ID - PTT-Modul: **ausgeblendet** (Home + WaypointListScreen) - Tour-Zähler-Karte: **ausgeblendet** (WaypointListScreen) - Multi-Clip: Hauptclip (idx 0) bearbeitbar; Zusatzclips (idx > 0) sichtbar (read-only), aber nicht bearbeitbar/hinzufügbar; Profi-Hinweis wird angezeigt - "Startseite anpassen" PTT-Toggle: deaktiviert mit Hinweis "Profi-Funktion · GPS2Audio Profi-Lizenz erforderlich" - "Ansicht anpassen" PTT/Tour-Zähler-Toggles: deaktiviert mit Hinweis - **Keine Daten werden gelöscht** (weder PTT-Aufnahmen noch Zusatzclips noch Zählerwerte) ### Mit Trial-Lizenz (gültig, state = VALID, license_type = "trial") - Vollständiger Profi-Zugang solange `valid_until` nicht abgelaufen - PTT-, Tour-Zähler-, Multi-Clip-Funktionen vollständig verfügbar - Nach Ablauf (state = EXPIRED): verhält sich wie "Ohne Lizenz" ### Mit Profi-Lizenz (state = VALID, license_type = "pro"/"profi"/"commercial") - Vollständiger Profi-Zugang - Alle drei Feature-Gates geöffnet - Reaktiv: bei Import einer Lizenz während der App-Laufzeit werden Gate-Zustände ohne Neustart aktualisiert (Compose-State) ### Mit Developer-Lizenz (state = VALID, license_type = "developer") - Vollständiger Profi-Zugang (identisch zu Profi) - Kein Ablaufdatum erforderlich --- ## Gesperrte/Ausgeblendete Aktionen (ohne Profi-Zugang) ### Multi-Clip (WaypointEditDialog) - **Ausgeblendet/deaktiviert**: "Weiteren Clip hinzufügen"-Button - **Ausgeblendet/deaktiviert**: Reihenfolge-Buttons (↑↓) für Zusatzclips (idx > 0) - **Read-only**: Titel-Feld für Zusatzclips - **Ausgeblendet**: Aktions-Zeile (Aktiv-Schalter, Audio ersetzen, Löschen) für Zusatzclips - **Ausgeblendet**: "Als Hauptclip festlegen" für Zusatzclips - **Sichtbar (statt "Clip hinzufügen")**: "Hauptclip-Audio wechseln" (Hauptclip-Bearbeitung bleibt immer frei) - **Profi-Hinweis**: Orangefarbener Container mit "Multi-Clip-Waypoints sind Teil der GPS2Audio Profi-Lizenz." (nur wenn Zusatzclips vorhanden) ### PTT (Home + WaypointListScreen) - **Ausgeblendet**: PttModuleCard auf HomeScreen (`homeModules.showPtt && canPtt`) - **Ausgeblendet**: LivePttCard in WaypointListScreen (`viewSettings.showPtt && canPtt`) - **Deaktiviert**: PTT-Toggle in "Startseite anpassen" und "Ansicht anpassen" (mit Profi-Hinweis im Beschreibungstext) - PTT-Aufnahmen/Bibliothek: **nicht gelöscht**, weiterhin im Dateisystem vorhanden ### Tour-Zähler (WaypointListScreen) - **Ausgeblendet**: TourCounterCard (`viewSettings.showTourCounter && canTourCounter`) - TourCounterDialog wird nicht geöffnet (da Karte ausgeblendet) - **Deaktiviert**: Tour-Zähler-Toggle in "Ansicht anpassen" (mit Profi-Hinweis) - Bestehende Zählerwerte (playCount pro Waypoint): **nicht gelöscht** --- ## Datenschutz: Keine Datenlöschung | Datentyp | Verhalten ohne Profi | |---|---| | Zusatzclips (AudioClip, idx > 0) | Erhalten, read-only sichtbar, in Backup enthalten | | PTT-Aufnahmen | Erhalten im Dateisystem, nicht in der UI erreichbar | | Zählerwerte (Waypoint.playCount) | Erhalten, akkumulieren weiter (Dienst läuft) | | Tourdeckel/Routen/GPX | Unberührt | --- ## Reaktivität (kein App-Neustart) Alle drei Screens lesen `LicenseStatusProvider.status` als Compose-State: ```kotlin val licenseStatus = LicenseStatusProvider.status val canPtt = LicenseFeatureAccess.canUsePtt(licenseStatus) ``` Da `LicenseStatusProvider.statusState` ein `MutableState` ist, löst ein Import im `AboutDialog` sofort eine Rekomposition in allen offenen Screens aus — ohne Neustart. --- ## Bekannte Einschränkungen / Offene Punkte 1. **PTT-Aufnahmen ohne Profi nicht erreichbar**: Die PTT-Aufnahmen-Bibliothek ist über die WaypointListScreen-LivePttCard zugänglich. Da diese ausgeblendet ist, gibt es keinen UI-Einstieg in die Bibliothek ohne Profi. Die Dateien sind physisch erhalten. Wenn später ein Read-only-Bibliotheksmodus gewünscht wird, kann dies als v2.5.33-Feature ergänzt werden. 2. **Multi-Clip-Sequenz ohne Profi**: Bestehende Zusatzclips werden in der Clip-Detailansicht (`ClipDetailSheet`/`ClipDetailFullscreen`) weiterhin angezeigt. Die Sequenzwiedergabe (AudioPlayer) spielt sie ab, sofern sie aktiv sind (isActive = true). Keine Änderung am Player-Verhalten — das ist bewusst risikoarm gehalten. Ein Sperren der Sequenzwiedergabe für Zusatzclips wäre im AudioPlayer-Service zu implementieren (für zukünftige Version). 3. **Customize-Dialog PTT-Toggle**: Der Toggle verändert den gespeicherten Wert nicht (guard im onCheckedChange-Lambda), zeigt aber weiterhin den gespeicherten Wert aus den Preferences an (immer false/off dargestellt wenn kein Profi). 4. **Developer-Lizenz ohne valid_until**: Wird von `LicenseValidator` als VALID durchgelassen (kein `valid_until` = unbefristet). `hasProfessionalAccess()` gibt `true` zurück. Korrekt. --- ## Nicht geändert (explizit bestätigt) - `LicenseStatusProvider` — nur Import-Aufruf (`val licenseStatus = LicenseStatusProvider.status`) - `LicenseValidator` — unverändert - `LicenseStorage` — unverändert - `CanonicalJson` — unverändert - `DeviceIdProvider` — unverändert - `WaypointApp.onCreate` — unverändert - Signaturprüfung (ECDSA-P256-SHA256) — unverändert - Public Key (res/raw/gps2audio_license_public.pem) — unverändert - Backup-Regeln (backup_rules.xml, data_extraction_rules.xml) — unverändert - Tourcover-Backup-Fix (v2.5.31) — unberührt - Tourwechsel-Wiedergabe (v2.5.30) — unberührt - Lizenzpersistenz (v2.5.29) — unberührt - Lizenzimport-Threadfix (v2.5.25) — unberührt - GPX additiv, Backup/Import, Explorer/MapLibre/Routing — unberührt - Atmo in Touransicht, Hintergrundwiedergabe — unberührt - Tour duplizieren, Waypoint Copy, Sequenzplayer, Countdown, maximierter Player — unberührt --- ## Build- / Signaturergebnis | Parameter | Wert | |---|---| | Build-Ergebnis | **BUILD SUCCESSFUL** | | Dauer | ~83 Sekunden | | APK-Größe | ~57 MB | | Signatur-Schema | APK Signature Scheme v2 ✓ | | Signatur-Alias | gps2audio_release_v2 | | Keystore | GPS2Audio_release_keystore_v2.jks (RSA 4096, 30 Jahre) | | apksigner verify | **Verifies** | | Warnungen im Build | Nur vorbestehende Deprecation-Warnings (menuAnchor, Divider, DirectionsBike) — keine neuen | --- ## Artefakte | Datei | Beschreibung | |---|---| | `GPS2Audio_v2_5_32_professional_feature_gates_signed.apk` | Signiertes Release-APK (v2-Signatur) | | `GPS2Audio_v2_5_32_professional_feature_gates_source.zip` | Quellcode ohne Build-Artefakte und Keystore | | `GPS2Audio_v2_5_32_professional_feature_gates_handoff.md` | Dieses Dokument |