diff --git a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt index b35d750..f2b8169 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt @@ -1,7 +1,6 @@ package app.revanced.manager.ui.screen import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -9,18 +8,23 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.outlined.HelpOutline -import androidx.compose.material.icons.outlined.Search import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.ListItem +import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +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.pluralStringResource @@ -29,6 +33,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.revanced.manager.R import app.revanced.manager.ui.component.AppTopBar +import app.revanced.manager.ui.component.GroupHeader import app.revanced.manager.ui.component.LoadingIndicator import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.ui.viewmodel.VersionSelectorViewModel @@ -56,6 +61,8 @@ fun VersionSelectorScreen( } } + var selectedVersion: SelectedApp? by rememberSaveable { mutableStateOf(null) } + Scaffold( topBar = { AppTopBar( @@ -65,75 +72,95 @@ fun VersionSelectorScreen( IconButton(onClick = { }) { Icon(Icons.Outlined.HelpOutline, stringResource(R.string.help)) } - IconButton(onClick = { }) { - Icon(Icons.Outlined.Search, stringResource(R.string.search)) - } } ) + }, + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text("Select version") }, + icon = { Icon(Icons.Default.Check, null) }, + onClick = { selectedVersion?.let(onAppClick) } + ) } ) { paddingValues -> Column( modifier = Modifier .padding(paddingValues) - .fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally + .fillMaxSize() + .verticalScroll(rememberScrollState()) ) { - when { - !viewModel.isDownloading && list.isNotEmpty() -> { - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - ) { - list.forEach { selectedApp -> - ListItem( - modifier = Modifier.clickable { onAppClick(selectedApp) }, - headlineContent = { Text(selectedApp.version) }, - supportingContent = - if (selectedApp is SelectedApp.Local) { - { Text(stringResource(R.string.already_downloaded)) } - } else null, - trailingContent = supportedVersions[selectedApp.version]?.let { { - Text( - pluralStringResource( - R.plurals.patches_count, - count = it, - it - ) - ) - } - } - ) - } - if (viewModel.errorMessage != null) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(stringResource(R.string.error_occurred)) - Text( - text = viewModel.errorMessage!!, - modifier = Modifier.padding(horizontal = 15.dp) - ) - } - } else if (viewModel.isLoading) - LoadingIndicator() - } + viewModel.installedApp?.let { packageInfo -> + SelectedApp.Installed( + packageName = viewModel.packageName, + version = packageInfo.versionName + ).let { + SelectedAppItem( + selectedApp = it, + selected = selectedVersion == it, + onClick = { selectedVersion = it }, + patchCount = supportedVersions[it.version] + ) } + } - viewModel.errorMessage != null -> { + GroupHeader("Downloadable versions") + + list.forEach { + SelectedAppItem( + selectedApp = it, + selected = selectedVersion == it, + onClick = { selectedVersion = it }, + patchCount = supportedVersions[it.version] + ) + } + + if (viewModel.errorMessage != null) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { Text(stringResource(R.string.error_occurred)) Text( text = viewModel.errorMessage!!, modifier = Modifier.padding(horizontal = 15.dp) ) } + } else if (viewModel.isLoading) + LoadingIndicator() - else -> { - LoadingIndicator() - } - } } } +} + +const val alreadyPatched = false + +@Composable +fun SelectedAppItem( + selectedApp: SelectedApp, + selected: Boolean, + onClick: () -> Unit, + patchCount: Int? +) { + ListItem( + leadingContent = { RadioButton(selected, null) }, + headlineContent = { Text(selectedApp.version) }, + supportingContent = when (selectedApp) { + is SelectedApp.Installed -> + if (alreadyPatched) { + { Text("Already patched") } + } else { + { Text("Installed") } + } + + is SelectedApp.Local -> { + { Text(stringResource(R.string.already_downloaded)) } + } + + else -> null + }, + trailingContent = patchCount?.let { { + Text(pluralStringResource(R.plurals.patches_count, it, it)) + } }, + modifier = Modifier.clickable(onClick = onClick) + ) } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt index 044a5c8..aac27f1 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt @@ -1,5 +1,6 @@ package app.revanced.manager.ui.viewmodel +import android.content.pm.PackageInfo import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -11,6 +12,7 @@ import app.revanced.manager.domain.repository.SourceRepository import app.revanced.manager.network.downloader.APKMirror import app.revanced.manager.network.downloader.AppDownloader import app.revanced.manager.ui.model.SelectedApp +import app.revanced.manager.util.PM import app.revanced.manager.util.mutableStateSetOf import app.revanced.manager.util.simpleMessage import app.revanced.manager.util.tag @@ -20,16 +22,17 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koin.core.component.KoinComponent -import org.koin.core.component.get +import org.koin.core.component.inject class VersionSelectorViewModel( val packageName: String ) : ViewModel(), KoinComponent { - private val downloadedAppRepository: DownloadedAppRepository = get() - private val sourceRepository: SourceRepository = get() + private val downloadedAppRepository: DownloadedAppRepository by inject() + private val sourceRepository: SourceRepository by inject() + private val pm: PM by inject() private val appDownloader: AppDownloader = APKMirror() - var isDownloading: Boolean by mutableStateOf(false) + var installedApp: PackageInfo? by mutableStateOf(null) private set var isLoading by mutableStateOf(true) private set @@ -63,6 +66,10 @@ class VersionSelectorViewModel( } init { + viewModelScope.launch(Dispatchers.Main) { + installedApp = withContext(Dispatchers.IO) { pm.getPackageInfo(packageName) } + } + viewModelScope.launch(Dispatchers.IO) { try { val compatibleVersions = supportedVersions.first() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d57ca41..98dd93e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -131,6 +131,7 @@ Loading… Not installed + An error occurred Already downloaded Select file