manager: Add groups and caps for profile

This commit is contained in:
weishu
2023-06-03 15:00:42 +08:00
parent 89f6cd044e
commit 68d639e325
6 changed files with 341 additions and 26 deletions

View File

@@ -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) })
}
}
}
}
}