Skip to content

Commit 9336779

Browse files
lamprosebackslashxx
authored andcommitted
manager: Add sort options on module's appbar (tiann#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.
1 parent a0c1e3f commit 9336779

File tree

4 files changed

+102
-34
lines changed

4 files changed

+102
-34
lines changed

manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,22 @@ import androidx.compose.foundation.selection.toggleable
3232
import androidx.compose.material.icons.Icons
3333
import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
3434
import androidx.compose.material.icons.filled.Add
35+
import androidx.compose.material.icons.filled.MoreVert
3536
import androidx.compose.material.icons.outlined.PlayArrow
3637
import androidx.compose.material.icons.outlined.Download
3738
import androidx.compose.material.icons.outlined.Delete
3839
import androidx.compose.material3.Button
3940
import androidx.compose.material3.ButtonDefaults
41+
import androidx.compose.material3.Checkbox
42+
import androidx.compose.material3.DropdownMenu
43+
import androidx.compose.material3.DropdownMenuItem
4044
import androidx.compose.material3.ElevatedCard
4145
import androidx.compose.material3.ExperimentalMaterial3Api
4246
import androidx.compose.material3.ExtendedFloatingActionButton
4347
import androidx.compose.material3.FilledTonalButton
4448
import androidx.compose.material3.HorizontalDivider
4549
import androidx.compose.material3.Icon
50+
import androidx.compose.material3.IconButton
4651
import androidx.compose.material3.MaterialTheme
4752
import androidx.compose.material3.Scaffold
4853
import androidx.compose.material3.SnackbarDuration
@@ -110,9 +115,13 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
110115
val viewModel = viewModel<ModuleViewModel>()
111116
val context = LocalContext.current
112117
val snackBarHost = LocalSnackbarHost.current
118+
val scope = rememberCoroutineScope()
119+
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
113120

114121
LaunchedEffect(Unit) {
115122
if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {
123+
viewModel.sortEnabledFirst = prefs.getBoolean("module_sort_enabled_first", false)
124+
viewModel.sortActionFirst = prefs.getBoolean("module_sort_action_first", false)
116125
viewModel.fetchModuleList()
117126
}
118127
}
@@ -127,6 +136,57 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
127136
Scaffold(
128137
topBar = {
129138
TopAppBar(
139+
actions = {
140+
var showDropdown by remember { mutableStateOf(false) }
141+
142+
IconButton(
143+
onClick = { showDropdown = true },
144+
) {
145+
Icon(
146+
imageVector = Icons.Filled.MoreVert,
147+
contentDescription = stringResource(id = R.string.settings)
148+
)
149+
150+
DropdownMenu(expanded = showDropdown, onDismissRequest = {
151+
showDropdown = false
152+
}) {
153+
DropdownMenuItem(text = {
154+
Text(stringResource(R.string.module_sort_action_first))
155+
}, trailingIcon = {
156+
Checkbox(viewModel.sortActionFirst, null)
157+
}, onClick = {
158+
viewModel.sortActionFirst =
159+
!viewModel.sortActionFirst
160+
prefs.edit()
161+
.putBoolean(
162+
"module_sort_action_first",
163+
viewModel.sortActionFirst
164+
)
165+
.apply()
166+
scope.launch {
167+
viewModel.fetchModuleList()
168+
}
169+
})
170+
DropdownMenuItem(text = {
171+
Text(stringResource(R.string.module_sort_enabled_first))
172+
}, trailingIcon = {
173+
Checkbox(viewModel.sortEnabledFirst, null)
174+
}, onClick = {
175+
viewModel.sortEnabledFirst =
176+
!viewModel.sortEnabledFirst
177+
prefs.edit()
178+
.putBoolean(
179+
"module_sort_enabled_first",
180+
viewModel.sortEnabledFirst
181+
)
182+
.apply()
183+
scope.launch {
184+
viewModel.fetchModuleList()
185+
}
186+
})
187+
}
188+
}
189+
},
130190
scrollBehavior = scrollBehavior,
131191
title = { Text(stringResource(R.string.module)) },
132192
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
@@ -493,8 +553,8 @@ fun ModuleItem(
493553
onValueChange = { onClick(module) }
494554
)
495555
} else {
496-
this
497-
}
556+
this
557+
}
498558
}
499559
.padding(22.dp, 18.dp, 22.dp, 12.dp)
500560
) {
@@ -577,24 +637,24 @@ fun ModuleItem(
577637
FilledTonalButton(
578638
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
579639
onClick = {
580-
navigator.navigate(ExecuteModuleActionScreenDestination(module.id))
581-
viewModel.markNeedRefresh()
640+
navigator.navigate(ExecuteModuleActionScreenDestination(module.id))
641+
viewModel.markNeedRefresh()
582642
},
583643
contentPadding = ButtonDefaults.TextButtonContentPadding
584644
) {
585645
Icon(
586-
modifier = Modifier.size(20.dp),
646+
modifier = Modifier.size(20.dp),
587647
imageVector = Icons.Outlined.PlayArrow,
588648
contentDescription = null
589649
)
590-
if (!module.hasWebUi && updateUrl.isEmpty()) {
650+
if (!module.hasWebUi && updateUrl.isEmpty()) {
591651
Text(
592-
modifier = Modifier.padding(start = 7.dp),
652+
modifier = Modifier.padding(start = 7.dp),
593653
text = stringResource(R.string.action),
594654
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
595655
fontSize = MaterialTheme.typography.labelMedium.fontSize
596656
)
597-
}
657+
}
598658
}
599659

600660
Spacer(modifier = Modifier.weight(0.1f, true))
@@ -608,16 +668,16 @@ fun ModuleItem(
608668
contentPadding = ButtonDefaults.TextButtonContentPadding
609669
) {
610670
Icon(
611-
modifier = Modifier.size(20.dp),
671+
modifier = Modifier.size(20.dp),
612672
imageVector = Icons.AutoMirrored.Outlined.Wysiwyg,
613673
contentDescription = null
614674
)
615675
if (!module.hasActionScript && updateUrl.isEmpty()) {
616676
Text(
617-
modifier = Modifier.padding(start = 7.dp),
618-
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
619-
fontSize = MaterialTheme.typography.labelMedium.fontSize,
620-
text = stringResource(R.string.open)
677+
modifier = Modifier.padding(start = 7.dp),
678+
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
679+
fontSize = MaterialTheme.typography.labelMedium.fontSize,
680+
text = stringResource(R.string.open)
621681
)
622682
}
623683
}
@@ -632,19 +692,19 @@ fun ModuleItem(
632692
shape = ButtonDefaults.textShape,
633693
contentPadding = ButtonDefaults.TextButtonContentPadding
634694
) {
635-
Icon(
636-
modifier = Modifier.size(20.dp),
637-
imageVector = Icons.Outlined.Download,
638-
contentDescription = null
639-
)
640-
if (!module.hasActionScript || !module.hasWebUi) {
695+
Icon(
696+
modifier = Modifier.size(20.dp),
697+
imageVector = Icons.Outlined.Download,
698+
contentDescription = null
699+
)
700+
if (!module.hasActionScript || !module.hasWebUi) {
641701
Text(
642-
modifier = Modifier.padding(start = 7.dp),
702+
modifier = Modifier.padding(start = 7.dp),
643703
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
644704
fontSize = MaterialTheme.typography.labelMedium.fontSize,
645705
text = stringResource(R.string.module_update)
646706
)
647-
}
707+
}
648708
}
649709

650710
Spacer(modifier = Modifier.weight(0.1f, true))
@@ -656,19 +716,19 @@ fun ModuleItem(
656716
onClick = { onUninstall(module) },
657717
contentPadding = ButtonDefaults.TextButtonContentPadding
658718
) {
659-
Icon(
660-
modifier = Modifier.size(20.dp),
661-
imageVector = Icons.Outlined.Delete,
662-
contentDescription = null
663-
)
664-
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
665-
Text(
666-
modifier = Modifier.padding(start = 7.dp),
719+
Icon(
720+
modifier = Modifier.size(20.dp),
721+
imageVector = Icons.Outlined.Delete,
722+
contentDescription = null
723+
)
724+
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
725+
Text(
726+
modifier = Modifier.padding(start = 7.dp),
667727
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
668728
fontSize = MaterialTheme.typography.labelMedium.fontSize,
669729
text = stringResource(R.string.uninstall)
670730
)
671-
}
731+
}
672732
}
673733
}
674734
}

manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import me.weishu.kernelsu.ui.util.listModules
1414
import me.weishu.kernelsu.ui.util.overlayFsAvailable
1515
import org.json.JSONArray
1616
import org.json.JSONObject
17-
import java.text.Collator
18-
import java.util.Locale
1917

2018
class ModuleViewModel : ViewModel() {
2119

@@ -52,8 +50,14 @@ class ModuleViewModel : ViewModel() {
5250
var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
5351
private set
5452

53+
var sortEnabledFirst by mutableStateOf(false)
54+
var sortActionFirst by mutableStateOf(false)
5555
val moduleList by derivedStateOf {
56-
val comparator = compareBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
56+
val comparator =
57+
compareBy<ModuleInfo>(
58+
{ if (sortEnabledFirst) !it.enabled else 0 },
59+
{ if (sortActionFirst) !it.hasWebUi && !it.hasActionScript else 0 },
60+
{ it.id })
5761
modules.sortedWith(comparator).also {
5862
isRefreshing = false
5963
}
@@ -159,4 +163,4 @@ class ModuleViewModel : ViewModel() {
159163

160164
return Triple(zipUrl, version, changelog)
161165
}
162-
}
166+
}

manager/app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
<string name="module_failed_to_disable">无法禁用模块: %s</string>
2222
<string name="module_empty">没有安装模块</string>
2323
<string name="module">模块</string>
24+
<string name="module_sort_action_first">可执行优先</string>
25+
<string name="module_sort_enabled_first">已启用优先</string>
2426
<string name="uninstall">卸载</string>
2527
<string name="module_install">安装</string>
2628
<string name="install">安装</string>

manager/app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
<string name="module_failed_to_disable">Failed to disable module: %s</string>
2424
<string name="module_empty">No module installed</string>
2525
<string name="module">Module</string>
26+
<string name="module_sort_action_first">Sort (Action First)</string>
27+
<string name="module_sort_enabled_first">Sort (Enabled First)</string>
2628
<string name="uninstall">Uninstall</string>
2729
<string name="module_install">Install</string>
2830
<string name="install">Install</string>

0 commit comments

Comments
 (0)