Show selected source in overview

This commit is contained in:
Robert
2026-01-07 20:51:39 +01:00
parent 08662b2132
commit 9fc2b4fdef
6 changed files with 90 additions and 119 deletions

View File

@@ -158,16 +158,15 @@ class PatcherWorker(
args.version,
prefs.suggestedVersionSafeguard.get(),
!prefs.disablePatchVersionCompatCheck.get(),
onDownload = { progress ->
args.onEvent(
ProgressEvent.Progress(
stepId = StepId.DownloadAPK,
current = progress.first,
total = progress.second
)
) { progress ->
args.onEvent(
ProgressEvent.Progress(
stepId = StepId.DownloadAPK,
current = progress.first,
total = progress.second
)
}
).also { args.setInputFile(it) }
)
}.also { args.setInputFile(it) }
val inputFile = when (val source = args.source) {
is SelectedSource.Auto -> throw Exception("Auto source is not supported in worker.")
@@ -212,6 +211,7 @@ class PatcherWorker(
}
is SelectedSource.Downloaded -> File(source.path)
is SelectedSource.Local -> File(source.path)
is SelectedSource.Installed -> File(pm.getPackageInfo(args.packageName)!!.applicationInfo!!.sourceDir)
}
@@ -251,10 +251,7 @@ class PatcherWorker(
Result.failure()
} finally {
patchedApk.delete()
// TODO
// if (args.source is SelectedApp.Local && args.source.temporary) {
// args.source.file.delete()
// }
if (args.source is SelectedSource.Local) File(args.source.path).delete()
}
}

View File

@@ -1,35 +0,0 @@
package app.revanced.manager.ui.model
import android.os.Parcelable
import app.revanced.manager.network.downloader.ParceledDownloaderData
import kotlinx.parcelize.Parcelize
import java.io.File
sealed interface SelectedApp : Parcelable {
val packageName: String
val version: String?
@Parcelize
data class Download(
override val packageName: String,
override val version: String?,
val data: ParceledDownloaderData
) : SelectedApp
@Parcelize
data class Search(override val packageName: String, override val version: String?) : SelectedApp
@Parcelize
data class Local(
override val packageName: String,
override val version: String,
val file: File,
val temporary: Boolean
) : SelectedApp
@Parcelize
data class Installed(
override val packageName: String,
override val version: String
) : SelectedApp
}

View File

@@ -8,5 +8,6 @@ sealed class SelectedSource : Parcelable {
data object Auto : SelectedSource()
data object Installed : SelectedSource()
data class Downloaded(val path: String, val version: String) : SelectedSource()
data class Local(val path: String) : SelectedSource()
data class Plugin(val packageName: String?) : SelectedSource()
}

View File

@@ -4,6 +4,7 @@ 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.ColumnScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
@@ -80,7 +81,6 @@ fun SelectedAppInfoScreen(
val incompatibleCount by vm.incompatiblePatchCount.collectAsStateWithLifecycle(0)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val plugins by vm.plugins.collectAsStateWithLifecycle(emptyList())
Scaffold(
topBar = {
@@ -150,18 +150,16 @@ fun SelectedAppInfoScreen(
customSelection,
vm.options
)
}
},
extraDescription = if (incompatibleCount > 0) { {
Text(
"$incompatibleCount incompatible",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
)
} } else null,
)
if (incompatibleCount > 0) {
Text(
"$incompatibleCount incompatible",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
val versionText = resolvedVersion ?: "Any available version"
val versionDescription = if (selectedVersion is SelectedVersion.Auto)
"Auto ($versionText)" // stringResource(R.string.selected_app_meta_auto_version, actualVersion)
@@ -179,19 +177,32 @@ fun SelectedAppInfoScreen(
},
)
val sourceText = when (val source = resolvedSource) {
is SelectedSource.Installed -> "Installed APK"
is SelectedSource.Downloaded -> "Downloaded APK"
is SelectedSource.Local -> "Local APK"
is SelectedSource.Plugin -> {
source.packageName ?: "Any available downloader"
}
else -> "Auto"
}
val sourceDescription = if (selectedSource is SelectedSource.Auto)
"Auto ($sourceText)" // stringResource(R.string.selected_app_meta_auto_version, actualVersion)
else sourceText
PageItem(
R.string.apk_source_selector_item,
selectedSource.toString(),
sourceDescription,
onClick = { onSourceClick(packageName, resolvedVersion, selectedSource) },
)
// error?.let {
// Text(
// stringResource(it.resourceId),
// color = MaterialTheme.colorScheme.error,
// modifier = Modifier.padding(horizontal = 16.dp)
// )
// }
error?.let {
Text(
stringResource(it.resourceId),
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
if (resolvedSource is SelectedSource.Plugin) Column(
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
@@ -225,7 +236,8 @@ private fun PageItem(
@StringRes title: Int,
description: String,
onClick: () -> Unit,
enabled: Boolean = true
enabled: Boolean = true,
extraDescription: @Composable (ColumnScope.() -> Unit)? = null,
) {
ListItem(
modifier = Modifier
@@ -239,11 +251,14 @@ private fun PageItem(
)
},
supportingContent = {
Text(
description,
color = MaterialTheme.colorScheme.outline,
style = MaterialTheme.typography.bodyMedium
)
Column {
Text(
description,
color = MaterialTheme.colorScheme.outline,
style = MaterialTheme.typography.bodyMedium
)
extraDescription?.invoke(this)
}
},
trailingContent = {
Icon(Icons.AutoMirrored.Outlined.ArrowRight, null)

View File

@@ -39,6 +39,9 @@ fun SourceSelectorScreen(
val downloadedApps by viewModel.downloadedApps.collectAsStateWithLifecycle(emptyList())
val plugins by viewModel.plugins.collectAsStateWithLifecycle(emptyList())
val version = viewModel.input.version
fun matchesVersion(appVersion: String) = version == null || version == appVersion
Scaffold(
topBar = {
AppTopBar(
@@ -82,7 +85,7 @@ fun SourceSelectorScreen(
onSelect = { viewModel.selectSource(SelectedSource.Installed) },
headlineContent = { Text(installedVersion) },
overlineContent = { Text("Installed") },
enabled = viewModel.input.version?.let { it == installedVersion } ?: true
enabled = matchesVersion(installedVersion)
)
}
}
@@ -95,6 +98,7 @@ fun SourceSelectorScreen(
onSelect = { viewModel.selectDownloadedApp(app) },
headlineContent = { Text(app.version) },
overlineContent = { Text("Downloaded") },
enabled = matchesVersion(app.version)
)
}

View File

@@ -15,6 +15,7 @@ import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable
import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.DownloadedAppRepository
import app.revanced.manager.domain.repository.DownloaderPluginRepository
import app.revanced.manager.domain.repository.InstalledAppRepository
import app.revanced.manager.domain.repository.PatchBundleRepository
@@ -49,13 +50,14 @@ import org.koin.core.component.get
@OptIn(SavedStateHandleSaveableApi::class, PluginHostApi::class)
class SelectedAppInfoViewModel(
val input: SelectedAppInfo.ViewModelParams
private val input: SelectedAppInfo.ViewModelParams
) : ViewModel(), KoinComponent {
private val bundleRepository: PatchBundleRepository = get()
private val selectionRepository: PatchSelectionRepository = get()
private val optionsRepository: PatchOptionsRepository = get()
private val pluginsRepository: DownloaderPluginRepository = get()
private val installedAppRepository: InstalledAppRepository = get()
private val downloadedAppRepository: DownloadedAppRepository = get()
private val pm: PM = get()
private val savedStateHandle: SavedStateHandle = get()
private val prefs: PreferencesManager = get()
@@ -101,16 +103,8 @@ class SelectedAppInfoViewModel(
}
// All patches for package
@OptIn(ExperimentalCoroutinesApi::class)
val bundles = _selectedVersion.flatMapLatest { selectedVersion ->
val version = if (selectedVersion is SelectedVersion.Specific)
selectedVersion.version
else null
bundleRepository.scopedBundleInfoFlow(packageName, version)
}
val bundles = bundleRepository.scopedBundleInfoFlow(packageName, null)
// Selection derived from selectionFlow
val patchSelection = combine(
@@ -163,20 +157,29 @@ class SelectedAppInfoViewModel(
}
// Resolve actual source from user selection
val resolvedSource = _selectedSource.map { source ->
// TODO
// when (source) {
// is SelectedSource.Auto -> null
// is SelectedSource.Installed -> null
// is SelectedSource.Downloaded -> null
// is SelectedSource.Plugin -> null
// }
val resolvedSource = combine(
_selectedSource,
resolvedVersion
) { source, version ->
when (source) {
is SelectedSource.Installed -> source
is SelectedSource.Local -> source
is SelectedSource.Downloaded -> source
is SelectedSource.Plugin -> source
is SelectedSource.Auto -> {
val app = version?.let {
downloadedAppRepository.get(packageName, it)
}
val file = app?.let {
downloadedAppRepository.getApkFileForApp(it)
}
source
file?.let { SelectedSource.Downloaded(it.path, version) }
?: SelectedSource.Plugin(null)
}
}
}
val bundleInfoFlow by derivedStateOf {
bundleRepository.scopedBundleInfoFlow(packageName, null)
}
@@ -197,6 +200,16 @@ class SelectedAppInfoViewModel(
private set
val errorFlow = combine(
plugins,
resolvedSource,
) { pluginsList, source ->
when {
source is SelectedSource.Plugin && pluginsList.isEmpty() -> Error.NoPlugins
else -> null
}
}
// var installedAppData: Pair<SelectedApp.Installed, InstalledApp?>? by mutableStateOf(null)
@@ -219,20 +232,6 @@ class SelectedAppInfoViewModel(
// TODO: Remove
private var oldSelectionState: SelectionState by savedStateHandle.saveable { mutableStateOf(SelectionState.Default) }
val errorFlow = combine(plugins, snapshotFlow { selectedApp }) { pluginsList, app ->
when {
// app is SelectedApp.Search && pluginsList.isEmpty() -> Error.NoPlugins
else -> null
}
}
// TODO: Load from local file or downloaded app
private fun invalidateSelectedAppInfo() = viewModelScope.launch {
selectedAppInfo = pm.getPackageInfo(packageName)
@@ -259,16 +258,6 @@ class SelectedAppInfoViewModel(
)
}
fun getPatches(bundles: List<PatchBundleInfo.Scoped>, allowIncompatible: Boolean) =
oldSelectionState.patches(bundles, allowIncompatible)
fun getCustomPatches(
bundles: List<PatchBundleInfo.Scoped>,
allowIncompatible: Boolean
): PatchSelection? =
(oldSelectionState as? SelectionState.Customized)?.patches(bundles, allowIncompatible)
init {
invalidateSelectedAppInfo()