Files
GPS2Audio/app/src/main/kotlin/de/waypointaudio/license/LicenseFeatureAccess.kt
T
2026-05-30 05:42:44 +00:00

102 lines
3.9 KiB
Kotlin

package de.waypointaudio.license
/**
* v2.5.32 — Zentrale Feature-Berechtigungsprüfung.
*
* Diese Klasse kapselt alle Regeln, welche Lizenztypen Zugriff auf
* Profi-Funktionen gewähren. Sie liest ausschließlich aus [LicenseStatus]
* und ändert NIEMALS Lizenzdaten, Import-Logik, Signaturprüfung,
* Geräte-ID, CanonicalJson oder Backup-Regeln.
*
* Lizenztypen mit professionellem Zugang:
* - "pro", "profi", "commercial" → Profi-Zugang solange status == VALID
* - "developer" → immer erlaubt wenn status == VALID
* - "trial" → Profi-Zugang solange status == VALID (valid_until-Prüfung
* erfolgt bereits in LicenseValidator; ist abgelaufen → state == EXPIRED)
*
* Ohne Lizenz (state == NONE) oder mit abgelaufener/ungültiger Lizenz:
* - Keine Profi-Funktion freigegeben.
* - Vorhandene Daten (Zusatzclips, PTT-Aufnahmen, Zählerwerte) werden
* NIEMALS gelöscht.
*
* Feature-Gates:
* - [hasProfessionalAccess]: gemeinsames Haupt-Gate
* - [canUseMultiClip]: Zusatzclips bearbeiten/hinzufügen/aktivieren
* - [canUsePtt]: PTT-Modul anzeigen/nutzen
* - [canUseTourCounter]: Tour-Zähler anzeigen/nutzen
*
* UI-Empfehlung: Prüfe den Status über [LicenseStatusProvider.status], das
* als Compose-State vorliegt. Reagiert reaktiv auf Lizenzimport ohne
* App-Neustart.
*/
object LicenseFeatureAccess {
/**
* Professionelle Lizenztypen (case-insensitive), die Profi-Zugang gewähren.
*/
private val PRO_LICENSE_TYPES = setOf("pro", "profi", "commercial", "developer", "trial")
/**
* Prüft, ob die aktuelle Lizenz professionellen Zugang gewährt.
*
* Bedingungen:
* 1. [LicenseStatus.state] muss [LicenseStatus.State.VALID] sein.
* 2. [LicenseStatus.licenseTypeRaw] muss in [PRO_LICENSE_TYPES] enthalten sein
* (case-insensitive), ODER in [LicenseStatus.permissions] ist mindestens
* eine Profi-Permission gesetzt.
* 3. Developer-Lizenzen sind immer eingeschlossen, wenn state == VALID.
*/
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 (z. B. "commercial_use" oder "paid_tours")
return status.permissions.any { (_, v) -> v }
}
/**
* Shortcut: Liest den aktuellen Status direkt aus [LicenseStatusProvider].
* Für Compose-Code bevorzuge den Status-Parameter, damit die Rekomposition
* reaktiv funktioniert.
*/
fun hasProfessionalAccessCurrent(): Boolean =
hasProfessionalAccess(LicenseStatusProvider.current())
/**
* Multi-Clip-Waypoints: Bearbeiten, Hinzufügen, Aktivieren von Zusatzclips.
* Hauptclip (index 0 / isPrimary) bleibt immer frei.
* Bestehende Clips werden niemals gelöscht.
*/
fun canUseMultiClip(status: LicenseStatus): Boolean = hasProfessionalAccess(status)
/**
* PTT (Push-to-Talk): Live-PTT-Modul, Aufnahmen starten.
* Bestehende PTT-Aufnahmen bleiben erhalten.
*/
fun canUsePtt(status: LicenseStatus): Boolean = hasProfessionalAccess(status)
/**
* Tour-Zähler: Abspiel-Modi, Zähler-Reset, Vorgaben.
* Bestehende Zählerwerte bleiben erhalten.
*/
fun canUseTourCounter(status: LicenseStatus): Boolean = hasProfessionalAccess(status)
/**
* Freundlicher Hinweistext für das Multi-Clip-Gate.
*/
const val MSG_MULTI_CLIP =
"Multi-Clip-Waypoints sind Teil der GPS2Audio Profi-Lizenz."
/**
* Freundlicher Hinweistext für das PTT-Gate.
*/
const val MSG_PTT =
"Live-PTT ist Teil der GPS2Audio Profi-Lizenz."
/**
* Freundlicher Hinweistext für das Tour-Zähler-Gate.
*/
const val MSG_TOUR_COUNTER =
"Der Tour-Zähler ist Teil der GPS2Audio Profi-Lizenz."
}