manager: support search module list (#2331)

This commit is contained in:
5ec1cff
2024-12-31 16:30:58 +08:00
committed by Rifat Azad
parent b1174448ac
commit cae7693ceb
2 changed files with 29 additions and 21 deletions
@@ -55,7 +55,6 @@ 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.TextButton import androidx.compose.material3.TextButton
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
@@ -96,6 +95,7 @@ import com.rifsxd.ksunext.R
import com.rifsxd.ksunext.ui.component.ConfirmResult import com.rifsxd.ksunext.ui.component.ConfirmResult
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
import com.rifsxd.ksunext.ui.component.rememberLoadingDialog import com.rifsxd.ksunext.ui.component.rememberLoadingDialog
import com.rifsxd.ksunext.ui.component.SearchAppBar
import com.rifsxd.ksunext.ui.util.* import com.rifsxd.ksunext.ui.util.*
import com.rifsxd.ksunext.ui.util.DownloadListener import com.rifsxd.ksunext.ui.util.DownloadListener
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
@@ -145,8 +145,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(
onClick = { showDropdown = true }, onClick = { showDropdown = true },
@@ -203,9 +207,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
} }
} }
}, },
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior
title = { Text(stringResource(R.string.module)) },
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) )
}, },
floatingActionButton = { floatingActionButton = {
@@ -535,7 +537,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) {
@@ -546,7 +547,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) }
@@ -558,11 +558,10 @@ private fun ModuleList(
scope.launch { scope.launch {
val success = loadingDialog.withLoading { val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
toggleModule(module.dirId, !isChecked) toggleModule(module.dirId, !module.enabled)
} }
} }
if (success) { if (success) {
isChecked = it
viewModel.fetchModuleList() viewModel.fetchModuleList()
val result = snackBarHost.showSnackbar( val result = snackBarHost.showSnackbar(
@@ -574,7 +573,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))
} }
} }
@@ -610,7 +609,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,
onRestore: (ModuleViewModel.ModuleInfo) -> Unit, onRestore: (ModuleViewModel.ModuleInfo) -> Unit,
@@ -631,7 +629,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,
@@ -687,7 +685,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
) )
@@ -826,7 +824,7 @@ fun ModuleItem(
imageVector = Icons.Outlined.Delete, imageVector = Icons.Outlined.Delete,
contentDescription = null contentDescription = null
) )
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) { if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
Text( Text(
modifier = Modifier.padding(start = 7.dp), modifier = Modifier.padding(start = 7.dp),
fontFamily = MaterialTheme.typography.labelMedium.fontFamily, fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
@@ -859,5 +857,5 @@ fun ModuleItemPreview() {
hasActionScript = false, hasActionScript = false,
dirId = "dirId" dirId = "dirId"
) )
ModuleItem(EmptyDestinationsNavigator, module, true, "", {}, {}, {}, {}, {}) ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}, {})
} }
@@ -10,6 +10,9 @@ 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 java.text.Collator
import java.util.Locale
import com.rifsxd.ksunext.ui.util.HanziToPinyin
import com.rifsxd.ksunext.ui.util.listModules import com.rifsxd.ksunext.ui.util.listModules
import com.rifsxd.ksunext.ui.util.overlayFsAvailable import com.rifsxd.ksunext.ui.util.overlayFsAvailable
import org.json.JSONArray import org.json.JSONArray
@@ -51,6 +54,8 @@ class ModuleViewModel : ViewModel() {
var isRefreshing by mutableStateOf(false) var isRefreshing by mutableStateOf(false)
private set private set
var search by mutableStateOf("")
var sortAToZ by mutableStateOf(false) var sortAToZ by mutableStateOf(false)
var sortZToA by mutableStateOf(false) var sortZToA by mutableStateOf(false)
@@ -59,8 +64,13 @@ class ModuleViewModel : ViewModel() {
sortAToZ -> compareBy<ModuleInfo> { it.name.lowercase() } sortAToZ -> compareBy<ModuleInfo> { it.name.lowercase() }
sortZToA -> compareByDescending<ModuleInfo> { it.name.lowercase() } sortZToA -> compareByDescending<ModuleInfo> { it.name.lowercase() }
else -> compareBy<ModuleInfo> { it.dirId } else -> compareBy<ModuleInfo> { it.dirId }
} }.thenBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
modules.sortedWith(comparator).also {
modules.filter {
it.id.contains(search, ignoreCase = true) ||
it.name.contains(search, ignoreCase = true) ||
HanziToPinyin.getInstance().toPinyinString(it.name).contains(search, ignoreCase = true)
}.sortedWith(comparator).also {
isRefreshing = false isRefreshing = false
} }
} }
@@ -83,7 +93,7 @@ class ModuleViewModel : ViewModel() {
kotlin.runCatching { kotlin.runCatching {
isOverlayAvailable = overlayFsAvailable() isOverlayAvailable = overlayFsAvailable()
val result = listModules() val result = listModules()
Log.i(TAG, "result: $result") Log.i(TAG, "result: $result")
@@ -167,4 +177,4 @@ class ModuleViewModel : ViewModel() {
return Triple(zipUrl, version, changelog) return Triple(zipUrl, version, changelog)
} }
} }