manager: several UI improvements (#515)

This commit is contained in:
Nullptr
2023-05-17 09:34:08 +08:00
committed by GitHub
parent d162221fac
commit 31a9189d80
3 changed files with 119 additions and 95 deletions

View File

@@ -2,9 +2,13 @@ package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.layout.Column
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.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
@@ -37,7 +41,7 @@ fun RootProfileConfig(
)
}
var namespaceBoxExpanded by remember { mutableStateOf(false) }
var expanded by remember { mutableStateOf(false) }
val currentNamespace = when (profile.namespace) {
RootProfile.Namespace.Inherited -> stringResource(R.string.profile_namespace_inherited)
RootProfile.Namespace.Global -> stringResource(R.string.profile_namespace_global)
@@ -45,8 +49,8 @@ fun RootProfileConfig(
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = namespaceBoxExpanded,
onExpandedChange = { namespaceBoxExpanded = it }
expanded = expanded,
onExpandedChange = { expanded = !expanded }
) {
OutlinedTextField(
modifier = Modifier.menuAnchor(),
@@ -54,30 +58,34 @@ fun RootProfileConfig(
label = { Text(stringResource(R.string.profile_namespace)) },
value = currentNamespace,
onValueChange = {},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
ExposedDropdownMenu(
expanded = namespaceBoxExpanded,
onDismissRequest = { namespaceBoxExpanded = false }
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
onClick = {
onProfileChange(profile.copy(namespace = RootProfile.Namespace.Inherited))
namespaceBoxExpanded = false
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_global)) },
onClick = {
onProfileChange(profile.copy(namespace = RootProfile.Namespace.Global))
namespaceBoxExpanded = false
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_individual)) },
onClick = {
onProfileChange(profile.copy(namespace = RootProfile.Namespace.Individual))
namespaceBoxExpanded = false
expanded = false
},
)
}

View File

@@ -1,19 +1,25 @@
package me.weishu.kernelsu.ui.screen
import android.os.Parcelable
import androidx.compose.animation.AnimatedVisibility
import androidx.annotation.StringRes
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
@@ -39,12 +45,10 @@ import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.profile.AppProfile
import me.weishu.kernelsu.profile.RootProfile
import me.weishu.kernelsu.ui.component.RadioItem
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
@@ -126,28 +130,15 @@ private fun AppProfileInner(
onCheckedChange = onSwitchRootPermission,
)
Divider(thickness = Dp.Hairline)
Crossfade(targetState = isRootGranted, label = "") { current ->
if (current) {
var mode: Mode<RootProfile> by rememberSaveable { mutableStateOf(Mode.Default()) }
var template by rememberSaveable { mutableStateOf("None") }
var profile by rememberSaveable { mutableStateOf(RootProfile("@$packageName")) }
Column {
RadioItem(
title = stringResource(R.string.profile_default),
selected = mode is Mode.Default,
onClick = { mode = Mode.Default() }
)
RadioItem(
title = stringResource(R.string.profile_template),
selected = mode is Mode.Template,
onClick = { mode = Mode.Template("") }
)
AnimatedVisibility(mode is Mode.Template) {
if (current) {
var mode by rememberSaveable { mutableStateOf(Mode.Default) }
ProfileBox(mode, true) { mode = it }
Crossfade(targetState = mode, label = "") { currentMode ->
if (currentMode == Mode.Template) {
var expanded by remember { mutableStateOf(false) }
var template by rememberSaveable { mutableStateOf("None") }
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = expanded,
@@ -158,19 +149,17 @@ private fun AppProfileInner(
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },
value = template,
onValueChange = {}
onValueChange = {},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
// TODO: Template
}
})
}
RadioItem(
title = stringResource(R.string.profile_custom),
selected = mode is Mode.Custom,
onClick = { mode = Mode.Custom(profile) }
)
AnimatedVisibility(mode is Mode.Custom) {
} else if (mode == Mode.Custom) {
var profile by rememberSaveable { mutableStateOf(RootProfile("@$packageName")) }
RootProfileConfig(
fixedName = true,
profile = profile,
@@ -179,22 +168,11 @@ private fun AppProfileInner(
}
}
} else {
var mode: Mode<AppProfile> by rememberSaveable { mutableStateOf(Mode.Default()) }
var profile by rememberSaveable { mutableStateOf(AppProfile("@$packageName")) }
Column {
RadioItem(
title = stringResource(R.string.profile_default),
selected = mode is Mode.Default,
onClick = { mode = Mode.Default() }
)
RadioItem(
title = stringResource(R.string.profile_custom),
selected = mode is Mode.Custom,
onClick = { mode = Mode.Custom(profile) }
)
AnimatedVisibility(mode is Mode.Custom) {
var mode by rememberSaveable { mutableStateOf(Mode.Default) }
ProfileBox(mode, false) { mode = it }
Crossfade(targetState = mode, label = "") { currentMode ->
if (currentMode == Mode.Custom) {
var profile by rememberSaveable { mutableStateOf(AppProfile(packageName)) }
AppProfileConfig(
fixedName = true,
profile = profile,
@@ -202,20 +180,19 @@ private fun AppProfileInner(
)
}
}
}
}
}
}
}
@Parcelize
private sealed class Mode<P : Parcelable> : Parcelable {
private enum class Mode(@StringRes private val res: Int) {
Default(R.string.profile_default),
Template(R.string.profile_template),
Custom(R.string.profile_custom);
class Default<P : Parcelable> : Mode<P>()
class Template<P : Parcelable>(val template: String) : Mode<P>()
class Custom<P : Parcelable>(val profile: P) : Mode<P>()
val text: String
@Composable get() = stringResource(res)
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -233,6 +210,45 @@ private fun TopBar(onBack: () -> Unit) {
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ProfileBox(
mode: Mode,
hasTemplate: Boolean,
onModeChange: (Mode) -> Unit,
) {
ListItem(
headlineContent = { Text(stringResource(R.string.profile)) },
supportingContent = { Text(mode.text) },
leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
)
Divider(thickness = Dp.Hairline)
ListItem(headlineContent = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
FilterChip(
selected = mode == Mode.Default,
label = { Text(stringResource(R.string.profile_default)) },
onClick = { onModeChange(Mode.Default) },
)
if (hasTemplate) {
FilterChip(
selected = mode == Mode.Template,
label = { Text(stringResource(R.string.profile_template)) },
onClick = { onModeChange(Mode.Template) },
)
}
FilterChip(
selected = mode == Mode.Custom,
label = { Text(stringResource(R.string.profile_custom)) },
onClick = { onModeChange(Mode.Custom) },
)
}
})
}
@Preview
@Composable
private fun AppProfilePreview() {

View File

@@ -66,9 +66,9 @@
<string name="home_support_content">KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation.</string>
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
<string name="profile">App profile</string>
<string name="profile_default">Use default profile</string>
<string name="profile_template">Use template profile</string>
<string name="profile_custom">Use custom profile</string>
<string name="profile_default">Default</string>
<string name="profile_template">Template</string>
<string name="profile_custom">Custom</string>
<string name="profile_name">Profile name</string>
<string name="profile_namespace">Mount namespace</string>
<string name="profile_namespace_inherited">Inherited</string>