From d7b3b4cb6b5e1cb9604e5e81ad6dfb56ac24150a Mon Sep 17 00:00:00 2001 From: Nullptr <52071314+Dr-TSNG@users.noreply.github.com> Date: Wed, 11 May 2022 13:32:57 +0800 Subject: [PATCH] Fix UI bugs --- .../lspatch/ui/activity/MainActivity.kt | 19 ++----- .../lsposed/lspatch/ui/page/NewPatchPage.kt | 56 ++++--------------- .../org/lsposed/lspatch/ui/page/PageList.kt | 7 +++ .../org/lsposed/lspatch/ui/util/Navigation.kt | 19 ++----- .../lspatch/ui/viewmodel/NewPatchViewModel.kt | 52 ++++++++++++++--- 5 files changed, 75 insertions(+), 78 deletions(-) diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/activity/MainActivity.kt b/manager/src/main/java/org/lsposed/lspatch/ui/activity/MainActivity.kt index 83e7378..64bf982 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/activity/MainActivity.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/activity/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -18,7 +19,7 @@ import org.lsposed.lspatch.ui.page.PageList import org.lsposed.lspatch.ui.theme.LSPTheme import org.lsposed.lspatch.ui.util.LocalNavController import org.lsposed.lspatch.ui.util.LocalSnackbarHost -import org.lsposed.lspatch.ui.util.currentRoute +import org.lsposed.lspatch.ui.util.navigateWithState class MainActivity : ComponentActivity() { @@ -27,7 +28,6 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { val navController = rememberAnimatedNavController() - val currentRoute = navController.currentRoute var mainPage by rememberSaveable { mutableStateOf(PageList.Home) } LSPTheme { @@ -39,12 +39,9 @@ class MainActivity : ComponentActivity() { Scaffold( bottomBar = { MainNavigationBar(mainPage) { + if (mainPage == it) return@MainNavigationBar mainPage = it - navController.navigate(it.name) { - currentRoute?.let { route -> - popUpTo(route) { inclusive = true } - } - } + navController.navigateWithState(it.name) } }, snackbarHost = { SnackbarHost(snackbarHostState) } @@ -64,12 +61,8 @@ private fun MainNavHost(navController: NavHostController, modifier: Modifier) { startDestination = PageList.Home.name, modifier = modifier ) { - PageList.values().forEach { page -> - val sb = StringBuilder(page.name) - if (page.arguments.isNotEmpty()) { - sb.append(page.arguments.joinToString(",", "?") { "${it.name}={${it.name}}" }) - } - composable(route = sb.toString(), arguments = page.arguments, content = page.body) + for (page in PageList.values()) { + composable(route = page.route, arguments = page.arguments, content = page.body) } } } diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt index 40b05ca..5c86699 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt @@ -23,12 +23,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily @@ -38,7 +36,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavBackStackEntry import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import org.lsposed.lspatch.Patcher import org.lsposed.lspatch.R import org.lsposed.lspatch.lspApp import org.lsposed.lspatch.ui.component.SelectionColumn @@ -51,7 +48,6 @@ import org.lsposed.lspatch.ui.viewmodel.NewPatchViewModel.PatchState import org.lsposed.lspatch.util.LSPPackageManager import org.lsposed.lspatch.util.LSPPackageManager.AppInfo import org.lsposed.lspatch.util.ShizukuApi -import org.lsposed.patch.util.Logger import java.io.File private const val TAG = "NewPatchPage" @@ -64,12 +60,6 @@ fun NewPatchPage(from: String, entry: NavBackStackEntry) { val navController = LocalNavController.current val lifecycleOwner = LocalLifecycleOwner.current val isCancelled by entry.observeState("isCancelled") - LaunchedEffect(Unit) { - lspApp.tmpApkDir.listFiles()?.forEach(File::delete) - entry.savedStateHandle.getLiveData("appInfo").observe(lifecycleOwner) { - viewModel.configurePatch(it) - } - } Log.d(TAG, "PatchState: ${viewModel.patchState}") if (viewModel.patchState == PatchState.SELECTING) { @@ -90,10 +80,16 @@ fun NewPatchPage(from: String, entry: NavBackStackEntry) { } } LaunchedEffect(Unit) { + lspApp.tmpApkDir.listFiles()?.forEach(File::delete) if (isCancelled == true) navController.popBackStack() else when (from) { "storage" -> storageLauncher.launch(arrayOf("application/vnd.android.package-archive")) - "applist" -> navController.navigate(PageList.SelectApps.name + "?multiSelect=false") + "applist" -> { + entry.savedStateHandle.getLiveData("appInfo").observe(lifecycleOwner) { + viewModel.configurePatch(it) + } + navController.navigate(PageList.SelectApps.name + "?multiSelect=false") + } } } } else { @@ -268,44 +264,16 @@ private fun PatchOptionsBody(modifier: Modifier) { } } -private class PatchLogger(private val logs: MutableList>) : Logger() { - override fun d(msg: String) { - if (verbose) { - Log.d(TAG, msg) - logs += Log.DEBUG to msg - } - } - - override fun i(msg: String) { - Log.i(TAG, msg) - logs += Log.INFO to msg - } - - override fun e(msg: String) { - Log.e(TAG, msg) - logs += Log.ERROR to msg - } -} - @Composable private fun DoPatchBody(modifier: Modifier) { val viewModel = viewModel() val snackbarHost = LocalSnackbarHost.current val navController = LocalNavController.current val scope = rememberCoroutineScope() - val logs = remember { mutableStateListOf>() } - val logger = remember { PatchLogger(logs) } LaunchedEffect(Unit) { - try { - Patcher.patch(logger, viewModel.patchOptions) - viewModel.finishPatch() - } catch (t: Throwable) { - logger.e(t.message.orEmpty()) - logger.e(t.stackTraceToString()) - viewModel.failPatch() - } finally { - lspApp.tmpApkDir.listFiles()?.forEach(File::delete) + if (viewModel.logs.isEmpty()) { + viewModel.launchPatch() } } @@ -333,7 +301,7 @@ private fun DoPatchBody(modifier: Modifier) { .background(brush) .padding(horizontal = 24.dp, vertical = 18.dp) ) { - items(logs) { + items(viewModel.logs) { when (it.first) { Log.DEBUG -> Text(text = it.second) Log.INFO -> Text(text = it.second) @@ -357,7 +325,7 @@ private fun DoPatchBody(modifier: Modifier) { val installSuccessfully = stringResource(R.string.patch_install_successfully) val installFailed = stringResource(R.string.patch_install_failed) val copyError = stringResource(R.string.patch_copy_error) - var installing by rememberSaveable { mutableStateOf(false) } + var installing by remember { mutableStateOf(false) } if (installing) InstallDialog(viewModel.patchApp) { status, message -> scope.launch { LSPPackageManager.fetchAppList() @@ -408,7 +376,7 @@ private fun DoPatchBody(modifier: Modifier) { modifier = Modifier.weight(1f), onClick = { val cm = lspApp.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - cm.setPrimaryClip(ClipData.newPlainText("LSPatch", logs.joinToString { it.second + "\n" })) + cm.setPrimaryClip(ClipData.newPlainText("LSPatch", viewModel.logs.joinToString { it.second + "\n" })) }, content = { Text(stringResource(R.string.patch_copy_error)) } ) diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/PageList.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/PageList.kt index 937ef95..1760191 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/PageList.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/PageList.kt @@ -66,4 +66,11 @@ enum class PageList( NewPatch -> stringResource(R.string.page_new_patch) SelectApps -> stringResource(R.string.page_select_apps) } + + val route = buildString { + append(name) + if (arguments.isNotEmpty()) { + append(arguments.joinToString(",", "?") { "${it.name}={${it.name}}" }) + } + } } diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/util/Navigation.kt b/manager/src/main/java/org/lsposed/lspatch/ui/util/Navigation.kt index 8be2ddb..861d8d5 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/util/Navigation.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/util/Navigation.kt @@ -5,27 +5,18 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController import androidx.navigation.NavGraph.Companion.findStartDestination -import androidx.navigation.compose.currentBackStackEntryAsState - -val NavController.currentRoute: String? - @Composable get() = currentBackStackEntryAsState().value?.destination?.route - -val NavController.startRoute: String? - get() = graph.findStartDestination().route fun NavBackStackEntry.setState(key: String, value: T?) { savedStateHandle.getLiveData(key).value = value } @Composable -fun NavBackStackEntry.observeState(key: String, initial: T? = null) = savedStateHandle.getLiveData(key, initial).observeAsState() +fun NavBackStackEntry.observeState(key: String, initial: T? = null) = + savedStateHandle.getLiveData(key, initial).observeAsState() -@Composable -fun NavController.isAtStartRoute(): Boolean = currentRoute == startRoute - -fun NavController.navigateWithState(route: String?) { - navigate(route.toString()) { - popUpTo(startRoute.toString()) { +fun NavController.navigateWithState(route: String) { + navigate(route) { + popUpTo(graph.findStartDestination().id) { saveState = true } launchSingleTop = true diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt b/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt index 3081e2e..51c8189 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt @@ -1,13 +1,21 @@ package org.lsposed.lspatch.ui.viewmodel +import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch import org.lsposed.lspatch.Patcher +import org.lsposed.lspatch.lspApp import org.lsposed.lspatch.util.LSPPackageManager.AppInfo +import org.lsposed.patch.util.Logger +import java.io.File + +private const val TAG = "NewPatchViewModel" class NewPatchViewModel : ViewModel() { @@ -21,7 +29,7 @@ class NewPatchViewModel : ViewModel() { var useManager by mutableStateOf(true) var debuggable by mutableStateOf(false) var overrideVersionCode by mutableStateOf(false) - var sign = mutableStateListOf(false, true) + val sign = mutableStateListOf(false, true) var sigBypassLevel by mutableStateOf(2) lateinit var patchApp: AppInfo @@ -30,12 +38,34 @@ class NewPatchViewModel : ViewModel() { lateinit var patchOptions: Patcher.Options private set + val logs = mutableStateListOf>() + private val logger = object : Logger() { + override fun d(msg: String) { + if (verbose) { + Log.d(TAG, msg) + logs += Log.DEBUG to msg + } + } + + override fun i(msg: String) { + Log.i(TAG, msg) + logs += Log.INFO to msg + } + + override fun e(msg: String) { + Log.e(TAG, msg) + logs += Log.ERROR to msg + } + } + fun configurePatch(app: AppInfo) { + Log.d(TAG, "Configuring patch for ${app.app.packageName}") patchApp = app patchState = PatchState.CONFIGURING } fun submitPatch() { + Log.d(TAG, "Submit patch") if (useManager) embeddedModules.clear() patchOptions = Patcher.Options( apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()), @@ -50,11 +80,19 @@ class NewPatchViewModel : ViewModel() { patchState = PatchState.PATCHING } - fun finishPatch() { - patchState = PatchState.FINISHED - } - - fun failPatch() { - patchState = PatchState.ERROR + fun launchPatch() { + logger.i("Launch patch") + viewModelScope.launch { + patchState = try { + Patcher.patch(logger, patchOptions) + PatchState.FINISHED + } catch (t: Throwable) { + logger.e(t.message.orEmpty()) + logger.e(t.stackTraceToString()) + PatchState.ERROR + } finally { + lspApp.tmpApkDir.listFiles()?.forEach(File::delete) + } + } } }