266 lines
11 KiB
Kotlin
266 lines
11 KiB
Kotlin
package de.waypointaudio.ui
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.Row
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.rememberScrollState
|
|
import androidx.compose.foundation.verticalScroll
|
|
import androidx.compose.material3.AlertDialog
|
|
import androidx.compose.material3.Card
|
|
import androidx.compose.material3.CardDefaults
|
|
import androidx.compose.material3.Checkbox
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.OutlinedButton
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.material3.TextButton
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.collectAsState
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
import androidx.compose.runtime.setValue
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.text.font.FontWeight
|
|
import androidx.compose.ui.unit.dp
|
|
import de.waypointaudio.R
|
|
import de.waypointaudio.data.BackgroundReliabilityStore
|
|
import de.waypointaudio.util.AppVersion
|
|
import de.waypointaudio.util.BackgroundReliability
|
|
import kotlinx.coroutines.launch
|
|
|
|
/**
|
|
* v2.5.13 — Dezenter Hinweis "Hintergrundwiedergabe absichern".
|
|
*
|
|
* Anzeigeregeln:
|
|
* - Nur sichtbar, wenn die App NICHT von Akkuoptimierungen ausgenommen ist
|
|
* (sonst gibt es nichts zu tun) UND der Nutzer den Hinweis für diese
|
|
* Version noch nicht weggeklickt hat.
|
|
* - Auf Xiaomi/Redmi/Poco wird die spezifische Schrittliste (Akku, Autostart,
|
|
* Recents-Schloss, Notifications) gezeigt — sonst eine generische Variante.
|
|
* - "Verstanden" merkt den aktuellen versionCode, "Nicht mehr anzeigen" ist
|
|
* eine Checkbox, weil so vorhandene Dialoge in der App (Versionshinweis,
|
|
* Terms) bereits funktionieren — konsistente UX.
|
|
* - Blockiert die Wiedergabe nicht: der Nutzer kann den Dialog jederzeit
|
|
* schließen, und das Playback läuft währenddessen weiter.
|
|
*/
|
|
@Composable
|
|
fun BackgroundReliabilityDialogHost(
|
|
/**
|
|
* Auslöser, ob der Hinweis überhaupt geprüft werden soll. Wird die
|
|
* Komponente immer in der Composition gehalten, übernimmt sie selbst
|
|
* die Anzeige-Entscheidung; das ist gewollt einfach.
|
|
*/
|
|
triggerCheck: Boolean,
|
|
onDismissed: () -> Unit = {}
|
|
) {
|
|
val context = LocalContext.current
|
|
val store = remember(context) {
|
|
BackgroundReliabilityStore(context.applicationContext)
|
|
}
|
|
val versionInfo = remember(context) { AppVersion.get(context) }
|
|
|
|
val dismissedCode by store.dismissedVersionCode.collectAsState(initial = -1L)
|
|
val scope = rememberCoroutineScope()
|
|
|
|
var visible by remember { mutableStateOf(false) }
|
|
var dontShowAgain by remember { mutableStateOf(false) }
|
|
|
|
LaunchedEffect(triggerCheck, dismissedCode, versionInfo.versionCode) {
|
|
if (!triggerCheck) return@LaunchedEffect
|
|
if (dismissedCode < 0L) return@LaunchedEffect
|
|
if (dismissedCode >= versionInfo.versionCode) return@LaunchedEffect
|
|
// Bereits ausgenommen → kein Bedarf, Nutzer mit dem Hinweis zu nerven.
|
|
if (BackgroundReliability.isIgnoringBatteryOptimizations(context)) return@LaunchedEffect
|
|
visible = true
|
|
}
|
|
|
|
if (!visible) return
|
|
|
|
BackgroundReliabilityDialog(
|
|
isXiaomi = BackgroundReliability.isXiaomiFamily(),
|
|
isOptimizationsIgnored = BackgroundReliability.isIgnoringBatteryOptimizations(context),
|
|
dontShowAgain = dontShowAgain,
|
|
onDontShowAgainChanged = { dontShowAgain = it },
|
|
onOpenBattery = { BackgroundReliability.openBatteryOptimizationSettings(context) },
|
|
onOpenAppDetails = { BackgroundReliability.openAppDetailsSettings(context) },
|
|
onOpenNotifications = { BackgroundReliability.openNotificationSettings(context) },
|
|
onOpenXiaomiAutostart = { BackgroundReliability.openXiaomiAutostartSettings(context) },
|
|
onDismiss = {
|
|
if (dontShowAgain) {
|
|
scope.launch {
|
|
store.setDismissedVersionCode(versionInfo.versionCode)
|
|
}
|
|
}
|
|
visible = false
|
|
onDismissed()
|
|
}
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Manuell aufrufbarer Dialog für den Einstellungen/About-Bereich. Ignoriert
|
|
* den "für Version verstanden"-Speicher und zeigt den Hinweis immer.
|
|
*/
|
|
@Composable
|
|
fun BackgroundReliabilityManualDialog(
|
|
onClose: () -> Unit
|
|
) {
|
|
val context = LocalContext.current
|
|
BackgroundReliabilityDialog(
|
|
isXiaomi = BackgroundReliability.isXiaomiFamily(),
|
|
isOptimizationsIgnored = BackgroundReliability.isIgnoringBatteryOptimizations(context),
|
|
dontShowAgain = false,
|
|
onDontShowAgainChanged = {},
|
|
showDontShowAgain = false,
|
|
onOpenBattery = { BackgroundReliability.openBatteryOptimizationSettings(context) },
|
|
onOpenAppDetails = { BackgroundReliability.openAppDetailsSettings(context) },
|
|
onOpenNotifications = { BackgroundReliability.openNotificationSettings(context) },
|
|
onOpenXiaomiAutostart = { BackgroundReliability.openXiaomiAutostartSettings(context) },
|
|
onDismiss = onClose
|
|
)
|
|
}
|
|
|
|
@Composable
|
|
private fun BackgroundReliabilityDialog(
|
|
isXiaomi: Boolean,
|
|
isOptimizationsIgnored: Boolean,
|
|
dontShowAgain: Boolean,
|
|
onDontShowAgainChanged: (Boolean) -> Unit,
|
|
onOpenBattery: () -> Unit,
|
|
onOpenAppDetails: () -> Unit,
|
|
onOpenNotifications: () -> Unit,
|
|
onOpenXiaomiAutostart: () -> Unit,
|
|
onDismiss: () -> Unit,
|
|
showDontShowAgain: Boolean = true
|
|
) {
|
|
AlertDialog(
|
|
onDismissRequest = onDismiss,
|
|
title = {
|
|
Text(
|
|
text = stringResource(R.string.bg_reliability_title),
|
|
style = MaterialTheme.typography.headlineSmall
|
|
)
|
|
},
|
|
text = {
|
|
Column(
|
|
modifier = Modifier.verticalScroll(rememberScrollState()),
|
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
) {
|
|
Text(
|
|
text = stringResource(R.string.bg_reliability_intro),
|
|
style = MaterialTheme.typography.bodyMedium
|
|
)
|
|
Card(
|
|
colors = CardDefaults.cardColors(
|
|
containerColor = MaterialTheme.colorScheme.surfaceVariant
|
|
)
|
|
) {
|
|
Box(Modifier.padding(12.dp)) {
|
|
Text(
|
|
text = if (isOptimizationsIgnored) {
|
|
stringResource(R.string.bg_reliability_status_ok)
|
|
} else {
|
|
stringResource(R.string.bg_reliability_status_optimized)
|
|
},
|
|
style = MaterialTheme.typography.bodySmall
|
|
)
|
|
}
|
|
}
|
|
if (isXiaomi) {
|
|
Text(
|
|
text = stringResource(R.string.bg_reliability_xiaomi_heading),
|
|
style = MaterialTheme.typography.titleMedium,
|
|
fontWeight = FontWeight.SemiBold
|
|
)
|
|
BulletLine(stringResource(R.string.bg_reliability_xiaomi_item_battery))
|
|
BulletLine(stringResource(R.string.bg_reliability_xiaomi_item_autostart))
|
|
BulletLine(stringResource(R.string.bg_reliability_xiaomi_item_lock))
|
|
BulletLine(stringResource(R.string.bg_reliability_xiaomi_item_notify))
|
|
} else {
|
|
Text(
|
|
text = stringResource(R.string.bg_reliability_generic_heading),
|
|
style = MaterialTheme.typography.titleMedium,
|
|
fontWeight = FontWeight.SemiBold
|
|
)
|
|
BulletLine(stringResource(R.string.bg_reliability_generic_item_battery))
|
|
BulletLine(stringResource(R.string.bg_reliability_generic_item_notify))
|
|
}
|
|
|
|
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
|
OutlinedButton(
|
|
onClick = onOpenBattery,
|
|
modifier = Modifier.fillMaxWidth()
|
|
) {
|
|
Text(stringResource(R.string.bg_reliability_btn_battery))
|
|
}
|
|
OutlinedButton(
|
|
onClick = onOpenNotifications,
|
|
modifier = Modifier.fillMaxWidth()
|
|
) {
|
|
Text(stringResource(R.string.bg_reliability_btn_notify))
|
|
}
|
|
OutlinedButton(
|
|
onClick = onOpenAppDetails,
|
|
modifier = Modifier.fillMaxWidth()
|
|
) {
|
|
Text(stringResource(R.string.bg_reliability_btn_app))
|
|
}
|
|
if (isXiaomi) {
|
|
OutlinedButton(
|
|
onClick = onOpenXiaomiAutostart,
|
|
modifier = Modifier.fillMaxWidth()
|
|
) {
|
|
Text(stringResource(R.string.bg_reliability_btn_autostart))
|
|
}
|
|
}
|
|
}
|
|
|
|
if (showDontShowAgain) {
|
|
Row(
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.padding(top = 4.dp)
|
|
) {
|
|
Checkbox(
|
|
checked = dontShowAgain,
|
|
onCheckedChange = onDontShowAgainChanged
|
|
)
|
|
Text(
|
|
text = stringResource(R.string.bg_reliability_dont_show_again),
|
|
style = MaterialTheme.typography.bodyMedium
|
|
)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
confirmButton = {
|
|
TextButton(onClick = onDismiss) {
|
|
Text(stringResource(R.string.bg_reliability_understood))
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
@Composable
|
|
private fun BulletLine(text: String) {
|
|
Row(verticalAlignment = Alignment.Top) {
|
|
Text(
|
|
text = "• ",
|
|
style = MaterialTheme.typography.bodyMedium
|
|
)
|
|
Text(
|
|
text = text,
|
|
style = MaterialTheme.typography.bodyMedium
|
|
)
|
|
}
|
|
}
|