Use ViewModel instead of rememberSaveable

This commit is contained in:
Nullptr 2022-03-06 17:35:26 +08:00
parent 4dd6369e1a
commit c73a5a079f
4 changed files with 80 additions and 54 deletions

View File

@ -32,6 +32,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionStatus import com.google.accompanist.permissions.PermissionStatus
@ -48,6 +49,7 @@ import org.lsposed.lspatch.ui.util.isScrolledToEnd
import org.lsposed.lspatch.ui.util.lastItemIndex import org.lsposed.lspatch.ui.util.lastItemIndex
import org.lsposed.lspatch.ui.util.observeState import org.lsposed.lspatch.ui.util.observeState
import org.lsposed.lspatch.ui.viewmodel.AppInfo import org.lsposed.lspatch.ui.viewmodel.AppInfo
import org.lsposed.lspatch.ui.viewmodel.NewPatchViewModel
import org.lsposed.patch.util.Logger import org.lsposed.patch.util.Logger
import java.io.File import java.io.File
@ -178,25 +180,19 @@ private fun PatchOptionsBody(
onSubmit: (Patcher.Options) -> Unit onSubmit: (Patcher.Options) -> Unit
) { ) {
val navController = LocalNavController.current val navController = LocalNavController.current
var useManager by rememberSaveable { mutableStateOf(true) } val viewModel = viewModel<NewPatchViewModel>()
var debuggable by rememberSaveable { mutableStateOf(false) }
var v1 by rememberSaveable { mutableStateOf(false) }
var v2 by rememberSaveable { mutableStateOf(true) }
var v3 by rememberSaveable { mutableStateOf(true) }
var sigBypassLevel by rememberSaveable { mutableStateOf(2) }
var overrideVersionCode by rememberSaveable { mutableStateOf(false) }
val embeddedModules = navController.currentBackStackEntry!! val embeddedModules = navController.currentBackStackEntry!!
.savedStateHandle.getLiveData<SnapshotStateList<AppInfo>>("selected", SnapshotStateList()) .savedStateHandle.getLiveData<SnapshotStateList<AppInfo>>("selected", SnapshotStateList())
if (patchState == PatchState.SUBMITTING) LaunchedEffect(patchApp) { if (patchState == PatchState.SUBMITTING) LaunchedEffect(patchApp) {
if (useManager) embeddedModules.value?.clear() if (viewModel.useManager) embeddedModules.value?.clear()
val options = Patcher.Options( val options = Patcher.Options(
apkPaths = arrayOf(patchApp.app.sourceDir), // TODO: Split Apk apkPaths = arrayOf(patchApp.app.sourceDir), // TODO: Split Apk
debuggable = debuggable, debuggable = viewModel.debuggable,
sigbypassLevel = sigBypassLevel, sigbypassLevel = viewModel.sigBypassLevel,
v1 = v1, v2 = v2, v3 = v3, v1 = viewModel.sign[0], v2 = viewModel.sign[1], v3 = viewModel.sign[2],
useManager = useManager, useManager = viewModel.useManager,
overrideVersionCode = overrideVersionCode, overrideVersionCode = viewModel.overrideVersionCode,
verbose = true, verbose = true,
embeddedModules = embeddedModules.value?.map { it.app.sourceDir } ?: emptyList() // TODO: Split Apk embeddedModules = embeddedModules.value?.map { it.app.sourceDir } ?: emptyList() // TODO: Split Apk
) )
@ -213,15 +209,15 @@ private fun PatchOptionsBody(
) )
SelectionColumn(Modifier.padding(horizontal = 24.dp)) { SelectionColumn(Modifier.padding(horizontal = 24.dp)) {
SelectionItem( SelectionItem(
selected = useManager, selected = viewModel.useManager,
onClick = { useManager = true }, onClick = { viewModel.useManager = true },
icon = Icons.Outlined.Api, icon = Icons.Outlined.Api,
title = stringResource(R.string.patch_local), title = stringResource(R.string.patch_local),
desc = stringResource(R.string.patch_local_desc) desc = stringResource(R.string.patch_local_desc)
) )
SelectionItem( SelectionItem(
selected = !useManager, selected = !viewModel.useManager,
onClick = { useManager = false }, onClick = { viewModel.useManager = false },
icon = Icons.Outlined.WorkOutline, icon = Icons.Outlined.WorkOutline,
title = stringResource(R.string.patch_portable), title = stringResource(R.string.patch_portable),
desc = stringResource(R.string.patch_portable_desc), desc = stringResource(R.string.patch_portable_desc),
@ -235,54 +231,62 @@ private fun PatchOptionsBody(
) )
} }
SettingsCheckBox( SettingsCheckBox(
checked = debuggable, checked = viewModel.debuggable,
onClick = { debuggable = !debuggable }, onClick = { viewModel.debuggable = !viewModel.debuggable },
icon = Icons.Outlined.BugReport, icon = Icons.Outlined.BugReport,
title = stringResource(R.string.patch_debuggable) title = stringResource(R.string.patch_debuggable)
) )
SettingsCheckBox( SettingsCheckBox(
checked = v1, checked = viewModel.overrideVersionCode,
onClick = { v1 = !v1 }, onClick = { viewModel.overrideVersionCode = !viewModel.overrideVersionCode },
title = stringResource(R.string.patch_v1) title = stringResource(R.string.patch_override_version_code),
) desc = stringResource(R.string.patch_override_version_code_desc)
SettingsCheckBox(
checked = v2,
onClick = { v2 = !v2 },
title = stringResource(R.string.patch_v2)
)
SettingsCheckBox(
checked = v3,
onClick = { v3 = !v3 },
title = stringResource(R.string.patch_v3)
) )
Box {
var expanded by remember { mutableStateOf(false) }
SettingsItem(
onClick = { expanded = true },
title = stringResource(R.string.patch_sign),
desc = viewModel.sign.mapIndexedNotNull { index, on -> if (on) "V" + (index + 1) else null }.joinToString(" + ").ifEmpty { "None" }
)
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
repeat(3) { index ->
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked = viewModel.sign[index], onCheckedChange = { viewModel.sign[index] = !viewModel.sign[index] })
Text("V" + (index + 1))
}
},
onClick = { viewModel.sign[index] = !viewModel.sign[index] }
)
}
}
}
Box { Box {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
SettingsItem( SettingsItem(
onClick = { expanded = true }, onClick = { expanded = true },
title = stringResource(R.string.patch_sigbypasslv), title = stringResource(R.string.patch_sigbypasslv),
desc = sigBypassLvStr(sigBypassLevel) desc = sigBypassLvStr(viewModel.sigBypassLevel)
) )
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
repeat(3) { repeat(3) {
DropdownMenuItem( DropdownMenuItem(
text = { text = {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = sigBypassLevel == it, onClick = { sigBypassLevel = it }) RadioButton(selected = viewModel.sigBypassLevel == it, onClick = { viewModel.sigBypassLevel = it })
Text(sigBypassLvStr(it)) Text(sigBypassLvStr(it))
} }
}, },
onClick = { sigBypassLevel = it } onClick = {
viewModel.sigBypassLevel = it
expanded = false
}
) )
} }
} }
} }
SettingsCheckBox(
checked = overrideVersionCode,
onClick = { overrideVersionCode = !overrideVersionCode },
title = stringResource(R.string.patch_override_version_code),
desc = stringResource(R.string.patch_override_version_code_desc)
)
Spacer(Modifier.height(56.dp))
} }
} }

View File

@ -18,19 +18,25 @@ enum class PageList(
val arguments: List<NamedNavArgument> = emptyList(), val arguments: List<NamedNavArgument> = emptyList(),
val body: @Composable NavBackStackEntry.() -> Unit val body: @Composable NavBackStackEntry.() -> Unit
) { ) {
Home(
iconSelected = Icons.Filled.Home, Repo(
iconNotSelected = Icons.Outlined.Home, iconSelected = Icons.Filled.GetApp,
body = { HomePage() } iconNotSelected = Icons.Outlined.GetApp,
body = {}
), ),
Manage( Manage(
iconSelected = Icons.Filled.Dashboard, iconSelected = Icons.Filled.Dashboard,
iconNotSelected = Icons.Outlined.Dashboard, iconNotSelected = Icons.Outlined.Dashboard,
body = { ManagePage() } body = { ManagePage() }
), ),
Repo( Home(
iconSelected = Icons.Filled.GetApp, iconSelected = Icons.Filled.Home,
iconNotSelected = Icons.Outlined.GetApp, iconNotSelected = Icons.Outlined.Home,
body = { HomePage() }
),
Logs(
iconSelected = Icons.Filled.Assessment,
iconNotSelected = Icons.Outlined.Assignment,
body = {} body = {}
), ),
Settings( Settings(
@ -50,9 +56,10 @@ enum class PageList(
val title: String val title: String
@Composable get() = when (this) { @Composable get() = when (this) {
Home -> stringResource(R.string.app_name)
Manage -> stringResource(R.string.page_manage)
Repo -> stringResource(R.string.page_repo) Repo -> stringResource(R.string.page_repo)
Manage -> stringResource(R.string.page_manage)
Home -> stringResource(R.string.app_name)
Logs -> stringResource(R.string.page_logs)
Settings -> stringResource(R.string.page_settings) Settings -> stringResource(R.string.page_settings)
NewPatch -> stringResource(R.string.page_new_patch) NewPatch -> stringResource(R.string.page_new_patch)
SelectApps -> stringResource(R.string.page_select_apps) SelectApps -> stringResource(R.string.page_select_apps)

View File

@ -0,0 +1,16 @@
package org.lsposed.lspatch.ui.viewmodel
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
class NewPatchViewModel : ViewModel() {
var useManager by mutableStateOf(true)
var debuggable by mutableStateOf(false)
var overrideVersionCode by mutableStateOf(false)
var sign = mutableStateListOf(false, true, true)
var sigBypassLevel by mutableStateOf(2)
}

View File

@ -3,6 +3,7 @@
<string name="add">Add</string> <string name="add">Add</string>
<string name="page_repo">Repo</string> <string name="page_repo">Repo</string>
<string name="page_logs">Logs</string>
<string name="page_settings">Settings</string> <string name="page_settings">Settings</string>
<!-- Manage Page --> <!-- Manage Page -->
@ -19,9 +20,7 @@
<string name="patch_portable_desc">Patch an app with modules embedded.\nThe patched app can run without the manager, but cannot be managed dynamically.\nPortable patched apps can be used on devices that do not have LSPatch Manager installed.</string> <string name="patch_portable_desc">Patch an app with modules embedded.\nThe patched app can run without the manager, but cannot be managed dynamically.\nPortable patched apps can be used on devices that do not have LSPatch Manager installed.</string>
<string name="patch_embed_modules">Embed modules</string> <string name="patch_embed_modules">Embed modules</string>
<string name="patch_debuggable">Debuggable</string> <string name="patch_debuggable">Debuggable</string>
<string name="patch_v1">V1 signature</string> <string name="patch_sign">Sign</string>
<string name="patch_v2">V2 signature</string>
<string name="patch_v3">V3 signature</string>
<string name="patch_sigbypasslv">Signature bypass level</string> <string name="patch_sigbypasslv">Signature bypass level</string>
<string name="patch_sigbypasslv_0">lv0: Off</string> <string name="patch_sigbypasslv_0">lv0: Off</string>
<string name="patch_sigbypasslv_1">lv1: Bypass PM</string> <string name="patch_sigbypasslv_1">lv1: Bypass PM</string>