manager: support search module list (#2331)

This commit is contained in:
5ec1cff
2024-12-31 16:30:58 +08:00
committed by GitHub
parent 02ad724406
commit 0a617959f9
2 changed files with 21 additions and 17 deletions

View File

@@ -56,7 +56,6 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
@@ -67,7 +66,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -95,6 +93,7 @@ import kotlinx.coroutines.withContext
import me.weishu.kernelsu.Natives import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmResult import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.component.rememberConfirmDialog import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.util.DownloadListener import me.weishu.kernelsu.ui.util.DownloadListener
@@ -139,8 +138,12 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( SearchAppBar(
actions = { title = { Text(stringResource(R.string.module)) },
searchText = viewModel.search,
onSearchTextChange = { viewModel.search = it },
onClearClick = { viewModel.search = "" },
dropdownContent = {
var showDropdown by remember { mutableStateOf(false) } var showDropdown by remember { mutableStateOf(false) }
IconButton( IconButton(
@@ -192,8 +195,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
} }
}, },
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
title = { Text(stringResource(R.string.module)) },
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) )
}, },
floatingActionButton = { floatingActionButton = {
@@ -458,7 +459,6 @@ private fun ModuleList(
else -> { else -> {
items(viewModel.moduleList) { module -> items(viewModel.moduleList) { module ->
var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val updatedModule by produceState(initialValue = Triple("", "", "")) { val updatedModule by produceState(initialValue = Triple("", "", "")) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
@@ -469,7 +469,6 @@ private fun ModuleList(
ModuleItem( ModuleItem(
navigator = navigator, navigator = navigator,
module = module, module = module,
isChecked = isChecked,
updateUrl = updatedModule.first, updateUrl = updatedModule.first,
onUninstall = { onUninstall = {
scope.launch { onModuleUninstall(module) } scope.launch { onModuleUninstall(module) }
@@ -478,11 +477,10 @@ private fun ModuleList(
scope.launch { scope.launch {
val success = loadingDialog.withLoading { val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
toggleModule(module.id, !isChecked) toggleModule(module.id, !module.enabled)
} }
} }
if (success) { if (success) {
isChecked = it
viewModel.fetchModuleList() viewModel.fetchModuleList()
val result = snackBarHost.showSnackbar( val result = snackBarHost.showSnackbar(
@@ -494,7 +492,7 @@ private fun ModuleList(
reboot() reboot()
} }
} else { } else {
val message = if (isChecked) failedDisable else failedEnable val message = if (module.enabled) failedDisable else failedEnable
snackBarHost.showSnackbar(message.format(module.name)) snackBarHost.showSnackbar(message.format(module.name))
} }
} }
@@ -530,7 +528,6 @@ private fun ModuleList(
fun ModuleItem( fun ModuleItem(
navigator: DestinationsNavigator, navigator: DestinationsNavigator,
module: ModuleViewModel.ModuleInfo, module: ModuleViewModel.ModuleInfo,
isChecked: Boolean,
updateUrl: String, updateUrl: String,
onUninstall: (ModuleViewModel.ModuleInfo) -> Unit, onUninstall: (ModuleViewModel.ModuleInfo) -> Unit,
onCheckChanged: (Boolean) -> Unit, onCheckChanged: (Boolean) -> Unit,
@@ -550,7 +547,7 @@ fun ModuleItem(
.run { .run {
if (module.hasWebUi) { if (module.hasWebUi) {
toggleable( toggleable(
value = isChecked, value = module.enabled,
interactionSource = interactionSource, interactionSource = interactionSource,
role = Role.Button, role = Role.Button,
indication = indication, indication = indication,
@@ -606,7 +603,7 @@ fun ModuleItem(
) { ) {
Switch( Switch(
enabled = !module.update, enabled = !module.update,
checked = isChecked, checked = module.enabled,
onCheckedChange = onCheckChanged, onCheckedChange = onCheckChanged,
interactionSource = if (!module.hasWebUi) interactionSource else null interactionSource = if (!module.hasWebUi) interactionSource else null
) )
@@ -756,5 +753,5 @@ fun ModuleItemPreview() {
hasWebUi = false, hasWebUi = false,
hasActionScript = false hasActionScript = false
) )
ModuleItem(EmptyDestinationsNavigator, module, true, "", {}, {}, {}, {}) ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {})
} }

View File

@@ -10,10 +10,13 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.weishu.kernelsu.ui.util.HanziToPinyin
import me.weishu.kernelsu.ui.util.listModules import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.overlayFsAvailable import me.weishu.kernelsu.ui.util.overlayFsAvailable
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.text.Collator
import java.util.Locale
class ModuleViewModel : ViewModel() { class ModuleViewModel : ViewModel() {
@@ -46,6 +49,7 @@ class ModuleViewModel : ViewModel() {
var isRefreshing by mutableStateOf(false) var isRefreshing by mutableStateOf(false)
private set private set
var search by mutableStateOf("")
var isOverlayAvailable by mutableStateOf(overlayFsAvailable()) var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
private set private set
@@ -57,8 +61,11 @@ class ModuleViewModel : ViewModel() {
compareBy<ModuleInfo>( compareBy<ModuleInfo>(
{ if (sortEnabledFirst) !it.enabled else 0 }, { if (sortEnabledFirst) !it.enabled else 0 },
{ if (sortActionFirst) !it.hasWebUi && !it.hasActionScript else 0 }, { if (sortActionFirst) !it.hasWebUi && !it.hasActionScript else 0 },
{ it.id }) ).thenBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
modules.sortedWith(comparator).also { modules.filter {
it.id.contains(search, true) || it.name.contains(search, true) || HanziToPinyin.getInstance()
.toPinyinString(it.name).contains(search, true)
}.sortedWith(comparator).also {
isRefreshing = false isRefreshing = false
} }
} }