parent
5a90ed436e
commit
5c8509e4f5
|
|
@ -30,6 +30,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.result.NavResult
|
||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||
|
|
@ -68,191 +70,199 @@ fun AppManageBody(
|
|||
val snackbarHost = LocalSnackbarHost.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
if (viewModel.appList.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = run {
|
||||
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
||||
else stringResource(R.string.manage_no_apps)
|
||||
},
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
}
|
||||
} else {
|
||||
var scopeApp by rememberSaveable { mutableStateOf("") }
|
||||
var afterCheckManager by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||
resultRecipient.onNavResult {
|
||||
if (it is NavResult.Value) {
|
||||
scope.launch {
|
||||
val result = it.value as SelectAppsResult.MultipleApps
|
||||
ConfigManager.getModulesForApp(scopeApp).forEach {
|
||||
ConfigManager.deactivateModule(scopeApp, it)
|
||||
}
|
||||
result.selected.forEach {
|
||||
Log.d(TAG, "Activate ${it.app.packageName} for $scopeApp")
|
||||
ConfigManager.activateModule(scopeApp, Module(it.app.packageName, it.app.sourceDir))
|
||||
}
|
||||
var scopeApp by rememberSaveable { mutableStateOf("") }
|
||||
var afterCheckManager by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||
|
||||
resultRecipient.onNavResult {
|
||||
if (it is NavResult.Value) {
|
||||
scope.launch {
|
||||
val result = it.value as SelectAppsResult.MultipleApps
|
||||
ConfigManager.getModulesForApp(scopeApp).forEach {
|
||||
ConfigManager.deactivateModule(scopeApp, it)
|
||||
}
|
||||
result.selected.forEach {
|
||||
Log.d(TAG, "Activate ${it.app.packageName} for $scopeApp")
|
||||
ConfigManager.activateModule(scopeApp, Module(it.app.packageName, it.app.sourceDir))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (viewModel.updateLoaderState) {
|
||||
is ProcessingState.Idle -> Unit
|
||||
is ProcessingState.Processing -> LoadingDialog()
|
||||
is ProcessingState.Done -> {
|
||||
val it = viewModel.updateLoaderState as ProcessingState.Done
|
||||
val updateSuccessfully = stringResource(R.string.manage_update_loader_successfully)
|
||||
val updateFailed = stringResource(R.string.manage_update_loader_failed)
|
||||
val copyError = stringResource(R.string.copy_error)
|
||||
LaunchedEffect(Unit) {
|
||||
it.result.onSuccess {
|
||||
snackbarHost.showSnackbar(updateSuccessfully)
|
||||
}.onFailure {
|
||||
val result = snackbarHost.showSnackbar(updateFailed, copyError)
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
val cm = lspApp.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cm.setPrimaryClip(ClipData.newPlainText("NPatch", it.toString()))
|
||||
}
|
||||
when (viewModel.updateLoaderState) {
|
||||
is ProcessingState.Idle -> Unit
|
||||
is ProcessingState.Processing -> LoadingDialog()
|
||||
is ProcessingState.Done -> {
|
||||
val it = viewModel.updateLoaderState as ProcessingState.Done
|
||||
val updateSuccessfully = stringResource(R.string.manage_update_loader_successfully)
|
||||
val updateFailed = stringResource(R.string.manage_update_loader_failed)
|
||||
val copyError = stringResource(R.string.copy_error)
|
||||
LaunchedEffect(Unit) {
|
||||
it.result.onSuccess {
|
||||
snackbarHost.showSnackbar(updateSuccessfully)
|
||||
}.onFailure {
|
||||
val result = snackbarHost.showSnackbar(updateFailed, copyError)
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
val cm = lspApp.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cm.setPrimaryClip(ClipData.newPlainText("NPatch", it.toString()))
|
||||
}
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.ClearUpdateLoaderResult)
|
||||
}
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.ClearUpdateLoaderResult)
|
||||
}
|
||||
}
|
||||
when (viewModel.optimizeState) {
|
||||
is ProcessingState.Idle -> Unit
|
||||
is ProcessingState.Processing -> LoadingDialog()
|
||||
is ProcessingState.Done -> {
|
||||
val it = viewModel.optimizeState as ProcessingState.Done
|
||||
val optimizeSucceed = stringResource(R.string.manage_optimize_successfully)
|
||||
val optimizeFailed = stringResource(R.string.manage_optimize_failed)
|
||||
LaunchedEffect(Unit) {
|
||||
snackbarHost.showSnackbar(if (it.result) optimizeSucceed else optimizeFailed)
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.ClearOptimizeResult)
|
||||
}
|
||||
}
|
||||
when (viewModel.optimizeState) {
|
||||
is ProcessingState.Idle -> Unit
|
||||
is ProcessingState.Processing -> LoadingDialog()
|
||||
is ProcessingState.Done -> {
|
||||
val it = viewModel.optimizeState as ProcessingState.Done
|
||||
val optimizeSucceed = stringResource(R.string.manage_optimize_successfully)
|
||||
val optimizeFailed = stringResource(R.string.manage_optimize_failed)
|
||||
LaunchedEffect(Unit) {
|
||||
snackbarHost.showSnackbar(if (it.result) optimizeSucceed else optimizeFailed)
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.ClearOptimizeResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 下拉刷新
|
||||
SwipeRefresh(
|
||||
state = rememberSwipeRefreshState(viewModel.isRefreshing),
|
||||
onRefresh = { viewModel.dispatch(AppManageViewModel.ViewAction.Refresh) },
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
if (viewModel.appList.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = run {
|
||||
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
||||
else stringResource(R.string.manage_no_apps)
|
||||
},
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
items(
|
||||
items = viewModel.appList,
|
||||
key = { it.first.app.packageName }
|
||||
) { (appInfo, patchConfig) ->
|
||||
val isRolling = patchConfig.useManager && patchConfig.lspConfig.VERSION_CODE >= Constants.MIN_ROLLING_VERSION_CODE
|
||||
val canUpdateLoader = !isRolling && (patchConfig.lspConfig.VERSION_CODE < LSPConfig.instance.VERSION_CODE || patchConfig.managerPackageName != BuildConfig.APPLICATION_ID)
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
LazyColumn(Modifier.fillMaxHeight()) {
|
||||
items(
|
||||
items = viewModel.appList,
|
||||
key = { it.first.app.packageName }
|
||||
) { (appInfo, patchConfig) ->
|
||||
val isRolling = patchConfig.useManager && patchConfig.lspConfig.VERSION_CODE >= Constants.MIN_ROLLING_VERSION_CODE
|
||||
val canUpdateLoader = !isRolling && (patchConfig.lspConfig.VERSION_CODE < LSPConfig.instance.VERSION_CODE || patchConfig.managerPackageName != BuildConfig.APPLICATION_ID)
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
AnywhereDropdown(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
onClick = { expanded = true },
|
||||
onLongClick = { expanded = true },
|
||||
surface = {
|
||||
AppItem(
|
||||
icon = NPackageManager.getIcon(appInfo),
|
||||
label = appInfo.label,
|
||||
packageName = appInfo.app.packageName,
|
||||
additionalContent = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
val patchText = if (patchConfig.useManager) {
|
||||
stringResource(R.string.patch_local)
|
||||
} else {
|
||||
stringResource(R.string.patch_integrated)
|
||||
}
|
||||
val patchColor = if (patchConfig.useManager) {
|
||||
MaterialTheme.colorScheme.secondary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.tertiary
|
||||
}
|
||||
val versionText = if (isRolling) {
|
||||
stringResource(R.string.manage_rolling)
|
||||
} else {
|
||||
patchConfig.lspConfig.VERSION_CODE.toString()
|
||||
}
|
||||
|
||||
AnywhereDropdown(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
onClick = { expanded = true },
|
||||
onLongClick = { expanded = true },
|
||||
surface = {
|
||||
AppItem(
|
||||
icon = NPackageManager.getIcon(appInfo),
|
||||
label = appInfo.label,
|
||||
packageName = appInfo.app.packageName,
|
||||
additionalContent = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
val patchText = if (patchConfig.useManager) {
|
||||
stringResource(R.string.patch_local)
|
||||
} else {
|
||||
stringResource(R.string.patch_integrated)
|
||||
}
|
||||
val patchColor = if (patchConfig.useManager) {
|
||||
MaterialTheme.colorScheme.secondary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.tertiary
|
||||
}
|
||||
val versionText = if (isRolling) {
|
||||
stringResource(R.string.manage_rolling)
|
||||
} else {
|
||||
patchConfig.lspConfig.VERSION_CODE.toString()
|
||||
}
|
||||
|
||||
Text(
|
||||
text = "$patchText $versionText",
|
||||
color = patchColor,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
if (canUpdateLoader) {
|
||||
with(LocalDensity.current) {
|
||||
val size = MaterialTheme.typography.bodySmall.fontSize * 1.2
|
||||
Icon(Icons.Filled.KeyboardCapslock, null, Modifier.size(size.toDp()))
|
||||
Text(
|
||||
text = "$patchText $versionText",
|
||||
color = patchColor,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
if (canUpdateLoader) {
|
||||
with(LocalDensity.current) {
|
||||
val size = MaterialTheme.typography.bodySmall.fontSize * 1.2
|
||||
Icon(Icons.Filled.KeyboardCapslock, null, Modifier.size(size.toDp()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = appInfo.label, color = MaterialTheme.colorScheme.primary) },
|
||||
onClick = {}, enabled = false
|
||||
)
|
||||
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
||||
if (canUpdateLoader || BuildConfig.DEBUG) {
|
||||
)
|
||||
}
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_update_loader)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.UpdateLoader(appInfo, patchConfig))
|
||||
}
|
||||
}
|
||||
text = { Text(text = appInfo.label, color = MaterialTheme.colorScheme.primary) },
|
||||
onClick = {}, enabled = false
|
||||
)
|
||||
}
|
||||
if (patchConfig.useManager) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_module_scope)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
scopeApp = appInfo.app.packageName
|
||||
val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet()
|
||||
val initialSelected = NPackageManager.appList.mapNotNullTo(ArrayList()) {
|
||||
if (activated.contains(it.app.packageName)) it.app.packageName else null
|
||||
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
||||
if (canUpdateLoader || BuildConfig.DEBUG) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_update_loader)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.UpdateLoader(appInfo, patchConfig))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if (patchConfig.useManager) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_module_scope)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
scopeApp = appInfo.app.packageName
|
||||
val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet()
|
||||
val initialSelected = NPackageManager.appList.mapNotNullTo(ArrayList()) {
|
||||
if (activated.contains(it.app.packageName)) it.app.packageName else null
|
||||
}
|
||||
navigator.navigate(SelectAppsScreenDestination(true, initialSelected))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_optimize)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
if (!ShizukuApi.isPermissionGranted) {
|
||||
snackbarHost.showSnackbar(shizukuUnavailable)
|
||||
} else {
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.PerformOptimize(appInfo))
|
||||
}
|
||||
navigator.navigate(SelectAppsScreenDestination(true, initialSelected))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_optimize)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
if (!ShizukuApi.isPermissionGranted) {
|
||||
snackbarHost.showSnackbar(shizukuUnavailable)
|
||||
} else {
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.PerformOptimize(appInfo))
|
||||
val uninstallSuccessfully = stringResource(R.string.manage_uninstall_successfully)
|
||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
scope.launch {
|
||||
snackbarHost.showSnackbar(uninstallSuccessfully)
|
||||
viewModel.dispatch(AppManageViewModel.ViewAction.Refresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
val uninstallSuccessfully = stringResource(R.string.manage_uninstall_successfully)
|
||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
scope.launch {
|
||||
snackbarHost.showSnackbar(uninstallSuccessfully)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.uninstall)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
val intent = Intent(Intent.ACTION_DELETE).apply {
|
||||
data = Uri.parse("package:${appInfo.app.packageName}")
|
||||
putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||
}
|
||||
launcher.launch(intent)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.uninstall)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
val intent = Intent(Intent.ACTION_DELETE).apply {
|
||||
data = Uri.parse("package:${appInfo.app.packageName}")
|
||||
putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||
}
|
||||
launcher.launch(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import androidx.compose.ui.text.buildAnnotatedString
|
|||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||
import org.lsposed.npatch.ui.component.AnywhereDropdown
|
||||
import org.lsposed.npatch.ui.component.AppItem
|
||||
import org.lsposed.npatch.R
|
||||
|
|
@ -32,75 +34,82 @@ import nkbe.util.NPackageManager
|
|||
fun ModuleManageBody() {
|
||||
val context = LocalContext.current
|
||||
val viewModel = viewModel<ModuleManageViewModel>()
|
||||
if (viewModel.appList.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = run {
|
||||
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
||||
else stringResource(R.string.manage_no_modules)
|
||||
},
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LazyColumn(Modifier.fillMaxHeight()) {
|
||||
items(
|
||||
items = viewModel.appList,
|
||||
key = { it.first.app.packageName }
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val settingsIntent = remember { NPackageManager.getSettingsIntent(it.first.app.packageName) }
|
||||
AnywhereDropdown(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
onClick = { settingsIntent?.let { context.startActivity(it) } },
|
||||
onLongClick = { expanded = true },
|
||||
surface = {
|
||||
AppItem(
|
||||
icon = NPackageManager.getIcon(it.first),
|
||||
label = it.first.label,
|
||||
packageName = it.first.app.packageName,
|
||||
additionalContent = {
|
||||
Text(
|
||||
text = it.second.description,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append(AnnotatedString("API", SpanStyle(color = MaterialTheme.colorScheme.secondary)))
|
||||
append(" ")
|
||||
append(it.second.api.toString())
|
||||
},
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
// 下拉刷新
|
||||
SwipeRefresh(
|
||||
state = rememberSwipeRefreshState(viewModel.isRefreshing),
|
||||
onRefresh = { viewModel.refresh() },
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
if (viewModel.appList.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = run {
|
||||
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
||||
else stringResource(R.string.manage_no_modules)
|
||||
},
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
items(
|
||||
items = viewModel.appList,
|
||||
key = { it.first.app.packageName }
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val settingsIntent = remember { NPackageManager.getSettingsIntent(it.first.app.packageName) }
|
||||
AnywhereDropdown(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
onClick = { settingsIntent?.let { context.startActivity(it) } },
|
||||
onLongClick = { expanded = true },
|
||||
surface = {
|
||||
AppItem(
|
||||
icon = NPackageManager.getIcon(it.first),
|
||||
label = it.first.label,
|
||||
packageName = it.first.app.packageName,
|
||||
additionalContent = {
|
||||
Text(
|
||||
text = it.second.description,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append(AnnotatedString("API", SpanStyle(color = MaterialTheme.colorScheme.secondary)))
|
||||
append(" ")
|
||||
append(it.second.api.toString())
|
||||
},
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontFamily = FontFamily.Serif,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = it.first.label, color = MaterialTheme.colorScheme.primary) },
|
||||
onClick = {}, enabled = false
|
||||
)
|
||||
if (settingsIntent != null) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_module_settings)) },
|
||||
onClick = { context.startActivity(settingsIntent) }
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_app_info)) },
|
||||
onClick = {
|
||||
val intent = Intent(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", it.first.app.packageName, null)
|
||||
)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = it.first.label, color = MaterialTheme.colorScheme.primary) },
|
||||
onClick = {}, enabled = false
|
||||
)
|
||||
if (settingsIntent != null) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_module_settings)) },
|
||||
onClick = { context.startActivity(settingsIntent) }
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.manage_app_info)) },
|
||||
onClick = {
|
||||
val intent = Intent(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", it.first.app.packageName, null)
|
||||
)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class AppManageViewModel : ViewModel() {
|
|||
object ClearUpdateLoaderResult : ViewAction()
|
||||
data class PerformOptimize(val appInfo: AppInfo) : ViewAction()
|
||||
object ClearOptimizeResult : ViewAction()
|
||||
object RefreshList : ViewAction()
|
||||
object Refresh : ViewAction()
|
||||
}
|
||||
|
||||
// 手動管理狀態,避免實時響應系統廣播導致列表跳動
|
||||
|
|
@ -98,7 +98,16 @@ class AppManageViewModel : ViewModel() {
|
|||
is ViewAction.ClearUpdateLoaderResult -> updateLoaderState = ProcessingState.Idle
|
||||
is ViewAction.PerformOptimize -> performOptimize(action.appInfo)
|
||||
is ViewAction.ClearOptimizeResult -> optimizeState = ProcessingState.Idle
|
||||
is ViewAction.RefreshList -> loadData(silent = false)
|
||||
is ViewAction.Refresh -> {
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true
|
||||
withContext(Dispatchers.IO) {
|
||||
NPackageManager.fetchAppList()
|
||||
}
|
||||
loadData(silent = true)
|
||||
isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@ package org.lsposed.npatch.ui.viewmodel.manage
|
|||
import android.util.Log
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import nkbe.util.NPackageManager
|
||||
|
||||
class ModuleManageViewModel : ViewModel() {
|
||||
|
|
@ -12,6 +18,9 @@ class ModuleManageViewModel : ViewModel() {
|
|||
private const val TAG = "ModuleManageViewModel"
|
||||
}
|
||||
|
||||
var isRefreshing by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
class XposedInfo(
|
||||
val api: Int,
|
||||
val description: String,
|
||||
|
|
@ -30,4 +39,15 @@ class ModuleManageViewModel : ViewModel() {
|
|||
Log.d(TAG, "Loaded ${it.size} Xposed modules")
|
||||
}
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
if (isRefreshing) return
|
||||
viewModelScope.launch {
|
||||
isRefreshing = true
|
||||
withContext(Dispatchers.IO) {
|
||||
NPackageManager.fetchAppList()
|
||||
}
|
||||
isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue