Small UI improvements

This commit is contained in:
Nullptr 2022-05-06 15:52:44 +08:00
parent 9106fc48b8
commit 6794d3a833
4 changed files with 53 additions and 42 deletions

View File

@ -41,7 +41,7 @@ fun SearchAppBar(
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
var onSearch by remember { mutableStateOf(false) } var onSearch by remember { mutableStateOf(false) }
LaunchedEffect(onSearch) { LaunchedEffect(Unit) {
if (onSearch) focusRequester.requestFocus() if (onSearch) focusRequester.requestFocus()
} }

View File

@ -72,11 +72,10 @@ private val listener: (Int, Int) -> Unit = { _, grantResult ->
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun ShizukuCard() { private fun ShizukuCard() {
val key = remember { true } LaunchedEffect(Unit) {
LaunchedEffect(key) {
Shizuku.addRequestPermissionResultListener(listener) Shizuku.addRequestPermissionResultListener(listener)
} }
DisposableEffect(key) { DisposableEffect(Unit) {
onDispose { onDispose {
Shizuku.removeRequestPermissionResultListener(listener) Shizuku.removeRequestPermissionResultListener(listener)
} }

View File

@ -5,6 +5,7 @@ import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.util.Log import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
@ -36,7 +37,6 @@ import androidx.navigation.NavBackStackEntry
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.lsposed.lspatch.Patcher import org.lsposed.lspatch.Patcher
import org.lsposed.lspatch.R import org.lsposed.lspatch.R
import org.lsposed.lspatch.TAG
import org.lsposed.lspatch.lspApp import org.lsposed.lspatch.lspApp
import org.lsposed.lspatch.ui.component.SelectionColumn import org.lsposed.lspatch.ui.component.SelectionColumn
import org.lsposed.lspatch.ui.component.ShimmerAnimation import org.lsposed.lspatch.ui.component.ShimmerAnimation
@ -50,6 +50,8 @@ import org.lsposed.lspatch.util.LSPPackageInstaller
import org.lsposed.lspatch.util.ShizukuApi import org.lsposed.lspatch.util.ShizukuApi
import org.lsposed.patch.util.Logger import org.lsposed.patch.util.Logger
private const val TAG = "NewPatchPage"
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun NewPatchPage(entry: NavBackStackEntry) { fun NewPatchPage(entry: NavBackStackEntry) {
@ -57,27 +59,29 @@ fun NewPatchPage(entry: NavBackStackEntry) {
val navController = LocalNavController.current val navController = LocalNavController.current
val lifecycleOwner = LocalLifecycleOwner.current val lifecycleOwner = LocalLifecycleOwner.current
val isCancelled by entry.observeState<Boolean>("isCancelled") val isCancelled by entry.observeState<Boolean>("isCancelled")
entry.savedStateHandle.getLiveData<AppInfo>("appInfo").observe(lifecycleOwner) { LaunchedEffect(Unit) {
viewModel.patchApp = it entry.savedStateHandle.getLiveData<AppInfo>("appInfo").observe(lifecycleOwner) {
viewModel.configurePatch(it)
}
} }
Log.d(TAG, "NewPatchPage: ${viewModel.patchState}") Log.d(TAG, "PatchState: ${viewModel.patchState}")
if (viewModel.patchState == PatchState.SELECTING) { if (viewModel.patchState == PatchState.SELECTING) {
when { LaunchedEffect(Unit) {
isCancelled == true -> { if (isCancelled == true) navController.popBackStack()
LaunchedEffect(viewModel) { navController.popBackStack() } else navController.navigate(PageList.SelectApps.name + "/false")
return
}
viewModel.patchApp != null -> {
LaunchedEffect(viewModel) { viewModel.configurePatch() }
}
else -> {
LaunchedEffect(viewModel) { navController.navigate(PageList.SelectApps.name + "/false") }
}
} }
} else { } else {
Scaffold( Scaffold(
topBar = { TopBar(viewModel.patchApp!!) }, topBar = {
when (viewModel.patchState) {
PatchState.CONFIGURING -> ConfiguringTopBar { navController.popBackStack() }
PatchState.PATCHING,
PatchState.FINISHED,
PatchState.ERROR -> CenterAlignedTopAppBar(title = { Text(viewModel.patchApp.app.packageName) })
else -> Unit
}
},
floatingActionButton = { floatingActionButton = {
if (viewModel.patchState == PatchState.CONFIGURING) { if (viewModel.patchState == PatchState.CONFIGURING) {
ConfiguringFab() ConfiguringFab()
@ -85,8 +89,10 @@ fun NewPatchPage(entry: NavBackStackEntry) {
} }
) { innerPadding -> ) { innerPadding ->
if (viewModel.patchState == PatchState.CONFIGURING) { if (viewModel.patchState == PatchState.CONFIGURING) {
entry.savedStateHandle.getLiveData<SnapshotStateList<AppInfo>>("selected", SnapshotStateList()).observe(lifecycleOwner) { LaunchedEffect(Unit) {
viewModel.embeddedModules = it entry.savedStateHandle.getLiveData<SnapshotStateList<AppInfo>>("selected", SnapshotStateList()).observe(lifecycleOwner) {
viewModel.embeddedModules = it
}
} }
PatchOptionsBody(Modifier.padding(innerPadding)) PatchOptionsBody(Modifier.padding(innerPadding))
} else { } else {
@ -97,21 +103,14 @@ fun NewPatchPage(entry: NavBackStackEntry) {
} }
@Composable @Composable
private fun TopBar(patchApp: AppInfo) { private fun ConfiguringTopBar(onBackClick: () -> Unit) {
SmallTopAppBar( SmallTopAppBar(
title = { title = { Text(stringResource(R.string.page_new_patch)) },
Column { navigationIcon = {
Text( IconButton(
text = patchApp.label, onClick = onBackClick,
style = MaterialTheme.typography.headlineSmall, content = { Icon(Icons.Outlined.ArrowBack, null) }
modifier = Modifier.padding(horizontal = 24.dp) )
)
Text(
text = patchApp.app.packageName,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(horizontal = 24.dp)
)
}
} }
) )
} }
@ -141,6 +140,16 @@ private fun PatchOptionsBody(modifier: Modifier) {
val navController = LocalNavController.current val navController = LocalNavController.current
Column(modifier.verticalScroll(rememberScrollState())) { Column(modifier.verticalScroll(rememberScrollState())) {
Text(
text = viewModel.patchApp.label,
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.padding(horizontal = 24.dp)
)
Text(
text = viewModel.patchApp.app.packageName,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(horizontal = 24.dp)
)
Text( Text(
text = stringResource(R.string.patch_mode), text = stringResource(R.string.patch_mode),
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleLarge,
@ -263,7 +272,7 @@ private fun DoPatchBody(modifier: Modifier) {
val logs = remember { mutableStateListOf<Pair<Int, String>>() } val logs = remember { mutableStateListOf<Pair<Int, String>>() }
val logger = remember { PatchLogger(logs) } val logger = remember { PatchLogger(logs) }
LaunchedEffect(viewModel) { LaunchedEffect(Unit) {
try { try {
Patcher.patch(context, logger, viewModel.patchOptions) Patcher.patch(context, logger, viewModel.patchOptions)
viewModel.finishPatch() viewModel.finishPatch()
@ -276,7 +285,7 @@ private fun DoPatchBody(modifier: Modifier) {
} }
} }
BoxWithConstraints(modifier.padding(24.dp)) { BoxWithConstraints(modifier.padding(start = 24.dp, end = 24.dp, bottom = 24.dp)) {
val shellBoxMaxHeight = val shellBoxMaxHeight =
if (viewModel.patchState == PatchState.PATCHING) maxHeight if (viewModel.patchState == PatchState.PATCHING) maxHeight
else maxHeight - ButtonDefaults.MinHeight - 12.dp else maxHeight - ButtonDefaults.MinHeight - 12.dp
@ -318,13 +327,14 @@ private fun DoPatchBody(modifier: Modifier) {
} }
when (viewModel.patchState) { when (viewModel.patchState) {
PatchState.PATCHING -> BackHandler {}
PatchState.FINISHED -> { PatchState.FINISHED -> {
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable) val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
val installSuccessfully = stringResource(R.string.patch_install_successfully) val installSuccessfully = stringResource(R.string.patch_install_successfully)
val installFailed = stringResource(R.string.patch_install_failed) val installFailed = stringResource(R.string.patch_install_failed)
val copyError = stringResource(R.string.patch_copy_error) val copyError = stringResource(R.string.patch_copy_error)
var installing by rememberSaveable { mutableStateOf(false) } var installing by rememberSaveable { mutableStateOf(false) }
if (installing) InstallDialog(viewModel.patchApp!!) { status, message -> if (installing) InstallDialog(viewModel.patchApp) { status, message ->
scope.launch { scope.launch {
installing = false installing = false
if (status == PackageInstaller.STATUS_SUCCESS) { if (status == PackageInstaller.STATUS_SUCCESS) {

View File

@ -16,7 +16,6 @@ class NewPatchViewModel : ViewModel() {
var patchState by mutableStateOf(PatchState.SELECTING) var patchState by mutableStateOf(PatchState.SELECTING)
private set private set
var patchApp by mutableStateOf<AppInfo?>(null)
var useManager by mutableStateOf(true) var useManager by mutableStateOf(true)
var debuggable by mutableStateOf(false) var debuggable by mutableStateOf(false)
@ -24,17 +23,20 @@ class NewPatchViewModel : ViewModel() {
var sign = mutableStateListOf(false, true) var sign = mutableStateListOf(false, true)
var sigBypassLevel by mutableStateOf(2) var sigBypassLevel by mutableStateOf(2)
lateinit var patchApp: AppInfo
private set
lateinit var embeddedModules: SnapshotStateList<AppInfo> lateinit var embeddedModules: SnapshotStateList<AppInfo>
lateinit var patchOptions: Patcher.Options lateinit var patchOptions: Patcher.Options
fun configurePatch() { fun configurePatch(app: AppInfo) {
patchApp = app
patchState = PatchState.CONFIGURING patchState = PatchState.CONFIGURING
} }
fun submitPatch() { fun submitPatch() {
if (useManager) embeddedModules.clear() if (useManager) embeddedModules.clear()
patchOptions = Patcher.Options( patchOptions = Patcher.Options(
apkPaths = listOf(patchApp!!.app.sourceDir) + (patchApp!!.app.splitSourceDirs ?: emptyArray()), apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()),
debuggable = debuggable, debuggable = debuggable,
sigbypassLevel = sigBypassLevel, sigbypassLevel = sigBypassLevel,
v1 = sign[0], v2 = sign[1], v1 = sign[0], v2 = sign[1],