refactor: fix terminology and wording related to patches (#1623)

This commit is contained in:
Ax333l 2024-01-18 20:50:24 +01:00 committed by GitHub
parent 36c8f59d6f
commit c0f3d02e6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 102 additions and 106 deletions

View File

@ -107,11 +107,11 @@ class MainActivity : ComponentActivity() {
) )
is Destination.InstalledApplicationInfo -> InstalledAppInfoScreen( is Destination.InstalledApplicationInfo -> InstalledAppInfoScreen(
onPatchClick = { packageName, patchesSelection -> onPatchClick = { packageName, patchSelection ->
navController.navigate( navController.navigate(
Destination.VersionSelector( Destination.VersionSelector(
packageName, packageName,
patchesSelection patchSelection
) )
) )
}, },
@ -142,14 +142,14 @@ class MainActivity : ComponentActivity() {
navController.navigate( navController.navigate(
Destination.SelectedApplicationInfo( Destination.SelectedApplicationInfo(
selectedApp, selectedApp,
destination.patchesSelection, destination.patchSelection,
) )
) )
}, },
viewModel = getComposeViewModel { viewModel = getComposeViewModel {
parametersOf( parametersOf(
destination.packageName, destination.packageName,
destination.patchesSelection destination.patchSelection
) )
} }
) )
@ -167,7 +167,7 @@ class MainActivity : ComponentActivity() {
parametersOf( parametersOf(
SelectedAppInfoViewModel.Params( SelectedAppInfoViewModel.Params(
destination.selectedApp, destination.selectedApp,
destination.patchesSelection destination.patchSelection
) )
) )
} }

View File

@ -4,7 +4,7 @@ import app.revanced.manager.data.room.AppDatabase
import app.revanced.manager.data.room.apps.installed.AppliedPatch import app.revanced.manager.data.room.apps.installed.AppliedPatch
import app.revanced.manager.data.room.apps.installed.InstallType import app.revanced.manager.data.room.apps.installed.InstallType
import app.revanced.manager.data.room.apps.installed.InstalledApp import app.revanced.manager.data.room.apps.installed.InstalledApp
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
class InstalledAppRepository( class InstalledAppRepository(
@ -16,7 +16,7 @@ class InstalledAppRepository(
suspend fun get(packageName: String) = dao.get(packageName) suspend fun get(packageName: String) = dao.get(packageName)
suspend fun getAppliedPatches(packageName: String): PatchesSelection = suspend fun getAppliedPatches(packageName: String): PatchSelection =
dao.getPatchesSelection(packageName).mapValues { (_, patches) -> patches.toSet() } dao.getPatchesSelection(packageName).mapValues { (_, patches) -> patches.toSet() }
suspend fun addOrUpdate( suspend fun addOrUpdate(
@ -24,7 +24,7 @@ class InstalledAppRepository(
originalPackageName: String, originalPackageName: String,
version: String, version: String,
installType: InstallType, installType: InstallType,
patchesSelection: PatchesSelection patchSelection: PatchSelection
) { ) {
dao.upsertApp( dao.upsertApp(
InstalledApp( InstalledApp(
@ -33,7 +33,7 @@ class InstalledAppRepository(
version = version, version = version,
installType = installType installType = installType
), ),
patchesSelection.flatMap { (uid, patches) -> patchSelection.flatMap { (uid, patches) ->
patches.map { patch -> patches.map { patch ->
AppliedPatch( AppliedPatch(
packageName = currentPackageName, packageName = currentPackageName,

View File

@ -33,7 +33,7 @@ import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.ui.model.State import app.revanced.manager.ui.model.State
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PM import app.revanced.manager.util.PM
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.tag import app.revanced.manager.util.tag
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -59,7 +59,7 @@ class PatcherWorker(
data class Args( data class Args(
val input: SelectedApp, val input: SelectedApp,
val output: String, val output: String,
val selectedPatches: PatchesSelection, val selectedPatches: PatchSelection,
val options: Options, val options: Options,
val logger: ManagerLogger, val logger: ManagerLogger,
val downloadProgress: MutableStateFlow<Pair<Float, Float>?>, val downloadProgress: MutableStateFlow<Pair<Float, Float>?>,

View File

@ -89,7 +89,7 @@ fun BundleItem(
supportingContent = { supportingContent = {
state.patchBundleOrNull()?.patches?.size?.let { patchCount -> state.patchBundleOrNull()?.patches?.size?.let { patchCount ->
Text( Text(
text = pluralStringResource(R.plurals.patches_count, patchCount, patchCount), text = pluralStringResource(R.plurals.patch_count, patchCount, patchCount),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
) )

View File

@ -4,7 +4,7 @@ import android.os.Parcelable
import app.revanced.manager.data.room.apps.installed.InstalledApp import app.revanced.manager.data.room.apps.installed.InstalledApp
import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.RawValue import kotlinx.parcelize.RawValue
@ -23,12 +23,12 @@ sealed interface Destination : Parcelable {
data class Settings(val startDestination: SettingsDestination = SettingsDestination.Settings) : Destination data class Settings(val startDestination: SettingsDestination = SettingsDestination.Settings) : Destination
@Parcelize @Parcelize
data class VersionSelector(val packageName: String, val patchesSelection: PatchesSelection? = null) : Destination data class VersionSelector(val packageName: String, val patchSelection: PatchSelection? = null) : Destination
@Parcelize @Parcelize
data class SelectedApplicationInfo(val selectedApp: SelectedApp, val patchesSelection: PatchesSelection? = null) : Destination data class SelectedApplicationInfo(val selectedApp: SelectedApp, val patchSelection: PatchSelection? = null) : Destination
@Parcelize @Parcelize
data class Patcher(val selectedApp: SelectedApp, val selectedPatches: PatchesSelection, val options: @RawValue Options) : Destination data class Patcher(val selectedApp: SelectedApp, val selectedPatches: PatchSelection, val options: @RawValue Options) : Destination
} }

View File

@ -3,7 +3,7 @@ package app.revanced.manager.ui.destination
import android.os.Parcelable import android.os.Parcelable
import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.RawValue import kotlinx.parcelize.RawValue
@ -12,7 +12,7 @@ sealed interface SelectedAppInfoDestination : Parcelable {
data object Main : SelectedAppInfoDestination data object Main : SelectedAppInfoDestination
@Parcelize @Parcelize
data class PatchesSelector(val app: SelectedApp, val currentSelection: PatchesSelection?, val options: @RawValue Options) : SelectedAppInfoDestination data class PatchesSelector(val app: SelectedApp, val currentSelection: PatchSelection?, val options: @RawValue Options) : SelectedAppInfoDestination
@Parcelize @Parcelize
data object VersionSelector: SelectedAppInfoDestination data object VersionSelector: SelectedAppInfoDestination

View File

@ -2,7 +2,7 @@ package app.revanced.manager.ui.model
import app.revanced.manager.domain.repository.PatchBundleRepository import app.revanced.manager.domain.repository.PatchBundleRepository
import app.revanced.manager.patcher.patch.PatchInfo import app.revanced.manager.patcher.patch.PatchInfo
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.flatMapLatestAndCombine import app.revanced.manager.util.flatMapLatestAndCombine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -34,7 +34,7 @@ data class BundleInfo(
} }
companion object Extensions { companion object Extensions {
inline fun Iterable<BundleInfo>.toPatchSelection(allowUnsupported: Boolean, condition: (Int, PatchInfo) -> Boolean): PatchesSelection = this.associate { bundle -> inline fun Iterable<BundleInfo>.toPatchSelection(allowUnsupported: Boolean, condition: (Int, PatchInfo) -> Boolean): PatchSelection = this.associate { bundle ->
val patches = val patches =
bundle.patchSequence(allowUnsupported) bundle.patchSequence(allowUnsupported)
.mapNotNullTo(mutableSetOf()) { patch -> .mapNotNullTo(mutableSetOf()) { patch ->

View File

@ -111,7 +111,7 @@ fun AppSelectorScreen(
{ {
Text( Text(
pluralStringResource( pluralStringResource(
R.plurals.patches_count, R.plurals.patch_count,
it, it,
it it
) )
@ -199,7 +199,7 @@ fun AppSelectorScreen(
{ {
Text( Text(
pluralStringResource( pluralStringResource(
R.plurals.patches_count, R.plurals.patch_count,
it, it,
it it
) )

View File

@ -29,6 +29,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -40,15 +41,18 @@ import app.revanced.manager.ui.component.ColumnWithScrollbar
import app.revanced.manager.ui.component.SegmentedButton import app.revanced.manager.ui.component.SegmentedButton
import app.revanced.manager.ui.component.settings.SettingsListItem import app.revanced.manager.ui.component.settings.SettingsListItem
import app.revanced.manager.ui.viewmodel.InstalledAppInfoViewModel import app.revanced.manager.ui.viewmodel.InstalledAppInfoViewModel
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.toast
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun InstalledAppInfoScreen( fun InstalledAppInfoScreen(
onPatchClick: (packageName: String, patchesSelection: PatchesSelection) -> Unit, onPatchClick: (packageName: String, patchSelection: PatchSelection) -> Unit,
onBackClick: () -> Unit, onBackClick: () -> Unit,
viewModel: InstalledAppInfoViewModel viewModel: InstalledAppInfoViewModel
) { ) {
val context = LocalContext.current
SideEffect { SideEffect {
viewModel.onBackClick = onBackClick viewModel.onBackClick = onBackClick
} }
@ -142,12 +146,12 @@ fun InstalledAppInfoScreen(
modifier = Modifier.padding(vertical = 16.dp) modifier = Modifier.padding(vertical = 16.dp)
) { ) {
SettingsListItem( SettingsListItem(
modifier = Modifier.clickable { }, modifier = Modifier.clickable { context.toast("Not implemented yet!") },
headlineContent = stringResource(R.string.applied_patches), headlineContent = stringResource(R.string.applied_patches),
supportingContent = supportingContent =
(viewModel.appliedPatches?.values?.sumOf { it.size } ?: 0).let { (viewModel.appliedPatches?.values?.sumOf { it.size } ?: 0).let {
pluralStringResource( pluralStringResource(
id = R.plurals.applied_patches, id = R.plurals.patch_count,
it, it,
it it
) )

View File

@ -68,14 +68,14 @@ import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNIVERSAL import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNIVERSAL
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNSUPPORTED import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNSUPPORTED
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.compose.rememberKoinInject import org.koin.compose.rememberKoinInject
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable @Composable
fun PatchesSelectorScreen( fun PatchesSelectorScreen(
onSave: (PatchesSelection?, Options) -> Unit, onSave: (PatchSelection?, Options) -> Unit,
onBackClick: () -> Unit, onBackClick: () -> Unit,
vm: PatchesSelectorViewModel vm: PatchesSelectorViewModel
) { ) {
@ -105,13 +105,13 @@ fun PatchesSelectorScreen(
modifier = Modifier.padding(horizontal = 24.dp) modifier = Modifier.padding(horizontal = 24.dp)
) { ) {
Text( Text(
text = stringResource(R.string.patches_selector_sheet_filter_title), text = stringResource(R.string.patch_selector_sheet_filter_title),
style = MaterialTheme.typography.headlineSmall, style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.padding(bottom = 16.dp) modifier = Modifier.padding(bottom = 16.dp)
) )
Text( Text(
text = stringResource(R.string.patches_selector_sheet_filter_compat_title), text = stringResource(R.string.patch_selector_sheet_filter_compat_title),
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
) )

View File

@ -32,7 +32,7 @@ import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel
import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.toast import app.revanced.manager.util.toast
import dev.olshevski.navigation.reimagined.AnimatedNavHost import dev.olshevski.navigation.reimagined.AnimatedNavHost
import dev.olshevski.navigation.reimagined.NavBackHandler import dev.olshevski.navigation.reimagined.NavBackHandler
@ -44,7 +44,7 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
fun SelectedAppInfoScreen( fun SelectedAppInfoScreen(
onPatchClick: (SelectedApp, PatchesSelection, Options) -> Unit, onPatchClick: (SelectedApp, PatchSelection, Options) -> Unit,
onBackClick: () -> Unit, onBackClick: () -> Unit,
vm: SelectedAppInfoViewModel vm: SelectedAppInfoViewModel
) { ) {

View File

@ -159,7 +159,7 @@ fun SelectedAppItem(
else -> null else -> null
}, },
trailingContent = patchCount?.let { { trailingContent = patchCount?.let { {
Text(pluralStringResource(R.plurals.patches_count, it, it)) Text(pluralStringResource(R.plurals.patch_count, it, it))
} }, } },
modifier = Modifier modifier = Modifier
.clickable(enabled = !alreadyPatched && enabled, onClick = onClick) .clickable(enabled = !alreadyPatched && enabled, onClick = onClick)

View File

@ -131,22 +131,22 @@ fun ImportExportSettingsScreen(
description = R.string.regenerate_keystore_description description = R.string.regenerate_keystore_description
) )
GroupHeader(stringResource(R.string.patches_selection)) GroupHeader(stringResource(R.string.patches))
GroupItem( GroupItem(
onClick = vm::importSelection, onClick = vm::importSelection,
headline = R.string.restore_patches_selection, headline = R.string.import_patch_selection,
description = R.string.restore_patches_selection_description description = R.string.import_patch_selection_description
) )
GroupItem( GroupItem(
onClick = vm::exportSelection, onClick = vm::exportSelection,
headline = R.string.backup_patches_selection, headline = R.string.export_patch_selection,
description = R.string.backup_patches_selection_description description = R.string.export_patch_selection_description
) )
// TODO: allow resetting selection for specific bundle or package name. // TODO: allow resetting selection for specific bundle or package name.
GroupItem( GroupItem(
onClick = vm::resetSelection, onClick = vm::resetSelection,
headline = R.string.clear_patches_selection, headline = R.string.reset_patch_selection,
description = R.string.clear_patches_selection_description description = R.string.reset_patch_selection_description
) )
var showPackageSelector by rememberSaveable { var showPackageSelector by rememberSaveable {
@ -158,7 +158,7 @@ fun ImportExportSettingsScreen(
if (showPackageSelector) if (showPackageSelector)
PackageSelector(packages = packagesWithOptions) { selected -> PackageSelector(packages = packagesWithOptions) { selected ->
selected?.let(vm::clearOptionsForPackage) selected?.let(vm::resetOptionsForPackage)
showPackageSelector = false showPackageSelector = false
} }
@ -170,23 +170,22 @@ fun ImportExportSettingsScreen(
showBundleSelector = false showBundleSelector = false
} }
GroupHeader(stringResource(R.string.patch_options))
// TODO: patch options import/export. // TODO: patch options import/export.
GroupItem(
onClick = vm::resetOptions,
headline = R.string.patch_options_reset_all,
description = R.string.patch_options_reset_all_description,
)
GroupItem( GroupItem(
onClick = { showPackageSelector = true }, onClick = { showPackageSelector = true },
headline = R.string.patch_options_clear_package, headline = R.string.patch_options_reset_package,
description = R.string.patch_options_clear_package_description description = R.string.patch_options_reset_package_description
) )
if (patchBundles.size > 1) if (patchBundles.size > 1)
GroupItem( GroupItem(
onClick = { showBundleSelector = true }, onClick = { showBundleSelector = true },
headline = R.string.patch_options_clear_bundle, headline = R.string.patch_options_reset_bundle,
description = R.string.patch_options_clear_bundle_description, description = R.string.patch_options_reset_bundle_description,
)
GroupItem(
onClick = vm::resetOptions,
headline = R.string.patch_options_clear_all,
description = R.string.patch_options_clear_all_description,
) )
} }
} }

View File

@ -53,7 +53,7 @@ class ImportExportViewModel(
val packagesWithOptions = optionsRepository.getPackagesWithSavedOptions() val packagesWithOptions = optionsRepository.getPackagesWithSavedOptions()
fun clearOptionsForPackage(packageName: String) = viewModelScope.launch { fun resetOptionsForPackage(packageName: String) = viewModelScope.launch {
optionsRepository.clearOptionsForPackage(packageName) optionsRepository.clearOptionsForPackage(packageName)
} }
@ -163,8 +163,8 @@ class ImportExportViewModel(
override val activityArg = JSON_MIMETYPE override val activityArg = JSON_MIMETYPE
override suspend fun execute(bundleUid: Int, location: Uri) = uiSafe( override suspend fun execute(bundleUid: Int, location: Uri) = uiSafe(
app, app,
R.string.restore_patches_selection_fail, R.string.import_patch_selection_fail,
"Failed to restore patches selection" "Failed to restore patch selection"
) { ) {
val selection = withContext(Dispatchers.IO) { val selection = withContext(Dispatchers.IO) {
contentResolver.openInputStream(location)!!.use { contentResolver.openInputStream(location)!!.use {
@ -181,8 +181,8 @@ class ImportExportViewModel(
override val activityArg = "selection.json" override val activityArg = "selection.json"
override suspend fun execute(bundleUid: Int, location: Uri) = uiSafe( override suspend fun execute(bundleUid: Int, location: Uri) = uiSafe(
app, app,
R.string.backup_patches_selection_fail, R.string.export_patch_selection_fail,
"Failed to backup patches selection" "Failed to backup patch selection"
) { ) {
val selection = selectionRepository.export(bundleUid) val selection = selectionRepository.export(bundleUid)

View File

@ -21,7 +21,7 @@ import app.revanced.manager.domain.installer.RootInstaller
import app.revanced.manager.domain.repository.InstalledAppRepository import app.revanced.manager.domain.repository.InstalledAppRepository
import app.revanced.manager.service.UninstallService import app.revanced.manager.service.UninstallService
import app.revanced.manager.util.PM import app.revanced.manager.util.PM
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.simpleMessage import app.revanced.manager.util.simpleMessage
import app.revanced.manager.util.tag import app.revanced.manager.util.tag
import app.revanced.manager.util.toast import app.revanced.manager.util.toast
@ -43,7 +43,7 @@ class InstalledAppInfoViewModel(
var appInfo: PackageInfo? by mutableStateOf(null) var appInfo: PackageInfo? by mutableStateOf(null)
private set private set
var appliedPatches: PatchesSelection? by mutableStateOf(null) var appliedPatches: PatchSelection? by mutableStateOf(null)
var isMounted by mutableStateOf(rootInstaller.isAppMounted(installedApp.currentPackageName)) var isMounted by mutableStateOf(rootInstaller.isAppMounted(installedApp.currentPackageName))
private set private set

View File

@ -24,7 +24,7 @@ import app.revanced.manager.ui.model.BundleInfo.Extensions.bundleInfoFlow
import app.revanced.manager.ui.model.BundleInfo.Extensions.toPatchSelection import app.revanced.manager.ui.model.BundleInfo.Extensions.toPatchSelection
import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.saver.Nullable import app.revanced.manager.util.saver.Nullable
import app.revanced.manager.util.saver.nullableSaver import app.revanced.manager.util.saver.nullableSaver
import app.revanced.manager.util.saver.persistentMapSaver import app.revanced.manager.util.saver.persistentMapSaver
@ -36,7 +36,6 @@ import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.get import org.koin.core.component.get
import kotlinx.collections.immutable.* import kotlinx.collections.immutable.*
import java.util.Optional
@Stable @Stable
@OptIn(SavedStateHandleSaveableApi::class) @OptIn(SavedStateHandleSaveableApi::class)
@ -72,11 +71,11 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
} }
private var hasModifiedSelection = false private var hasModifiedSelection = false
private var customPatchesSelection: PersistentPatchesSelection? by savedStateHandle.saveable( private var customPatchSelection: PersistentPatchSelection? by savedStateHandle.saveable(
key = "selection", key = "selection",
stateSaver = patchesSaver, stateSaver = selectionSaver,
) { ) {
mutableStateOf(input.currentSelection?.toPersistentPatchesSelection()) mutableStateOf(input.currentSelection?.toPersistentPatchSelection())
} }
private val patchOptions: PersistentOptions by savedStateHandle.saveable( private val patchOptions: PersistentOptions by savedStateHandle.saveable(
@ -98,12 +97,12 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
var filter by mutableIntStateOf(SHOW_SUPPORTED or SHOW_UNIVERSAL or SHOW_UNSUPPORTED) var filter by mutableIntStateOf(SHOW_SUPPORTED or SHOW_UNIVERSAL or SHOW_UNSUPPORTED)
private set private set
private suspend fun generateDefaultSelection(): PersistentPatchesSelection { private suspend fun generateDefaultSelection(): PersistentPatchSelection {
val bundles = bundlesFlow.first() val bundles = bundlesFlow.first()
val generatedSelection = val generatedSelection =
bundles.toPatchSelection(allowExperimental) { _, patch -> patch.include } bundles.toPatchSelection(allowExperimental) { _, patch -> patch.include }
return generatedSelection.toPersistentPatchesSelection() return generatedSelection.toPersistentPatchSelection()
} }
fun selectionIsValid(bundles: List<BundleInfo>) = bundles.any { bundle -> fun selectionIsValid(bundles: List<BundleInfo>) = bundles.any { bundle ->
@ -112,14 +111,14 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
} }
} }
fun isSelected(bundle: Int, patch: PatchInfo) = customPatchesSelection?.let { selection -> fun isSelected(bundle: Int, patch: PatchInfo) = customPatchSelection?.let { selection ->
selection[bundle]?.contains(patch.name) ?: false selection[bundle]?.contains(patch.name) ?: false
} ?: patch.include } ?: patch.include
fun togglePatch(bundle: Int, patch: PatchInfo) = viewModelScope.launch { fun togglePatch(bundle: Int, patch: PatchInfo) = viewModelScope.launch {
hasModifiedSelection = true hasModifiedSelection = true
val selection = customPatchesSelection ?: generateDefaultSelection() val selection = customPatchSelection ?: generateDefaultSelection()
val newPatches = selection[bundle]?.let { patches -> val newPatches = selection[bundle]?.let { patches ->
if (patch.name in patches) if (patch.name in patches)
patches.remove(patch.name) patches.remove(patch.name)
@ -127,7 +126,7 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
patches.add(patch.name) patches.add(patch.name)
} ?: persistentSetOf(patch.name) } ?: persistentSetOf(patch.name)
customPatchesSelection = selection.put(bundle, newPatches) customPatchSelection = selection.put(bundle, newPatches)
} }
fun confirmSelectionWarning(dismissPermanently: Boolean) { fun confirmSelectionWarning(dismissPermanently: Boolean) {
@ -149,15 +148,15 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
fun reset() { fun reset() {
patchOptions.clear() patchOptions.clear()
customPatchesSelection = null customPatchSelection = null
hasModifiedSelection = false hasModifiedSelection = false
app.toast(app.getString(R.string.patch_selection_reset_toast)) app.toast(app.getString(R.string.patch_selection_reset_toast))
} }
fun getCustomSelection(): PatchesSelection? { fun getCustomSelection(): PatchSelection? {
// Convert persistent collections to standard hash collections because persistent collections are not parcelable. // Convert persistent collections to standard hash collections because persistent collections are not parcelable.
return customPatchesSelection?.mapValues { (_, v) -> v.toSet() } return customPatchSelection?.mapValues { (_, v) -> v.toSet() }
} }
fun getOptions(): Options { fun getOptions(): Options {
@ -211,20 +210,20 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
) )
) )
private val patchesSaver: Saver<PersistentPatchesSelection?, Nullable<PatchesSelection>> = private val selectionSaver: Saver<PersistentPatchSelection?, Nullable<PatchSelection>> =
nullableSaver(persistentMapSaver(valueSaver = persistentSetSaver())) nullableSaver(persistentMapSaver(valueSaver = persistentSetSaver()))
} }
data class Params( data class Params(
val app: SelectedApp, val app: SelectedApp,
val currentSelection: PatchesSelection?, val currentSelection: PatchSelection?,
val options: Options, val options: Options,
) )
} }
// Versions of other types, but utilizing persistent/observable collection types. // Versions of other types, but utilizing persistent/observable collection types.
private typealias PersistentOptions = SnapshotStateMap<Int, PersistentMap<String, PersistentMap<String, Any?>>> private typealias PersistentOptions = SnapshotStateMap<Int, PersistentMap<String, PersistentMap<String, Any?>>>
private typealias PersistentPatchesSelection = PersistentMap<Int, PersistentSet<String>> private typealias PersistentPatchSelection = PersistentMap<Int, PersistentSet<String>>
private fun PatchesSelection.toPersistentPatchesSelection(): PersistentPatchesSelection = private fun PatchSelection.toPersistentPatchSelection(): PersistentPatchSelection =
mapValues { (_, v) -> v.toPersistentSet() }.toPersistentMap() mapValues { (_, v) -> v.toPersistentSet() }.toPersistentMap()

View File

@ -20,7 +20,7 @@ import app.revanced.manager.ui.model.BundleInfo.Extensions.toPatchSelection
import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.util.Options import app.revanced.manager.util.Options
import app.revanced.manager.util.PM import app.revanced.manager.util.PM
import app.revanced.manager.util.PatchesSelection import app.revanced.manager.util.PatchSelection
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -109,11 +109,11 @@ class SelectedAppInfoViewModel(input: Params) : ViewModel(), KoinComponent {
fun getCustomPatches( fun getCustomPatches(
bundles: List<BundleInfo>, bundles: List<BundleInfo>,
allowUnsupported: Boolean allowUnsupported: Boolean
): PatchesSelection? = ): PatchSelection? =
(selectionState as? SelectionState.Customized)?.patches(bundles, allowUnsupported) (selectionState as? SelectionState.Customized)?.patches(bundles, allowUnsupported)
fun updateConfiguration( fun updateConfiguration(
selection: PatchesSelection?, selection: PatchSelection?,
options: Options, options: Options,
bundles: List<BundleInfo> bundles: List<BundleInfo>
) { ) {
@ -135,7 +135,7 @@ class SelectedAppInfoViewModel(input: Params) : ViewModel(), KoinComponent {
data class Params( data class Params(
val app: SelectedApp, val app: SelectedApp,
val patches: PatchesSelection?, val patches: PatchSelection?,
) )
private companion object { private companion object {
@ -165,15 +165,15 @@ class SelectedAppInfoViewModel(input: Params) : ViewModel(), KoinComponent {
} }
private sealed interface SelectionState : Parcelable { private sealed interface SelectionState : Parcelable {
fun patches(bundles: List<BundleInfo>, allowUnsupported: Boolean): PatchesSelection fun patches(bundles: List<BundleInfo>, allowUnsupported: Boolean): PatchSelection
@Parcelize @Parcelize
data class Customized(val patchesSelection: PatchesSelection) : SelectionState { data class Customized(val patchSelection: PatchSelection) : SelectionState {
override fun patches(bundles: List<BundleInfo>, allowUnsupported: Boolean) = override fun patches(bundles: List<BundleInfo>, allowUnsupported: Boolean) =
bundles.toPatchSelection( bundles.toPatchSelection(
allowUnsupported allowUnsupported
) { uid, patch -> ) { uid, patch ->
patchesSelection[uid]?.contains(patch.name) ?: false patchSelection[uid]?.contains(patch.name) ?: false
} }
} }

View File

@ -34,7 +34,7 @@ import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException import java.time.format.DateTimeParseException
import java.util.Locale import java.util.Locale
typealias PatchesSelection = Map<Int, Set<String>> typealias PatchSelection = Map<Int, Set<String>>
typealias Options = Map<Int, Map<String, Map<String, Any?>>> typealias Options = Map<Int, Map<String, Map<String, Any?>>>
val Context.isDebuggable get() = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE val Context.isDebuggable get() = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE

View File

@ -1,13 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<plurals name="patches_count"> <plurals name="patch_count">
<item quantity="one">%d patch</item> <item quantity="one">%d patch</item>
<item quantity="other">%d patches</item> <item quantity="other">%d patches</item>
</plurals> </plurals>
<plurals name="applied_patches">
<item quantity="one">%d applied patch</item>
<item quantity="other">%d applied patches</item>
</plurals>
<plurals name="patches_applied"> <plurals name="patches_applied">
<item quantity="one">Applied %d patch</item> <item quantity="one">Applied %d patch</item>
<item quantity="other">Applied %d patches</item> <item quantity="other">Applied %d patches</item>

View File

@ -83,22 +83,20 @@
<string name="regenerate_keystore">Regenerate keystore</string> <string name="regenerate_keystore">Regenerate keystore</string>
<string name="regenerate_keystore_description">Generate a new keystore</string> <string name="regenerate_keystore_description">Generate a new keystore</string>
<string name="regenerate_keystore_success">The keystore has been successfully replaced</string> <string name="regenerate_keystore_success">The keystore has been successfully replaced</string>
<string name="patches_selection">Patches selection</string> <string name="import_patch_selection">Import patch selection</string>
<string name="restore_patches_selection">Restore patches selections</string> <string name="import_patch_selection_description">Import patch selection from a JSON file</string>
<string name="restore_patches_selection_description">Restore patches selection from a file</string> <string name="import_patch_selection_fail">Could not import patch selection: %s</string>
<string name="restore_patches_selection_fail">Failed to restore patches selection: %s</string> <string name="export_patch_selection">Export patch selection</string>
<string name="backup_patches_selection">Backup patches selections</string> <string name="export_patch_selection_description">Export patch selection from a JSON file</string>
<string name="backup_patches_selection_description">Backup patches selection to a file</string> <string name="export_patch_selection_fail">Could not export patch selection: %s</string>
<string name="backup_patches_selection_fail">Failed to backup patches selection: %s</string> <string name="reset_patch_selection">Reset patch selection</string>
<string name="clear_patches_selection">Clear patches selection</string> <string name="reset_patch_selection_description">Reset the stored patch selection</string>
<string name="clear_patches_selection_description">Clear all patches selection</string> <string name="patch_options_reset_package">Reset patch options for app</string>
<string name="patch_options">Patch options</string> <string name="patch_options_reset_package_description">Resets patch options for a single app</string>
<string name="patch_options_clear_package">Clear patch options for package</string> <string name="patch_options_reset_bundle">Resets patch options for bundle</string>
<string name="patch_options_clear_package_description">Resets patch options for a single package</string> <string name="patch_options_reset_bundle_description">Resets patch options for all patches in a bundle</string>
<string name="patch_options_clear_bundle">Clear patch options for bundle</string> <string name="patch_options_reset_all">Reset patch options</string>
<string name="patch_options_clear_bundle_description">Resets patch options for all patches in a bundle</string> <string name="patch_options_reset_all_description">Resets all patch options</string>
<string name="patch_options_clear_all">Clear all patch options</string>
<string name="patch_options_clear_all_description">Resets all patch options</string>
<string name="prefer_splits">Prefer split APK\'s</string> <string name="prefer_splits">Prefer split APK\'s</string>
<string name="prefer_splits_description">Prefer split APK\'s instead of full APK\'s</string> <string name="prefer_splits_description">Prefer split APK\'s instead of full APK\'s</string>
<string name="prefer_universal">Prefer universal APK\'s</string> <string name="prefer_universal">Prefer universal APK\'s</string>
@ -211,8 +209,8 @@
<string name="downloadable_versions">Downloadable versions</string> <string name="downloadable_versions">Downloadable versions</string>
<string name="already_patched">Already patched</string> <string name="already_patched">Already patched</string>
<string name="patches_selector_sheet_filter_title">Filter</string> <string name="patch_selector_sheet_filter_title">Filter</string>
<string name="patches_selector_sheet_filter_compat_title">Compatibility</string> <string name="patch_selector_sheet_filter_compat_title">Compatibility</string>
<string name="string_option_icon_description">Edit</string> <string name="string_option_icon_description">Edit</string>
<string name="string_option_menu_description">More options</string> <string name="string_option_menu_description">More options</string>