feat: improve the safeguards (#2038)

This commit is contained in:
Ax333l
2024-07-06 17:43:37 +02:00
committed by oSumAtrIX
parent d3d4c27f6d
commit e5b414e277
13 changed files with 136 additions and 218 deletions

View File

@@ -15,7 +15,6 @@ class PreferencesManager(
val multithreadingDexFileWriter = booleanPreference("multithreading_dex_file_writer", true)
val useProcessRuntime = booleanPreference("use_process_runtime", false)
val patcherProcessMemoryLimit = intPreference("process_runtime_memory_limit", 700)
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
val keystoreCommonName = stringPreference("keystore_cn", KeystoreManager.DEFAULT)
val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT)
@@ -25,8 +24,8 @@ class PreferencesManager(
val firstLaunch = booleanPreference("first_launch", true)
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
val enableSelectionWarningCountdown = booleanPreference("enable_selection_warning_countdown", true)
val disableUniversalPatchWarning = booleanPreference("disable_universal_patch_warning", false)
val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true)
}

View File

@@ -1,26 +0,0 @@
package app.revanced.manager.ui.component
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import kotlinx.coroutines.delay
@Composable
fun Countdown(start: Int, content: @Composable (Int) -> Unit) {
var timer by rememberSaveable(start) {
mutableStateOf(start)
}
LaunchedEffect(timer) {
if (timer == 0) {
return@LaunchedEffect
}
delay(1000L)
timer -= 1
}
content(timer)
}

View File

@@ -1,91 +0,0 @@
package app.revanced.manager.ui.component
import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
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.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
@Composable
fun DangerousActionDialogBase(
onCancel: () -> Unit,
confirmButton: @Composable (Boolean) -> Unit,
@StringRes title: Int,
body: String,
) {
var dismissPermanently by rememberSaveable {
mutableStateOf(false)
}
AlertDialog(
onDismissRequest = onCancel,
confirmButton = {
confirmButton(dismissPermanently)
},
dismissButton = {
TextButton(onClick = onCancel) {
Text(stringResource(R.string.cancel))
}
},
icon = {
Icon(Icons.Outlined.WarningAmber, null)
},
title = {
Text(
text = stringResource(title),
style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center),
color = MaterialTheme.colorScheme.onSurface,
)
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.Start
) {
Text(
text = body,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(0.dp),
modifier = Modifier
.fillMaxWidth()
.clickable {
dismissPermanently = !dismissPermanently
}
) {
Checkbox(
checked = dismissPermanently,
onCheckedChange = {
dismissPermanently = it
}
)
Text(stringResource(R.string.permanent_dismiss))
}
}
}
)
}

View File

@@ -1,23 +0,0 @@
package app.revanced.manager.ui.component
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
@Composable
fun NonSuggestedVersionDialog(suggestedVersion: String, onCancel: () -> Unit, onContinue: (Boolean) -> Unit) {
DangerousActionDialogBase(
onCancel = onCancel,
confirmButton = { dismissPermanently ->
TextButton(
onClick = { onContinue(dismissPermanently) }
) {
Text(stringResource(R.string.continue_))
}
},
title = R.string.non_suggested_version_warning_title,
body = stringResource(R.string.non_suggested_version_warning_description, suggestedVersion),
)
}

View File

@@ -0,0 +1,51 @@
package app.revanced.manager.ui.component
import androidx.annotation.StringRes
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 SafeguardDialog(
onDismiss: () -> Unit,
@StringRes title: Int,
body: String,
) {
AlertDialog(
onDismissRequest = onDismiss,
confirmButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.ok))
}
},
icon = {
Icon(Icons.Outlined.WarningAmber, null)
},
title = {
Text(
text = stringResource(title),
style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center)
)
},
text = {
Text(body)
}
)
}
@Composable
fun NonSuggestedVersionDialog(suggestedVersion: String, onDismiss: () -> Unit) {
SafeguardDialog(
onDismiss = onDismiss,
title = R.string.non_suggested_version_warning_title,
body = stringResource(R.string.non_suggested_version_warning_description, suggestedVersion),
)
}

View File

@@ -70,8 +70,7 @@ fun AppSelectorScreen(
vm.nonSuggestedVersionDialogSubject?.let {
NonSuggestedVersionDialog(
suggestedVersion = suggestedVersions[it.packageName].orEmpty(),
onCancel = vm::dismissNonSuggestedVersionDialog,
onContinue = vm::continueWithNonSuggestedVersion,
onDismiss = vm::dismissNonSuggestedVersionDialog
)
}

View File

@@ -20,6 +20,7 @@ import androidx.compose.material.icons.outlined.Restore
import androidx.compose.material.icons.outlined.Save
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -37,7 +38,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -48,17 +48,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.patcher.patch.Option
import app.revanced.manager.patcher.patch.PatchInfo
import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.Countdown
import app.revanced.manager.ui.component.DangerousActionDialogBase
import app.revanced.manager.ui.component.SafeguardDialog
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
import app.revanced.manager.ui.component.SearchView
import app.revanced.manager.ui.component.patches.OptionItem
@@ -70,7 +69,6 @@ import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.isScrollingUp
import kotlinx.coroutines.launch
import org.koin.compose.koinInject
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
@@ -160,10 +158,16 @@ fun PatchesSelectorScreen(
)
}
vm.pendingSelectionAction?.let {
SelectionWarningDialog(
onCancel = vm::dismissSelectionWarning,
onConfirm = vm::confirmSelectionWarning
var showSelectionWarning by rememberSaveable {
mutableStateOf(false)
}
if (showSelectionWarning) {
SelectionWarningDialog(onDismiss = { showSelectionWarning = false })
}
vm.pendingUniversalPatchAction?.let {
UniversalPatchWarningDialog(
onCancel = vm::dismissUniversalPatchWarning,
onConfirm = vm::confirmUniversalPatchWarning
)
}
@@ -196,9 +200,9 @@ fun PatchesSelectorScreen(
),
onToggle = {
if (vm.selectionWarningEnabled) {
vm.pendingSelectionAction = {
vm.togglePatch(uid, patch)
}
showSelectionWarning = true
} else if (vm.universalPatchWarningEnabled && patch.compatiblePackages == null) {
vm.pendingUniversalPatchAction = { vm.togglePatch(uid, patch) }
} else {
vm.togglePatch(uid, patch)
}
@@ -369,36 +373,43 @@ fun PatchesSelectorScreen(
}
@Composable
fun SelectionWarningDialog(
fun SelectionWarningDialog(onDismiss: () -> Unit) {
SafeguardDialog(
onDismiss = onDismiss,
title = R.string.warning,
body = stringResource(R.string.selection_warning_description),
)
}
@Composable
fun UniversalPatchWarningDialog(
onCancel: () -> Unit,
onConfirm: (Boolean) -> Unit
onConfirm: () -> Unit
) {
val prefs: PreferencesManager = koinInject()
DangerousActionDialogBase(
onCancel = onCancel,
confirmButton = { dismissPermanently ->
val enableCountdown by prefs.enableSelectionWarningCountdown.getAsState()
Countdown(start = if (enableCountdown) 3 else 0) { timer ->
LaunchedEffect(timer) {
if (timer == 0) prefs.enableSelectionWarningCountdown.update(false)
}
TextButton(
onClick = { onConfirm(dismissPermanently) },
enabled = timer == 0
) {
val text =
if (timer == 0) stringResource(R.string.continue_) else stringResource(
R.string.selection_warning_continue_countdown, timer
)
Text(text, color = MaterialTheme.colorScheme.error)
}
AlertDialog(
onDismissRequest = onCancel,
confirmButton = {
TextButton(onClick = onConfirm) {
Text(stringResource(R.string.continue_))
}
},
title = R.string.selection_warning_title,
body = stringResource(R.string.selection_warning_description),
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))
}
)
}

View File

@@ -69,8 +69,7 @@ fun VersionSelectorScreen(
if (viewModel.showNonSuggestedVersionDialog)
NonSuggestedVersionDialog(
suggestedVersion = viewModel.requiredVersion.orEmpty(),
onCancel = viewModel::dismissNonSuggestedVersionDialog,
onContinue = viewModel::continueWithNonSuggestedVersion,
onDismiss = viewModel::dismissNonSuggestedVersionDialog
)
val lazyListState = rememberLazyListState()

View File

@@ -126,12 +126,24 @@ fun AdvancedSettingsScreen(
headline = R.string.patch_compat_check,
description = R.string.patch_compat_check_description
)
BooleanItem(
preference = vm.prefs.disableUniversalPatchWarning,
coroutineScope = vm.viewModelScope,
headline = R.string.universal_patches_safeguard,
description = R.string.universal_patches_safeguard_description
)
BooleanItem(
preference = vm.prefs.suggestedVersionSafeguard,
coroutineScope = vm.viewModelScope,
headline = R.string.suggested_version_safeguard,
description = R.string.suggested_version_safeguard_description
)
BooleanItem(
preference = vm.prefs.disableSelectionWarning,
coroutineScope = vm.viewModelScope,
headline = R.string.patch_selection_safeguard,
description = R.string.patch_selection_safeguard_description
)
GroupHeader(stringResource(R.string.device))
SettingsListItem(

View File

@@ -3,14 +3,12 @@ package app.revanced.manager.ui.viewmodel
import android.app.Application
import android.content.pm.PackageInfo
import android.net.Uri
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.PatchBundleRepository
import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.util.PM
@@ -25,8 +23,7 @@ import java.nio.file.Files
class AppSelectorViewModel(
private val app: Application,
private val pm: PM,
private val patchBundleRepository: PatchBundleRepository,
private val prefs: PreferencesManager,
private val patchBundleRepository: PatchBundleRepository
) : ViewModel() {
private val inputFile = File(app.cacheDir, "input.apk").also {
it.delete()
@@ -46,13 +43,6 @@ class AppSelectorViewModel(
nonSuggestedVersionDialogSubject = null
}
fun continueWithNonSuggestedVersion(dismissPermanently: Boolean) = viewModelScope.launch {
if (dismissPermanently) prefs.suggestedVersionSafeguard.update(false)
nonSuggestedVersionDialogSubject?.let(onStorageClick)
dismissNonSuggestedVersionDialog()
}
fun handleStorageResult(uri: Uri) = viewModelScope.launch {
val selectedApp = withContext(Dispatchers.IO) {
loadSelectedFile(uri)

View File

@@ -47,10 +47,12 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
private val packageName = input.app.packageName
val appVersion = input.app.version
var pendingSelectionAction by mutableStateOf<(() -> Unit)?>(null)
var pendingUniversalPatchAction by mutableStateOf<(() -> Unit)?>(null)
var selectionWarningEnabled by mutableStateOf(true)
private set
var universalPatchWarningEnabled by mutableStateOf(true)
private set
val allowIncompatiblePatches =
get<PreferencesManager>().disablePatchVersionCompatCheck.getBlocking()
@@ -59,6 +61,8 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
init {
viewModelScope.launch {
universalPatchWarningEnabled = !prefs.disableUniversalPatchWarning.get()
if (prefs.disableSelectionWarning.get()) {
selectionWarningEnabled = false
return@launch
@@ -131,21 +135,15 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
customPatchSelection = selection.put(bundle, newPatches)
}
fun confirmSelectionWarning(dismissPermanently: Boolean) {
selectionWarningEnabled = false
fun confirmUniversalPatchWarning() {
universalPatchWarningEnabled = false
pendingSelectionAction?.invoke()
pendingSelectionAction = null
if (!dismissPermanently) return
viewModelScope.launch {
prefs.disableSelectionWarning.update(true)
}
pendingUniversalPatchAction?.invoke()
pendingUniversalPatchAction = null
}
fun dismissSelectionWarning() {
pendingSelectionAction = null
fun dismissUniversalPatchWarning() {
pendingUniversalPatchAction = null
}
fun reset() {

View File

@@ -162,12 +162,6 @@ class VersionSelectorViewModel(
nonSuggestedVersionDialogSubject = null
}
fun continueWithNonSuggestedVersion(dismissPermanently: Boolean) = viewModelScope.launch {
if (dismissPermanently) prefs.suggestedVersionSafeguard.update(false)
selectedVersion = nonSuggestedVersionDialogSubject
dismissNonSuggestedVersionDialog()
}
fun select(app: SelectedApp) {
if (requiredVersion != null && app.version != requiredVersion) {
nonSuggestedVersionDialogSubject = app