manager: Add sort options on module's appbar (#2308)

module list will be sorted by options when these are enabled:

![83d5cd3d23b8f6c36b52e731f5e21a97](https://github.com/user-attachments/assets/eaadc1a3-21c6-4b73-a55f-206b6faa7d2d)
It will be very friendly and convenient  when manager has many modules.
This commit is contained in:
Michelle Rodriguez
2024-12-25 19:48:28 +08:00
committed by GitHub
parent 6eba848228
commit 2e2d9b9c04
4 changed files with 102 additions and 34 deletions

View File

@@ -32,17 +32,22 @@ import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Wysiwyg import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.outlined.PlayArrow import androidx.compose.material.icons.outlined.PlayArrow
import androidx.compose.material.icons.outlined.Download import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration
@@ -110,9 +115,13 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<ModuleViewModel>() val viewModel = viewModel<ModuleViewModel>()
val context = LocalContext.current val context = LocalContext.current
val snackBarHost = LocalSnackbarHost.current val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) { if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {
viewModel.sortEnabledFirst = prefs.getBoolean("module_sort_enabled_first", false)
viewModel.sortActionFirst = prefs.getBoolean("module_sort_action_first", false)
viewModel.fetchModuleList() viewModel.fetchModuleList()
} }
} }
@@ -127,6 +136,57 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
actions = {
var showDropdown by remember { mutableStateOf(false) }
IconButton(
onClick = { showDropdown = true },
) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
DropdownMenuItem(text = {
Text(stringResource(R.string.module_sort_action_first))
}, trailingIcon = {
Checkbox(viewModel.sortActionFirst, null)
}, onClick = {
viewModel.sortActionFirst =
!viewModel.sortActionFirst
prefs.edit()
.putBoolean(
"module_sort_action_first",
viewModel.sortActionFirst
)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
})
DropdownMenuItem(text = {
Text(stringResource(R.string.module_sort_enabled_first))
}, trailingIcon = {
Checkbox(viewModel.sortEnabledFirst, null)
}, onClick = {
viewModel.sortEnabledFirst =
!viewModel.sortEnabledFirst
prefs.edit()
.putBoolean(
"module_sort_enabled_first",
viewModel.sortEnabledFirst
)
.apply()
scope.launch {
viewModel.fetchModuleList()
}
})
}
}
},
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
title = { Text(stringResource(R.string.module)) }, title = { Text(stringResource(R.string.module)) },
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal) windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)

View File

@@ -14,8 +14,6 @@ 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() {
@@ -52,8 +50,14 @@ class ModuleViewModel : ViewModel() {
var isOverlayAvailable by mutableStateOf(overlayFsAvailable()) var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
private set private set
var sortEnabledFirst by mutableStateOf(false)
var sortActionFirst by mutableStateOf(false)
val moduleList by derivedStateOf { val moduleList by derivedStateOf {
val comparator = compareBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id) val comparator =
compareBy<ModuleInfo>(
{ if (sortEnabledFirst) !it.enabled else 0 },
{ if (sortActionFirst) !it.hasWebUi && !it.hasActionScript else 0 },
{ it.id })
modules.sortedWith(comparator).also { modules.sortedWith(comparator).also {
isRefreshing = false isRefreshing = false
} }

View File

@@ -21,6 +21,8 @@
<string name="module_failed_to_disable">无法禁用模块: %s</string> <string name="module_failed_to_disable">无法禁用模块: %s</string>
<string name="module_empty">没有安装模块</string> <string name="module_empty">没有安装模块</string>
<string name="module">模块</string> <string name="module">模块</string>
<string name="module_sort_action_first">可执行优先</string>
<string name="module_sort_enabled_first">已启用优先</string>
<string name="uninstall">卸载</string> <string name="uninstall">卸载</string>
<string name="module_install">安装</string> <string name="module_install">安装</string>
<string name="install">安装</string> <string name="install">安装</string>

View File

@@ -23,6 +23,8 @@
<string name="module_failed_to_disable">Failed to disable module: %s</string> <string name="module_failed_to_disable">Failed to disable module: %s</string>
<string name="module_empty">No module installed</string> <string name="module_empty">No module installed</string>
<string name="module">Module</string> <string name="module">Module</string>
<string name="module_sort_action_first">Sort (Action First)</string>
<string name="module_sort_enabled_first">Sort (Enabled First)</string>
<string name="uninstall">Uninstall</string> <string name="uninstall">Uninstall</string>
<string name="module_install">Install</string> <string name="module_install">Install</string>
<string name="install">Install</string> <string name="install">Install</string>