mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-11 05:36:17 +00:00
Show selected source in overview
This commit is contained in:
@@ -158,16 +158,15 @@ class PatcherWorker(
|
|||||||
args.version,
|
args.version,
|
||||||
prefs.suggestedVersionSafeguard.get(),
|
prefs.suggestedVersionSafeguard.get(),
|
||||||
!prefs.disablePatchVersionCompatCheck.get(),
|
!prefs.disablePatchVersionCompatCheck.get(),
|
||||||
onDownload = { progress ->
|
) { progress ->
|
||||||
args.onEvent(
|
args.onEvent(
|
||||||
ProgressEvent.Progress(
|
ProgressEvent.Progress(
|
||||||
stepId = StepId.DownloadAPK,
|
stepId = StepId.DownloadAPK,
|
||||||
current = progress.first,
|
current = progress.first,
|
||||||
total = progress.second
|
total = progress.second
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
).also { args.setInputFile(it) }
|
}.also { args.setInputFile(it) }
|
||||||
|
|
||||||
val inputFile = when (val source = args.source) {
|
val inputFile = when (val source = args.source) {
|
||||||
is SelectedSource.Auto -> throw Exception("Auto source is not supported in worker.")
|
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.Downloaded -> File(source.path)
|
||||||
|
is SelectedSource.Local -> File(source.path)
|
||||||
|
|
||||||
is SelectedSource.Installed -> File(pm.getPackageInfo(args.packageName)!!.applicationInfo!!.sourceDir)
|
is SelectedSource.Installed -> File(pm.getPackageInfo(args.packageName)!!.applicationInfo!!.sourceDir)
|
||||||
}
|
}
|
||||||
@@ -251,10 +251,7 @@ class PatcherWorker(
|
|||||||
Result.failure()
|
Result.failure()
|
||||||
} finally {
|
} finally {
|
||||||
patchedApk.delete()
|
patchedApk.delete()
|
||||||
// TODO
|
if (args.source is SelectedSource.Local) File(args.source.path).delete()
|
||||||
// if (args.source is SelectedApp.Local && args.source.temporary) {
|
|
||||||
// args.source.file.delete()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -8,5 +8,6 @@ sealed class SelectedSource : Parcelable {
|
|||||||
data object Auto : SelectedSource()
|
data object Auto : SelectedSource()
|
||||||
data object Installed : SelectedSource()
|
data object Installed : SelectedSource()
|
||||||
data class Downloaded(val path: String, val version: String) : 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()
|
data class Plugin(val packageName: String?) : SelectedSource()
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -80,7 +81,6 @@ fun SelectedAppInfoScreen(
|
|||||||
val incompatibleCount by vm.incompatiblePatchCount.collectAsStateWithLifecycle(0)
|
val incompatibleCount by vm.incompatiblePatchCount.collectAsStateWithLifecycle(0)
|
||||||
|
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
val plugins by vm.plugins.collectAsStateWithLifecycle(emptyList())
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -150,18 +150,16 @@ fun SelectedAppInfoScreen(
|
|||||||
customSelection,
|
customSelection,
|
||||||
vm.options
|
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 versionText = resolvedVersion ?: "Any available version"
|
||||||
val versionDescription = if (selectedVersion is SelectedVersion.Auto)
|
val versionDescription = if (selectedVersion is SelectedVersion.Auto)
|
||||||
"Auto ($versionText)" // stringResource(R.string.selected_app_meta_auto_version, actualVersion)
|
"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(
|
PageItem(
|
||||||
R.string.apk_source_selector_item,
|
R.string.apk_source_selector_item,
|
||||||
selectedSource.toString(),
|
sourceDescription,
|
||||||
onClick = { onSourceClick(packageName, resolvedVersion, selectedSource) },
|
onClick = { onSourceClick(packageName, resolvedVersion, selectedSource) },
|
||||||
)
|
)
|
||||||
|
|
||||||
// error?.let {
|
error?.let {
|
||||||
// Text(
|
Text(
|
||||||
// stringResource(it.resourceId),
|
stringResource(it.resourceId),
|
||||||
// color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
// modifier = Modifier.padding(horizontal = 16.dp)
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (resolvedSource is SelectedSource.Plugin) Column(
|
if (resolvedSource is SelectedSource.Plugin) Column(
|
||||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
|
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
|
||||||
@@ -225,7 +236,8 @@ private fun PageItem(
|
|||||||
@StringRes title: Int,
|
@StringRes title: Int,
|
||||||
description: String,
|
description: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
enabled: Boolean = true
|
enabled: Boolean = true,
|
||||||
|
extraDescription: @Composable (ColumnScope.() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -239,11 +251,14 @@ private fun PageItem(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
supportingContent = {
|
supportingContent = {
|
||||||
Text(
|
Column {
|
||||||
description,
|
Text(
|
||||||
color = MaterialTheme.colorScheme.outline,
|
description,
|
||||||
style = MaterialTheme.typography.bodyMedium
|
color = MaterialTheme.colorScheme.outline,
|
||||||
)
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
extraDescription?.invoke(this)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
Icon(Icons.AutoMirrored.Outlined.ArrowRight, null)
|
Icon(Icons.AutoMirrored.Outlined.ArrowRight, null)
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ fun SourceSelectorScreen(
|
|||||||
val downloadedApps by viewModel.downloadedApps.collectAsStateWithLifecycle(emptyList())
|
val downloadedApps by viewModel.downloadedApps.collectAsStateWithLifecycle(emptyList())
|
||||||
val plugins by viewModel.plugins.collectAsStateWithLifecycle(emptyList())
|
val plugins by viewModel.plugins.collectAsStateWithLifecycle(emptyList())
|
||||||
|
|
||||||
|
val version = viewModel.input.version
|
||||||
|
fun matchesVersion(appVersion: String) = version == null || version == appVersion
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
AppTopBar(
|
AppTopBar(
|
||||||
@@ -82,7 +85,7 @@ fun SourceSelectorScreen(
|
|||||||
onSelect = { viewModel.selectSource(SelectedSource.Installed) },
|
onSelect = { viewModel.selectSource(SelectedSource.Installed) },
|
||||||
headlineContent = { Text(installedVersion) },
|
headlineContent = { Text(installedVersion) },
|
||||||
overlineContent = { Text("Installed") },
|
overlineContent = { Text("Installed") },
|
||||||
enabled = viewModel.input.version?.let { it == installedVersion } ?: true
|
enabled = matchesVersion(installedVersion)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,6 +98,7 @@ fun SourceSelectorScreen(
|
|||||||
onSelect = { viewModel.selectDownloadedApp(app) },
|
onSelect = { viewModel.selectDownloadedApp(app) },
|
||||||
headlineContent = { Text(app.version) },
|
headlineContent = { Text(app.version) },
|
||||||
overlineContent = { Text("Downloaded") },
|
overlineContent = { Text("Downloaded") },
|
||||||
|
enabled = matchesVersion(app.version)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
|
|||||||
import androidx.lifecycle.viewmodel.compose.saveable
|
import androidx.lifecycle.viewmodel.compose.saveable
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
import app.revanced.manager.domain.manager.PreferencesManager
|
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.DownloaderPluginRepository
|
||||||
import app.revanced.manager.domain.repository.InstalledAppRepository
|
import app.revanced.manager.domain.repository.InstalledAppRepository
|
||||||
import app.revanced.manager.domain.repository.PatchBundleRepository
|
import app.revanced.manager.domain.repository.PatchBundleRepository
|
||||||
@@ -49,13 +50,14 @@ import org.koin.core.component.get
|
|||||||
|
|
||||||
@OptIn(SavedStateHandleSaveableApi::class, PluginHostApi::class)
|
@OptIn(SavedStateHandleSaveableApi::class, PluginHostApi::class)
|
||||||
class SelectedAppInfoViewModel(
|
class SelectedAppInfoViewModel(
|
||||||
val input: SelectedAppInfo.ViewModelParams
|
private val input: SelectedAppInfo.ViewModelParams
|
||||||
) : ViewModel(), KoinComponent {
|
) : ViewModel(), KoinComponent {
|
||||||
private val bundleRepository: PatchBundleRepository = get()
|
private val bundleRepository: PatchBundleRepository = get()
|
||||||
private val selectionRepository: PatchSelectionRepository = get()
|
private val selectionRepository: PatchSelectionRepository = get()
|
||||||
private val optionsRepository: PatchOptionsRepository = get()
|
private val optionsRepository: PatchOptionsRepository = get()
|
||||||
private val pluginsRepository: DownloaderPluginRepository = get()
|
private val pluginsRepository: DownloaderPluginRepository = get()
|
||||||
private val installedAppRepository: InstalledAppRepository = get()
|
private val installedAppRepository: InstalledAppRepository = get()
|
||||||
|
private val downloadedAppRepository: DownloadedAppRepository = get()
|
||||||
private val pm: PM = get()
|
private val pm: PM = get()
|
||||||
private val savedStateHandle: SavedStateHandle = get()
|
private val savedStateHandle: SavedStateHandle = get()
|
||||||
private val prefs: PreferencesManager = get()
|
private val prefs: PreferencesManager = get()
|
||||||
@@ -101,16 +103,8 @@ class SelectedAppInfoViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// All patches for package
|
// All patches for package
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
val bundles = bundleRepository.scopedBundleInfoFlow(packageName, null)
|
||||||
val bundles = _selectedVersion.flatMapLatest { selectedVersion ->
|
|
||||||
val version = if (selectedVersion is SelectedVersion.Specific)
|
|
||||||
selectedVersion.version
|
|
||||||
else null
|
|
||||||
bundleRepository.scopedBundleInfoFlow(packageName, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Selection derived from selectionFlow
|
// Selection derived from selectionFlow
|
||||||
val patchSelection = combine(
|
val patchSelection = combine(
|
||||||
@@ -163,20 +157,29 @@ class SelectedAppInfoViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resolve actual source from user selection
|
// Resolve actual source from user selection
|
||||||
val resolvedSource = _selectedSource.map { source ->
|
val resolvedSource = combine(
|
||||||
// TODO
|
_selectedSource,
|
||||||
// when (source) {
|
resolvedVersion
|
||||||
// is SelectedSource.Auto -> null
|
) { source, version ->
|
||||||
// is SelectedSource.Installed -> null
|
when (source) {
|
||||||
// is SelectedSource.Downloaded -> null
|
is SelectedSource.Installed -> source
|
||||||
// is SelectedSource.Plugin -> null
|
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 {
|
val bundleInfoFlow by derivedStateOf {
|
||||||
bundleRepository.scopedBundleInfoFlow(packageName, null)
|
bundleRepository.scopedBundleInfoFlow(packageName, null)
|
||||||
}
|
}
|
||||||
@@ -197,6 +200,16 @@ class SelectedAppInfoViewModel(
|
|||||||
private set
|
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)
|
// 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
|
// TODO: Load from local file or downloaded app
|
||||||
private fun invalidateSelectedAppInfo() = viewModelScope.launch {
|
private fun invalidateSelectedAppInfo() = viewModelScope.launch {
|
||||||
selectedAppInfo = pm.getPackageInfo(packageName)
|
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 {
|
init {
|
||||||
invalidateSelectedAppInfo()
|
invalidateSelectedAppInfo()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user