manager: Add groups and caps for profile
This commit is contained in:
@@ -1,15 +1,27 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package me.weishu.kernelsu.ui.component.profile
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.ArrowDropUp
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -21,8 +33,15 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||
import com.maxkeppeler.sheets.list.ListDialog
|
||||
import com.maxkeppeler.sheets.list.models.ListOption
|
||||
import com.maxkeppeler.sheets.list.models.ListSelection
|
||||
import me.weishu.kernelsu.Natives
|
||||
import me.weishu.kernelsu.R
|
||||
import me.weishu.kernelsu.profile.Capabilities
|
||||
import me.weishu.kernelsu.profile.Groups
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -53,7 +72,9 @@ fun RootProfileConfig(
|
||||
onExpandedChange = { expanded = !expanded }
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.menuAnchor(),
|
||||
modifier = Modifier
|
||||
.menuAnchor()
|
||||
.fillMaxWidth(),
|
||||
readOnly = true,
|
||||
label = { Text(stringResource(R.string.profile_namespace)) },
|
||||
value = currentNamespace,
|
||||
@@ -94,6 +115,7 @@ fun RootProfileConfig(
|
||||
|
||||
ListItem(headlineContent = {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = { Text("uid") },
|
||||
value = profile.uid.toString(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
@@ -104,7 +126,12 @@ fun RootProfileConfig(
|
||||
}.let { filtered ->
|
||||
filtered.ifEmpty { "0" }
|
||||
}.let { value ->
|
||||
onProfileChange(profile.copy(uid = value.toInt(), rootUseDefault = false))
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
uid = value.toInt(),
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +141,7 @@ fun RootProfileConfig(
|
||||
|
||||
ListItem(headlineContent = {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = { Text("gid") },
|
||||
value = profile.gid.toString(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
@@ -124,42 +152,173 @@ fun RootProfileConfig(
|
||||
}.let { filtered ->
|
||||
filtered.ifEmpty { "0" }
|
||||
}.let { value ->
|
||||
onProfileChange(profile.copy(gid = value.toInt(), rootUseDefault = false))
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
gid = value.toInt(),
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
ListItem(headlineContent = {
|
||||
OutlinedTextField(
|
||||
label = { Text("groups") },
|
||||
value = profile.groups.joinToString(","),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
onValueChange = { s ->
|
||||
if (s.isNotEmpty()) {
|
||||
s.filter { symbol ->
|
||||
symbol.isDigit() || symbol == ','
|
||||
}.let { filtered ->
|
||||
filtered.ifEmpty { "0" }
|
||||
}.let { value ->
|
||||
val groups = value.split(',').filter { it.isNotEmpty() }.map { it.toInt() }
|
||||
onProfileChange(profile.copy(groups = groups, rootUseDefault = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
val selectedGroups = profile.groups.mapNotNull { id ->
|
||||
Groups.values().find { it.gid == id }
|
||||
}
|
||||
GroupsPanel(selectedGroups) {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
groups = it.map { group -> group.gid }.ifEmpty { listOf(0) },
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
val selectedCaps = profile.capabilities.mapNotNull { id ->
|
||||
Capabilities.values().find { it.cap == id }
|
||||
}
|
||||
CapsPanel(selectedCaps) {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
capabilities = it.map { cap -> cap.cap },
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ListItem(headlineContent = {
|
||||
OutlinedTextField(
|
||||
label = { Text("context") },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = { Text("SELinux context") },
|
||||
value = profile.context,
|
||||
onValueChange = {
|
||||
onProfileChange(profile.copy(context = it, rootUseDefault = false))
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: List<Groups>) -> Unit) {
|
||||
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showDialog) {
|
||||
val groups = Groups.values()
|
||||
val options = groups.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
selected = selected.contains(value),
|
||||
)
|
||||
}
|
||||
|
||||
val selection = mutableListOf<Groups>()
|
||||
ListDialog(
|
||||
state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
Log.i("mylog", "onFinishedRequest")
|
||||
closeSelection(selection)
|
||||
}, onCloseRequest = {
|
||||
showDialog = false
|
||||
Log.i("mylog", "onCloseRequest")
|
||||
}),
|
||||
selection = ListSelection.Multiple(
|
||||
showCheckBoxes = true,
|
||||
options = options
|
||||
) { indecies, _ ->
|
||||
// Handle selection
|
||||
indecies.forEach { index ->
|
||||
val group = groups[index]
|
||||
selection.add(group)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedCard(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
.clickable {
|
||||
showDialog = true
|
||||
}) {
|
||||
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text("groups")
|
||||
FlowRow {
|
||||
selected.forEach { group ->
|
||||
AssistChip(
|
||||
modifier = Modifier.padding(3.dp),
|
||||
onClick = { /*TODO*/ },
|
||||
label = { Text(group.display) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun CapsPanel(
|
||||
selected: List<Capabilities>,
|
||||
closeSelection: (selection: List<Capabilities>) -> Unit
|
||||
) {
|
||||
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showDialog) {
|
||||
val caps = Capabilities.values()
|
||||
val options = caps.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
selected = selected.contains(value),
|
||||
)
|
||||
}
|
||||
|
||||
val selection = mutableListOf<Capabilities>()
|
||||
ListDialog(
|
||||
state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
closeSelection(selection)
|
||||
}, onCloseRequest = {
|
||||
showDialog = false
|
||||
}),
|
||||
selection = ListSelection.Multiple(
|
||||
showCheckBoxes = true,
|
||||
options = options
|
||||
) { indecies, _ ->
|
||||
// Handle selection
|
||||
indecies.forEach { index ->
|
||||
val group = caps[index]
|
||||
selection.add(group)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedCard(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
.clickable {
|
||||
showDialog = true
|
||||
}) {
|
||||
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text("Capabilities")
|
||||
FlowRow {
|
||||
selected.forEach { group ->
|
||||
AssistChip(
|
||||
modifier = Modifier.padding(3.dp),
|
||||
onClick = { /*TODO*/ },
|
||||
label = { Text(group.display) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user