fix(Compose): Adjusted universal patches safeguard and warnings (#2550)

This commit is contained in:
Brosssh 2025-05-17 21:33:02 +02:00 committed by oSumAtrIX
parent 5153e5e0cb
commit 2b380b0d7c
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
8 changed files with 88 additions and 165 deletions

View File

@ -234,7 +234,7 @@ private fun ReVancedManager(vm: MainViewModel) {
selectedAppInfoVm.updateConfiguration(patches, options)
navController.popBackStack()
},
vm = koinViewModel { parametersOf(data) }
viewModel = koinViewModel { parametersOf(data) }
)
}

View File

@ -25,7 +25,7 @@ class PreferencesManager(
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
val disableUniversalPatchWarning = booleanPreference("disable_universal_patch_warning", false)
val disableUniversalPatchCheck = booleanPreference("disable_patch_universal_check", false)
val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true)
val acknowledgedDownloaderPlugins = stringSetPreference("acknowledged_downloader_plugins", emptySet())

View File

@ -1,6 +1,8 @@
package app.revanced.manager.ui.component.settings
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -9,7 +11,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.domain.manager.base.Preference
import app.revanced.manager.ui.component.ConfirmDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ -28,13 +32,15 @@ fun SafeguardBooleanItem(
}
if (showSafeguardWarning) {
SafeguardConfirmationDialog(
ConfirmDialog(
onDismiss = { showSafeguardWarning = false },
onConfirm = {
coroutineScope.launch { preference.update(!value) }
showSafeguardWarning = false
},
body = stringResource(confirmationText)
title = stringResource(id = R.string.warning),
description = stringResource(confirmationText),
icon = Icons.Outlined.WarningAmber
)
}

View File

@ -1,46 +0,0 @@
package app.revanced.manager.ui.component.settings
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import app.revanced.manager.R
@Composable
fun SafeguardConfirmationDialog(
onDismiss: () -> Unit,
onConfirm: () -> Unit,
body: String,
) {
AlertDialog(
onDismissRequest = onDismiss,
confirmButton = {
TextButton(onClick = onConfirm) {
Text(stringResource(R.string.yes))
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.no))
}
},
icon = {
Icon(Icons.Outlined.WarningAmber, null)
},
title = {
Text(
text = stringResource(id = R.string.warning),
style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center)
)
},
text = {
Text(body)
}
)
}

View File

@ -58,7 +58,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import app.revanced.manager.R
@ -88,9 +87,9 @@ import kotlinx.coroutines.launch
fun PatchesSelectorScreen(
onSave: (PatchSelection?, Options) -> Unit,
onBackClick: () -> Unit,
vm: PatchesSelectorViewModel
viewModel: PatchesSelectorViewModel
) {
val bundles by vm.bundlesFlow.collectAsStateWithLifecycle(initialValue = emptyList())
val bundles by viewModel.bundlesFlow.collectAsStateWithLifecycle(initialValue = emptyList())
val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f
@ -106,15 +105,15 @@ fun PatchesSelectorScreen(
}
var showBottomSheet by rememberSaveable { mutableStateOf(false) }
val showSaveButton by remember {
derivedStateOf { vm.selectionIsValid(bundles) }
derivedStateOf { viewModel.selectionIsValid(bundles) }
}
val defaultPatchSelectionCount by vm.defaultSelectionCount
val defaultPatchSelectionCount by viewModel.defaultSelectionCount
.collectAsStateWithLifecycle(initialValue = 0)
val selectedPatchCount by remember {
derivedStateOf {
vm.customPatchSelection?.values?.sumOf { it.size } ?: defaultPatchSelectionCount
viewModel.customPatchSelection?.values?.sumOf { it.size } ?: defaultPatchSelectionCount
}
}
@ -146,14 +145,14 @@ fun PatchesSelectorScreen(
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
CheckedFilterChip(
selected = vm.filter and SHOW_INCOMPATIBLE == 0,
onClick = { vm.toggleFlag(SHOW_INCOMPATIBLE) },
selected = viewModel.filter and SHOW_INCOMPATIBLE == 0,
onClick = { viewModel.toggleFlag(SHOW_INCOMPATIBLE) },
label = { Text(stringResource(R.string.this_version)) }
)
CheckedFilterChip(
selected = vm.filter and SHOW_UNIVERSAL != 0,
onClick = { vm.toggleFlag(SHOW_UNIVERSAL) },
selected = viewModel.filter and SHOW_UNIVERSAL != 0,
onClick = { viewModel.toggleFlag(SHOW_UNIVERSAL) },
label = { Text(stringResource(R.string.universal)) },
)
}
@ -161,43 +160,39 @@ fun PatchesSelectorScreen(
}
}
if (vm.compatibleVersions.isNotEmpty())
if (viewModel.compatibleVersions.isNotEmpty())
IncompatiblePatchDialog(
appVersion = vm.appVersion ?: stringResource(R.string.any_version),
compatibleVersions = vm.compatibleVersions,
onDismissRequest = vm::dismissDialogs
appVersion = viewModel.appVersion ?: stringResource(R.string.any_version),
compatibleVersions = viewModel.compatibleVersions,
onDismissRequest = viewModel::dismissDialogs
)
var showIncompatiblePatchesDialog by rememberSaveable {
mutableStateOf(false)
}
if (showIncompatiblePatchesDialog)
IncompatiblePatchesDialog(
appVersion = vm.appVersion ?: stringResource(R.string.any_version),
appVersion = viewModel.appVersion ?: stringResource(R.string.any_version),
onDismissRequest = { showIncompatiblePatchesDialog = false }
)
vm.optionsDialog?.let { (bundle, patch) ->
viewModel.optionsDialog?.let { (bundle, patch) ->
OptionsDialog(
onDismissRequest = vm::dismissDialogs,
onDismissRequest = viewModel::dismissDialogs,
patch = patch,
values = vm.getOptions(bundle, patch),
reset = { vm.resetOptions(bundle, patch) },
set = { key, value -> vm.setOption(bundle, patch, key, value) }
values = viewModel.getOptions(bundle, patch),
reset = { viewModel.resetOptions(bundle, patch) },
set = { key, value -> viewModel.setOption(bundle, patch, key, value) }
)
}
var showSelectionWarning by rememberSaveable {
mutableStateOf(false)
}
if (showSelectionWarning) {
var showSelectionWarning by rememberSaveable { mutableStateOf(false) }
var showUniversalWarning by rememberSaveable { mutableStateOf(false) }
if (showSelectionWarning)
SelectionWarningDialog(onDismiss = { showSelectionWarning = false })
}
vm.pendingUniversalPatchAction?.let {
UniversalPatchWarningDialog(
onCancel = vm::dismissUniversalPatchWarning,
onConfirm = vm::confirmUniversalPatchWarning
)
}
if (showUniversalWarning)
UniversalPatchWarningDialog(onDismiss = { showUniversalWarning = false })
fun LazyListScope.patchList(
uid: Int,
@ -221,27 +216,25 @@ fun PatchesSelectorScreen(
PatchItem(
patch = patch,
onOptionsDialog = {
vm.optionsDialog = uid to patch
viewModel.optionsDialog = uid to patch
},
selected = compatible && vm.isSelected(
selected = compatible && viewModel.isSelected(
uid,
patch
),
onToggle = {
when {
// Open incompatible dialog if the patch is not supported
!compatible -> vm.openIncompatibleDialog(patch)
!compatible -> viewModel.openIncompatibleDialog(patch)
// Show selection warning if enabled
vm.selectionWarningEnabled -> showSelectionWarning = true
viewModel.selectionWarningEnabled -> showSelectionWarning = true
// Set pending universal patch action if the universal patch warning is enabled and there are no compatible packages
vm.universalPatchWarningEnabled && patch.compatiblePackages == null -> {
vm.pendingUniversalPatchAction = { vm.togglePatch(uid, patch) }
}
// Show universal warning if enabled
viewModel.universalPatchWarningEnabled -> showUniversalWarning = true
// Toggle the patch otherwise
else -> vm.togglePatch(uid, patch)
else -> viewModel.togglePatch(uid, patch)
}
},
compatible = compatible
@ -327,7 +320,7 @@ fun PatchesSelectorScreen(
patchList(
uid = bundle.uid,
patches = bundle.universal.searched(),
visible = vm.filter and SHOW_UNIVERSAL != 0,
visible = viewModel.filter and SHOW_UNIVERSAL != 0,
compatible = true
) {
ListHeader(
@ -338,8 +331,8 @@ fun PatchesSelectorScreen(
patchList(
uid = bundle.uid,
patches = bundle.incompatible.searched(),
visible = vm.filter and SHOW_INCOMPATIBLE != 0,
compatible = vm.allowIncompatiblePatches
visible = viewModel.filter and SHOW_INCOMPATIBLE != 0,
compatible = viewModel.allowIncompatiblePatches
) {
ListHeader(
title = stringResource(R.string.incompatible_patches),
@ -362,7 +355,7 @@ fun PatchesSelectorScreen(
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
SmallFloatingActionButton(
onClick = vm::reset,
onClick = viewModel::reset,
containerColor = MaterialTheme.colorScheme.tertiaryContainer
) {
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
@ -385,7 +378,7 @@ fun PatchesSelectorScreen(
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp
?: true,
onClick = {
onSave(vm.getCustomSelection(), vm.getOptions())
onSave(viewModel.getCustomSelection(), viewModel.getOptions())
}
)
}
@ -453,7 +446,7 @@ fun PatchesSelectorScreen(
patchList(
uid = bundle.uid,
patches = bundle.universal,
visible = vm.filter and SHOW_UNIVERSAL != 0,
visible = viewModel.filter and SHOW_UNIVERSAL != 0,
compatible = true
) {
ListHeader(
@ -463,8 +456,8 @@ fun PatchesSelectorScreen(
patchList(
uid = bundle.uid,
patches = bundle.incompatible,
visible = vm.filter and SHOW_INCOMPATIBLE != 0,
compatible = vm.allowIncompatiblePatches
visible = viewModel.filter and SHOW_INCOMPATIBLE != 0,
compatible = viewModel.allowIncompatiblePatches
) {
ListHeader(
title = stringResource(R.string.incompatible_patches),
@ -479,7 +472,9 @@ fun PatchesSelectorScreen(
}
@Composable
private fun SelectionWarningDialog(onDismiss: () -> Unit) {
private fun SelectionWarningDialog(
onDismiss: () -> Unit
) {
SafeguardDialog(
onDismiss = onDismiss,
title = R.string.warning,
@ -489,33 +484,12 @@ private fun SelectionWarningDialog(onDismiss: () -> Unit) {
@Composable
private fun UniversalPatchWarningDialog(
onCancel: () -> Unit,
onConfirm: () -> Unit
onDismiss: () -> Unit
) {
AlertDialog(
onDismissRequest = onCancel,
confirmButton = {
TextButton(onClick = onConfirm) {
Text(stringResource(R.string.continue_))
}
},
dismissButton = {
TextButton(onClick = onCancel) {
Text(stringResource(R.string.cancel))
}
},
icon = {
Icon(Icons.Outlined.WarningAmber, null)
},
title = {
Text(
text = stringResource(R.string.warning),
style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center)
)
},
text = {
Text(stringResource(R.string.universal_patch_warning_description))
}
SafeguardDialog(
onDismiss = onDismiss,
title = R.string.warning,
body = stringResource(R.string.universal_patch_warning_description),
)
}

View File

@ -61,7 +61,7 @@ import org.koin.androidx.compose.koinViewModel
@Composable
fun AdvancedSettingsScreen(
onBackClick: () -> Unit,
vm: AdvancedSettingsViewModel = koinViewModel()
viewModel: AdvancedSettingsViewModel = koinViewModel()
) {
val context = LocalContext.current
val memoryLimit = remember {
@ -91,16 +91,16 @@ fun AdvancedSettingsScreen(
) {
GroupHeader(stringResource(R.string.manager))
val apiUrl by vm.prefs.api.getAsState()
val apiUrl by viewModel.prefs.api.getAsState()
var showApiUrlDialog by rememberSaveable { mutableStateOf(false) }
if (showApiUrlDialog) {
APIUrlDialog(
currentUrl = apiUrl,
defaultUrl = vm.prefs.api.default,
defaultUrl = viewModel.prefs.api.default,
onSubmit = {
showApiUrlDialog = false
it?.let(vm::setApiUrl)
it?.let(viewModel::setApiUrl)
}
)
}
@ -114,44 +114,44 @@ fun AdvancedSettingsScreen(
GroupHeader(stringResource(R.string.safeguards))
SafeguardBooleanItem(
preference = vm.prefs.disablePatchVersionCompatCheck,
coroutineScope = vm.viewModelScope,
preference = viewModel.prefs.disablePatchVersionCompatCheck,
coroutineScope = viewModel.viewModelScope,
headline = R.string.patch_compat_check,
description = R.string.patch_compat_check_description,
confirmationText = R.string.patch_compat_check_confirmation
)
SafeguardBooleanItem(
preference = vm.prefs.disableUniversalPatchWarning,
coroutineScope = vm.viewModelScope,
headline = R.string.universal_patches_safeguard,
description = R.string.universal_patches_safeguard_description,
confirmationText = R.string.universal_patches_safeguard_confirmation
)
SafeguardBooleanItem(
preference = vm.prefs.suggestedVersionSafeguard,
coroutineScope = vm.viewModelScope,
preference = viewModel.prefs.suggestedVersionSafeguard,
coroutineScope = viewModel.viewModelScope,
headline = R.string.suggested_version_safeguard,
description = R.string.suggested_version_safeguard_description,
confirmationText = R.string.suggested_version_safeguard_confirmation
)
SafeguardBooleanItem(
preference = vm.prefs.disableSelectionWarning,
coroutineScope = vm.viewModelScope,
preference = viewModel.prefs.disableSelectionWarning,
coroutineScope = viewModel.viewModelScope,
headline = R.string.patch_selection_safeguard,
description = R.string.patch_selection_safeguard_description,
confirmationText = R.string.patch_selection_safeguard_confirmation
)
SafeguardBooleanItem(
preference = viewModel.prefs.disableUniversalPatchCheck,
coroutineScope = viewModel.viewModelScope,
headline = R.string.universal_patches_safeguard,
description = R.string.universal_patches_safeguard_description,
confirmationText = R.string.universal_patches_safeguard_confirmation
)
GroupHeader(stringResource(R.string.patcher))
BooleanItem(
preference = vm.prefs.useProcessRuntime,
coroutineScope = vm.viewModelScope,
preference = viewModel.prefs.useProcessRuntime,
coroutineScope = viewModel.viewModelScope,
headline = R.string.process_runtime,
description = R.string.process_runtime_description,
)
IntegerItem(
preference = vm.prefs.patcherProcessMemoryLimit,
coroutineScope = vm.viewModelScope,
preference = viewModel.prefs.patcherProcessMemoryLimit,
coroutineScope = viewModel.viewModelScope,
headline = R.string.process_runtime_memory_limit,
description = R.string.process_runtime_memory_limit_description,
)
@ -159,11 +159,11 @@ fun AdvancedSettingsScreen(
GroupHeader(stringResource(R.string.debugging))
val exportDebugLogsLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
it?.let(vm::exportDebugLogs)
it?.let(viewModel::exportDebugLogs)
}
SettingsListItem(
headlineContent = stringResource(R.string.debug_logs_export),
modifier = Modifier.clickable { exportDebugLogsLauncher.launch(vm.debugLogFileName) }
modifier = Modifier.clickable { exportDebugLogsLauncher.launch(viewModel.debugLogFileName) }
)
val clipboard = remember { context.getSystemService<ClipboardManager>()!! }
val deviceContent = """

View File

@ -55,8 +55,6 @@ class PatchesSelectorViewModel(input: SelectedApplicationInfo.PatchesSelector.Vi
private val packageName = input.app.packageName
val appVersion = input.app.version
var pendingUniversalPatchAction by mutableStateOf<(() -> Unit)?>(null)
var selectionWarningEnabled by mutableStateOf(true)
private set
var universalPatchWarningEnabled by mutableStateOf(true)
@ -69,7 +67,9 @@ class PatchesSelectorViewModel(input: SelectedApplicationInfo.PatchesSelector.Vi
init {
viewModelScope.launch {
universalPatchWarningEnabled = !prefs.disableUniversalPatchWarning.get()
if (prefs.disableUniversalPatchCheck.get()) {
universalPatchWarningEnabled = false
}
if (prefs.disableSelectionWarning.get()) {
selectionWarningEnabled = false
@ -160,17 +160,6 @@ class PatchesSelectorViewModel(input: SelectedApplicationInfo.PatchesSelector.Vi
customPatchSelection = selection.put(bundle, newPatches)
}
fun confirmUniversalPatchWarning() {
universalPatchWarningEnabled = false
pendingUniversalPatchAction?.invoke()
pendingUniversalPatchAction = null
}
fun dismissUniversalPatchWarning() {
pendingUniversalPatchAction = null
}
fun reset() {
patchOptions.clear()
customPatchSelection = null

View File

@ -100,8 +100,8 @@
<string name="patch_selection_safeguard">Allow changing patch selection</string>
<string name="patch_selection_safeguard_description">Do not prevent selecting or deselecting patches</string>
<string name="patch_selection_safeguard_confirmation">Changing the selection of patches may cause unexpected issues.\n\nEnable anyways?</string>
<string name="universal_patches_safeguard">Disable universal patch warning</string>
<string name="universal_patches_safeguard_description">Disables the warning that appears when you try to select universal patches</string>
<string name="universal_patches_safeguard">Allow using universal patches</string>
<string name="universal_patches_safeguard_description">Do not prevent using universal patches</string>
<string name="universal_patches_safeguard_confirmation">Universal patches are not as well tested as those that target specific apps.\n\nEnable anyways?</string>
<string name="import_keystore">Import keystore</string>
<string name="import_keystore_description">Import a custom keystore</string>
@ -226,7 +226,7 @@
<string name="non_suggested_version_warning_description">The version of the app you have selected does not match the suggested version.\nPlease use the suggested version: %s\n\nTo continue anyway, disable \"Require suggested app version\" in the advanced settings.</string>
<string name="selection_warning_title">Stop using defaults?</string>
<string name="selection_warning_description">It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou need to turn on \"Allow changing patch selection\" in the advanced settings before toggling patches.</string>
<string name="universal_patch_warning_description">Universal patches have a more generalized use and do not work as reliably as patches that target specific apps. You may encounter issues while using them.\n\nThis warning can be disabled in the advanced settings.</string>
<string name="universal_patch_warning_description">Universal patches have a more generalized use and do not work as reliably as patches that target specific apps. You may encounter issues while using them.\n\nYou need to turn on \"Allow using universal patches\" in the advanced settings before using universal patches.</string>
<string name="this_version">This version</string>
<string name="universal">Any app</string>
<string name="search_patches">Search patches</string>