feat: add settings to select default installer

This commit is contained in:
Aunali321 2023-08-15 00:07:29 +05:30
parent 6ca2268a34
commit c5d859f990
6 changed files with 121 additions and 8 deletions

View File

@ -1,12 +1,21 @@
package app.revanced.manager.domain.manager package app.revanced.manager.domain.manager
import android.content.Context import android.content.Context
import app.revanced.manager.R
import app.revanced.manager.domain.manager.base.BasePreferencesManager import app.revanced.manager.domain.manager.base.BasePreferencesManager
import app.revanced.manager.ui.theme.Theme import app.revanced.manager.ui.theme.Theme
class PreferencesManager( class PreferencesManager(
context: Context context: Context
) : BasePreferencesManager(context, "settings") { ) : BasePreferencesManager(context, "settings") {
enum class InstallerManager(val displayName: Int) {
DEFAULT(R.string.default_installer),
SHIZUKU(R.string.shizuku_installer),
ROOT(R.string.root_installer),
MAGISK(R.string.magisk_installer),
}
val dynamicColor = booleanPreference("dynamic_color", true) val dynamicColor = booleanPreference("dynamic_color", true)
val theme = enumPreference("theme", Theme.SYSTEM) val theme = enumPreference("theme", Theme.SYSTEM)
@ -18,6 +27,7 @@ class PreferencesManager(
val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT) val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT)
val preferSplits = booleanPreference("prefer_splits", false) val preferSplits = booleanPreference("prefer_splits", false)
val installer = enumPreference("installer", InstallerManager.DEFAULT)
val showAutoUpdatesDialog = booleanPreference("show_auto_updates_dialog", true) val showAutoUpdatesDialog = booleanPreference("show_auto_updates_dialog", true)
val managerAutoUpdates = booleanPreference("manager_auto_updates", false) val managerAutoUpdates = booleanPreference("manager_auto_updates", false)

View File

@ -5,18 +5,24 @@ import android.os.Build
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.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Http import androidx.compose.material.icons.outlined.Http
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@ -26,6 +32,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -33,10 +40,12 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.GroupHeader import app.revanced.manager.ui.component.GroupHeader
import app.revanced.manager.ui.viewmodel.AdvancedSettingsViewModel import app.revanced.manager.ui.viewmodel.AdvancedSettingsViewModel
import org.koin.androidx.compose.getViewModel import org.koin.androidx.compose.getViewModel
import org.koin.compose.koinInject
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -44,7 +53,9 @@ fun AdvancedSettingsScreen(
onBackClick: () -> Unit, onBackClick: () -> Unit,
vm: AdvancedSettingsViewModel = getViewModel() vm: AdvancedSettingsViewModel = getViewModel()
) { ) {
val prefs = vm.prefs
val context = LocalContext.current val context = LocalContext.current
var showInstallerPicker by rememberSaveable { mutableStateOf(false) }
val memoryLimit = remember { val memoryLimit = remember {
val activityManager = context.getSystemService<ActivityManager>()!! val activityManager = context.getSystemService<ActivityManager>()!!
context.getString( context.getString(
@ -54,6 +65,13 @@ fun AdvancedSettingsScreen(
) )
} }
if (showInstallerPicker) {
InstallerPicker(
onDismiss = { showInstallerPicker = false },
onConfirm = { vm.setInstaller(it) }
)
}
Scaffold( Scaffold(
topBar = { topBar = {
AppTopBar( AppTopBar(
@ -99,6 +117,26 @@ fun AdvancedSettingsScreen(
} }
) )
val installer by prefs.installer.getAsState()
GroupHeader(stringResource(R.string.installer))
ListItem(
modifier = Modifier.clickable { showInstallerPicker = true },
headlineContent = { Text(stringResource(R.string.installer)) },
supportingContent = { Text(stringResource(R.string.installer_description)) },
trailingContent = {
FilledTonalButton(
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
),
onClick = {
showInstallerPicker = true
}
) {
Text(stringResource(installer.displayName))
}
}
)
GroupHeader(stringResource(R.string.device)) GroupHeader(stringResource(R.string.device))
ListItem( ListItem(
headlineContent = { Text(stringResource(R.string.device_model)) }, headlineContent = { Text(stringResource(R.string.device_model)) },
@ -173,3 +211,42 @@ private fun APIUrlDialog(currentUrl: String, onSubmit: (String?) -> Unit) {
} }
) )
} }
@Composable
private fun InstallerPicker(
onDismiss: () -> Unit,
onConfirm: (PreferencesManager.InstallerManager) -> Unit,
prefs: PreferencesManager = koinInject()
) {
var selectedInstaller by rememberSaveable { mutableStateOf(prefs.installer.getBlocking()) }
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.installer)) },
text = {
Column {
PreferencesManager.InstallerManager.values().forEach {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { selectedInstaller = it },
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = selectedInstaller == it,
onClick = { selectedInstaller = it })
Text(stringResource(it.displayName))
}
}
}
},
confirmButton = {
Button(onClick = {
onConfirm(selectedInstaller)
onDismiss()
}) {
Text(stringResource(R.string.apply))
}
}
)
}

View File

@ -1,7 +1,6 @@
package app.revanced.manager.ui.screen.settings package app.revanced.manager.ui.screen.settings
import android.os.Build import android.os.Build
import androidx.annotation.StringRes
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -23,7 +22,6 @@ import app.revanced.manager.ui.component.GroupHeader
import app.revanced.manager.ui.component.settings.BooleanItem import app.revanced.manager.ui.component.settings.BooleanItem
import app.revanced.manager.ui.theme.Theme import app.revanced.manager.ui.theme.Theme
import app.revanced.manager.ui.viewmodel.SettingsViewModel import app.revanced.manager.ui.viewmodel.SettingsViewModel
import kotlinx.coroutines.launch
import org.koin.compose.koinInject import org.koin.compose.koinInject
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -65,7 +63,10 @@ fun GeneralSettingsScreen(
headlineContent = { Text(stringResource(R.string.theme)) }, headlineContent = { Text(stringResource(R.string.theme)) },
supportingContent = { Text(stringResource(R.string.theme_description)) }, supportingContent = { Text(stringResource(R.string.theme_description)) },
trailingContent = { trailingContent = {
Button( FilledTonalButton(
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
),
onClick = { onClick = {
showThemePicker = true showThemePicker = true
} }

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AdvancedSettingsViewModel( class AdvancedSettingsViewModel(
prefs: PreferencesManager, val prefs: PreferencesManager,
private val app: Application, private val app: Application,
private val patchBundleRepository: PatchBundleRepository private val patchBundleRepository: PatchBundleRepository
) : ViewModel() { ) : ViewModel() {
@ -34,4 +34,8 @@ class AdvancedSettingsViewModel(
fun resetBundles() = viewModelScope.launch { fun resetBundles() = viewModelScope.launch {
patchBundleRepository.reset() patchBundleRepository.reset()
} }
fun setInstaller(installer: PreferencesManager.InstallerManager) = viewModelScope.launch {
prefs.installer.update(installer)
}
} }

View File

@ -20,6 +20,7 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
import app.revanced.manager.domain.manager.KeystoreManager import app.revanced.manager.domain.manager.KeystoreManager
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.worker.WorkerRepository import app.revanced.manager.domain.worker.WorkerRepository
import app.revanced.manager.patcher.worker.PatcherProgressManager import app.revanced.manager.patcher.worker.PatcherProgressManager
import app.revanced.manager.patcher.worker.PatcherWorker import app.revanced.manager.patcher.worker.PatcherWorker
@ -52,6 +53,7 @@ class InstallerViewModel(input: Destination.Installer) : ViewModel(), KoinCompon
private val pm: PM by inject() private val pm: PM by inject()
private val workerRepository: WorkerRepository by inject() private val workerRepository: WorkerRepository by inject()
val prefs: PreferencesManager by inject()
val packageName: String = input.selectedApp.packageName val packageName: String = input.selectedApp.packageName
private val outputFile = File(app.cacheDir, "output.apk") private val outputFile = File(app.cacheDir, "output.apk")
private val signedFile = File(app.cacheDir, "signed.apk").also { if (it.exists()) it.delete() } private val signedFile = File(app.cacheDir, "signed.apk").also { if (it.exists()) it.delete() }
@ -62,6 +64,7 @@ class InstallerViewModel(input: Destination.Installer) : ViewModel(), KoinCompon
var installedPackageName by mutableStateOf<String?>(null) var installedPackageName by mutableStateOf<String?>(null)
private set private set
val appButtonText by derivedStateOf { if (installedPackageName == null) R.string.install_app else R.string.open_app } val appButtonText by derivedStateOf { if (installedPackageName == null) R.string.install_app else R.string.open_app }
private val selectedInstaller by derivedStateOf { prefs.installer.getBlocking() }
private val workManager = WorkManager.getInstance(app) private val workManager = WorkManager.getInstance(app)
@ -189,9 +192,22 @@ class InstallerViewModel(input: Destination.Installer) : ViewModel(), KoinCompon
isInstalling = true isInstalling = true
try { try {
if (!signApk()) return@launch if (!signApk()) return@launch
//
// pm.installApp(listOf(signedFile)) when (selectedInstaller) {
ShizukuApi.installPackage(signedFile) PreferencesManager.InstallerManager.DEFAULT -> {
pm.installApp(listOf(signedFile))
}
PreferencesManager.InstallerManager.SHIZUKU -> {
ShizukuApi.installPackage(signedFile)
}
PreferencesManager.InstallerManager.ROOT -> {
// RootApi.installPackage(signedFile)
}
PreferencesManager.InstallerManager.MAGISK -> {
// MagiskApi.installPackage(signedFile)
}
}
} finally { } finally {
isInstalling = false isInstalling = false
} }

View File

@ -233,4 +233,9 @@
<string name="shizuku_available">Shizuku service available</string> <string name="shizuku_available">Shizuku service available</string>
<string name="shizuku_unavailable">Shizuku service not connected</string> <string name="shizuku_unavailable">Shizuku service not connected</string>
<string name="home_shizuku_warning">Some functions unavailable</string> <string name="home_shizuku_warning">Some functions unavailable</string>
<string name="installer_description">Choose the default installer</string>
<string name="default_installer">Default</string>
<string name="shizuku_installer">Shizuku</string>
<string name="root_installer">Root</string>
<string name="magisk_installer">Magisk</string>
</resources> </resources>