manager: Make SwitchItem can be click like preference (#1697)

Use `AutoMirrored` icon
Drop some deprecated methods
Remove unused imports
Add bottom padding for AppProfileTemplateScreen to avoid display content
behind fab
This commit is contained in:
Light_summer
2024-05-04 20:41:05 +08:00
committed by GitHub
parent b6ac012189
commit c0b7ab5d42
23 changed files with 100 additions and 160 deletions

View File

@@ -3,9 +3,14 @@ package me.weishu.kernelsu.ui
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.* import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -14,8 +19,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.navigation.popBackStack import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
@@ -29,13 +33,12 @@ import me.weishu.kernelsu.ui.util.rootAvailable
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
KernelSUTheme { KernelSUTheme {
val navController = rememberAnimatedNavController() val navController = rememberNavController()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
Scaffold( Scaffold(
bottomBar = { BottomBar(navController) }, bottomBar = { BottomBar(navController) },
@@ -61,7 +64,7 @@ private fun BottomBar(navController: NavHostController) {
val isManager = Natives.becomeManager(ksuApp.packageName) val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
NavigationBar(tonalElevation = 8.dp) { NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.values().forEach { destination -> BottomBarDestination.entries.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction) val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem( NavigationBarItem(

View File

@@ -12,13 +12,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext

View File

@@ -10,9 +10,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
@@ -39,7 +38,7 @@ import androidx.compose.ui.unit.dp
private const val TAG = "SearchBar" private const val TAG = "SearchBar"
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SearchAppBar( fun SearchAppBar(
title: @Composable () -> Unit, title: @Composable () -> Unit,
@@ -115,7 +114,7 @@ fun SearchAppBar(
if (onBackClick != null) { if (onBackClick != null) {
IconButton( IconButton(
onClick = onBackClick, onClick = onBackClick,
content = { Icon(Icons.Outlined.ArrowBack, null) } content = { Icon(Icons.AutoMirrored.Outlined.ArrowBack, null) }
) )
} }
}, },

View File

@@ -1,11 +1,13 @@
package me.weishu.kernelsu.ui.component package me.weishu.kernelsu.ui.component
import androidx.compose.foundation.clickable
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
@Composable @Composable
@@ -18,6 +20,9 @@ fun SwitchItem(
onCheckedChange: (Boolean) -> Unit onCheckedChange: (Boolean) -> Unit
) { ) {
ListItem( ListItem(
modifier = Modifier.clickable {
onCheckedChange.invoke(!checked)
},
headlineContent = { headlineContent = {
Text(title) Text(title)
}, },

View File

@@ -22,15 +22,13 @@ import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -148,7 +146,7 @@ fun RootProfileConfig(
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e -> val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
e.mapNotNull { g -> e.mapNotNull { g ->
Groups.values().find { it.gid == g } Groups.entries.find { it.gid == g }
} }
} }
GroupsPanel(selectedGroups) { GroupsPanel(selectedGroups) {
@@ -161,7 +159,7 @@ fun RootProfileConfig(
} }
val selectedCaps = profile.capabilities.mapNotNull { e -> val selectedCaps = profile.capabilities.mapNotNull { e ->
Capabilities.values().find { it.cap == e } Capabilities.entries.find { it.cap == e }
} }
CapsPanel(selectedCaps) { CapsPanel(selectedCaps) {
@@ -190,7 +188,7 @@ fun RootProfileConfig(
@Composable @Composable
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) { fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit -> val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
val groups = Groups.values().sortedWith( val groups = Groups.entries.toTypedArray().sortedWith(
compareBy<Groups> { if (selected.contains(it)) 0 else 1 } compareBy<Groups> { if (selected.contains(it)) 0 else 1 }
.then(compareBy { .then(compareBy {
when (it) { when (it) {
@@ -265,7 +263,7 @@ fun CapsPanel(
closeSelection: (selection: Set<Capabilities>) -> Unit closeSelection: (selection: Set<Capabilities>) -> Unit
) { ) {
val selectCapabilitiesDialog = rememberCustomDialog { dismiss -> val selectCapabilitiesDialog = rememberCustomDialog { dismiss ->
val caps = Capabilities.values().sortedWith( val caps = Capabilities.entries.toTypedArray().sortedWith(
compareBy<Capabilities> { if (selected.contains(it)) 0 else 1 } compareBy<Capabilities> { if (selected.contains(it)) 0 else 1 }
.then(compareBy { it.name }) .then(compareBy { it.name })
) )
@@ -323,7 +321,6 @@ fun CapsPanel(
} }
} }
@OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) { private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
@@ -447,7 +444,7 @@ private fun SELinuxPanel(
editSELinuxDialog.show() editSELinuxDialog.show()
}, },
enabled = false, enabled = false,
colors = TextFieldDefaults.outlinedTextFieldColors( colors = OutlinedTextFieldDefaults.colors(
disabledTextColor = MaterialTheme.colorScheme.onSurface, disabledTextColor = MaterialTheme.colorScheme.onSurface,
disabledBorderColor = MaterialTheme.colorScheme.outline, disabledBorderColor = MaterialTheme.colorScheme.outline,
disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant, disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,

View File

@@ -2,10 +2,10 @@ package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ReadMore
import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.ReadMore
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
@@ -105,7 +105,7 @@ fun TemplateConfig(
IconButton(onClick = { IconButton(onClick = {
onViewTemplate(tid) onViewTemplate(tid)
}) { }) {
Icon(Icons.Filled.ReadMore, null) Icon(Icons.AutoMirrored.Filled.ReadMore, null)
} }
} }
) )

View File

@@ -15,15 +15,15 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Android import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Security import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.Divider
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
@@ -246,12 +246,11 @@ private fun TopBar(onBack: () -> Unit) {
navigationIcon = { navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, },
) )
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun ProfileBox( private fun ProfileBox(
mode: Mode, mode: Mode,
@@ -263,7 +262,7 @@ private fun ProfileBox(
supportingContent = { Text(mode.text) }, supportingContent = { Text(mode.text) },
leadingContent = { Icon(Icons.Filled.AccountCircle, null) }, leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
) )
Divider(thickness = Dp.Hairline) HorizontalDivider(thickness = Dp.Hairline)
ListItem(headlineContent = { ListItem(headlineContent = {
Row( Row(
modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly

View File

@@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.key
@@ -46,8 +45,8 @@ import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.LkmSelection import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.LocalSnackbarHost import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.installBoot
import me.weishu.kernelsu.ui.util.flashModule import me.weishu.kernelsu.ui.util.flashModule
import me.weishu.kernelsu.ui.util.installBoot
import me.weishu.kernelsu.ui.util.reboot import me.weishu.kernelsu.ui.util.reboot
import me.weishu.kernelsu.ui.util.restoreBoot import me.weishu.kernelsu.ui.util.restoreBoot
import me.weishu.kernelsu.ui.util.uninstallPermanently import me.weishu.kernelsu.ui.util.uninstallPermanently
@@ -66,7 +65,6 @@ enum class FlashingStatus {
* @author weishu * @author weishu
* @date 2023/1/1. * @date 2023/1/1.
*/ */
@OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
@Destination @Destination
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
@@ -101,7 +99,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
logContent.append(it).append("\n") logContent.append(it).append("\n")
}, onStderr = { }, onStderr = {
logContent.append(it).append("\n") logContent.append(it).append("\n")
}); })
} }
} }

View File

@@ -327,7 +327,7 @@ fun LearnMoreCard() {
uriHandler.openUri(url) uriHandler.openUri(url)
} }
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) { .padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
Column() { Column {
Text( Text(
text = stringResource(R.string.home_learn_kernelsu), text = stringResource(R.string.home_learn_kernelsu),
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
@@ -354,7 +354,7 @@ fun DonateCard() {
uriHandler.openUri("https://patreon.com/weishu") uriHandler.openUri("https://patreon.com/weishu")
} }
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) { .padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
Column() { Column {
Text( Text(
text = stringResource(R.string.home_support_title), text = stringResource(R.string.home_support_title),
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall

View File

@@ -12,7 +12,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -296,7 +296,7 @@ private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) {
TopAppBar(title = { Text(stringResource(R.string.install)) }, navigationIcon = { TopAppBar(title = { Text(stringResource(R.string.install)) }, navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = { }, actions = {
IconButton(onClick = onLkmUpload) { IconButton(onClick = onLkmUpload) {
Icon(Icons.Filled.FileUpload, contentDescription = null) Icon(Icons.Filled.FileUpload, contentDescription = null)

View File

@@ -10,8 +10,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Undo import androidx.compose.material.icons.automirrored.filled.Undo
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.BugReport import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.Compress import androidx.compose.material.icons.filled.Compress
import androidx.compose.material.icons.filled.ContactPage import androidx.compose.material.icons.filled.ContactPage
@@ -350,7 +350,7 @@ private fun TopBar(onBack: () -> Unit = {}) {
navigationIcon = { navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, },
) )
} }

View File

@@ -6,14 +6,15 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ImportExport import androidx.compose.material.icons.filled.ImportExport
import androidx.compose.material.icons.filled.Sync import androidx.compose.material.icons.filled.Sync
import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.PullRefreshIndicator
@@ -43,6 +44,7 @@ import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -149,7 +151,9 @@ fun AppProfileTemplateScreen(
.padding(innerPadding) .padding(innerPadding)
.pullRefresh(refreshState) .pullRefresh(refreshState)
) { ) {
LazyColumn(Modifier.fillMaxSize()) { LazyColumn(Modifier.fillMaxSize(), contentPadding = remember {
PaddingValues(bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */)
}) {
items(viewModel.templateList, key = { it.id }) { app -> items(viewModel.templateList, key = { it.id }) { app ->
TemplateItem(navigator, app) TemplateItem(navigator, app)
} }
@@ -214,7 +218,7 @@ private fun TopBar(
navigationIcon = { navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, },
actions = { actions = {
IconButton(onClick = onSync) { IconButton(onClick = onSync) {

View File

@@ -10,7 +10,7 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.DeleteForever import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.material.icons.filled.Save import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -40,16 +40,12 @@ import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.result.ResultBackNavigator
import me.weishu.kernelsu.Natives import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R import me.weishu.kernelsu.R
import me.weishu.kernelsu.profile.Capabilities
import me.weishu.kernelsu.profile.Groups
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.util.deleteAppProfileTemplate import me.weishu.kernelsu.ui.util.deleteAppProfileTemplate
import me.weishu.kernelsu.ui.util.getAppProfileTemplate import me.weishu.kernelsu.ui.util.getAppProfileTemplate
import me.weishu.kernelsu.ui.util.setAppProfileTemplate import me.weishu.kernelsu.ui.util.setAppProfileTemplate
import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
import me.weishu.kernelsu.ui.viewmodel.toJSON import me.weishu.kernelsu.ui.viewmodel.toJSON
import org.json.JSONArray
import org.json.JSONObject
/** /**
* @author weishu * @author weishu
@@ -259,7 +255,7 @@ private fun TopBar(
}, navigationIcon = { }, navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
}, actions = { }, actions = {
if (readOnly) { if (readOnly) {
return@TopAppBar return@TopAppBar
@@ -279,7 +275,6 @@ private fun TopBar(
}) })
} }
@OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
private fun TextEdit( private fun TextEdit(
label: String, label: String,

View File

@@ -1,17 +1,17 @@
package me.weishu.kernelsu.ui.theme package me.weishu.kernelsu.ui.theme
import android.app.Activity
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.ViewCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorScheme = darkColorScheme( private val DarkColorScheme = darkColorScheme(

View File

@@ -391,9 +391,9 @@ public class HanziToPinyin {
return sInstance; return sInstance;
} }
// Check if zh_CN collation data is available // Check if zh_CN collation data is available
final Locale locale[] = Collator.getAvailableLocales(); final Locale[] locale = Collator.getAvailableLocales();
for (int i = 0; i < locale.length; i++) { for (Locale value : locale) {
if (locale[i].equals(Locale.CHINA) || locale[i].getLanguage().contains("zh")) { if (value.equals(Locale.CHINA) || value.getLanguage().contains("zh")) {
// Do self validation just once. // Do self validation just once.
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Self validation. Result: " + doSelfValidation()); Log.d(TAG, "Self validation. Result: " + doSelfValidation());
@@ -508,7 +508,7 @@ public class HanziToPinyin {
* Token. If these is no China collator, the empty token array is returned. * Token. If these is no China collator, the empty token array is returned.
*/ */
public ArrayList<Token> get(final String input) { public ArrayList<Token> get(final String input) {
ArrayList<Token> tokens = new ArrayList<Token>(); ArrayList<Token> tokens = new ArrayList<>();
if (!mHasChinaCollator || TextUtils.isEmpty(input)) { if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
// return empty tokens. // return empty tokens.
return tokens; return tokens;

View File

@@ -1,6 +1,5 @@
package me.weishu.kernelsu.ui.viewmodel package me.weishu.kernelsu.ui.viewmodel
import android.net.Uri
import android.os.SystemClock import android.os.SystemClock
import android.util.Log import android.util.Log
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
@@ -16,7 +15,7 @@ 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.text.Collator
import java.util.* import java.util.Locale
class ModuleViewModel : ViewModel() { class ModuleViewModel : ViewModel() {

View File

@@ -107,7 +107,7 @@ class SuperUserViewModel : ViewModel() {
} }
} }
val intent = Intent(ksuApp, KsuService::class.java); val intent = Intent(ksuApp, KsuService::class.java)
val task = KsuService.bindOrTask( val task = KsuService.bindOrTask(
intent, intent,
@@ -119,7 +119,7 @@ class SuperUserViewModel : ViewModel() {
} }
private fun stopKsuService() { private fun stopKsuService() {
val intent = Intent(ksuApp, KsuService::class.java); val intent = Intent(ksuApp, KsuService::class.java)
KsuService.stop(intent) KsuService.stop(intent)
} }

View File

@@ -235,7 +235,7 @@ private fun fromJSON(templateJson: JSONObject): TemplateViewModel.TemplateInfo?
val groupsJsonArray = templateJson.optJSONArray("groups") val groupsJsonArray = templateJson.optJSONArray("groups")
val capabilitiesJsonArray = templateJson.optJSONArray("capabilities") val capabilitiesJsonArray = templateJson.optJSONArray("capabilities")
val context = templateJson.optString("context").takeIf { it.isNotEmpty() } val context = templateJson.optString("context").takeIf { it.isNotEmpty() }
?: Natives.KERNEL_SU_DOMAIN; ?: Natives.KERNEL_SU_DOMAIN
val namespace = templateJson.optString("namespace").takeIf { it.isNotEmpty() } val namespace = templateJson.optString("namespace").takeIf { it.isNotEmpty() }
?: Natives.Profile.Namespace.INHERITED.name ?: Natives.Profile.Namespace.INHERITED.name
@@ -276,13 +276,13 @@ fun TemplateViewModel.TemplateInfo.toJSON(): JSONObject {
if (template.author.isNotEmpty()) { if (template.author.isNotEmpty()) {
put("author", template.author) put("author", template.author)
} }
put("namespace", Natives.Profile.Namespace.values()[template.namespace].name) put("namespace", Natives.Profile.Namespace.entries[template.namespace].name)
put("uid", template.uid) put("uid", template.uid)
put("gid", template.gid) put("gid", template.gid)
if (template.groups.isNotEmpty()) { if (template.groups.isNotEmpty()) {
put("groups", JSONArray( put("groups", JSONArray(
Groups.values().filter { Groups.entries.filter {
template.groups.contains(it.gid) template.groups.contains(it.gid)
}.map { }.map {
it.name it.name
@@ -292,7 +292,7 @@ fun TemplateViewModel.TemplateInfo.toJSON(): JSONObject {
if (template.capabilities.isNotEmpty()) { if (template.capabilities.isNotEmpty()) {
put("capabilities", JSONArray( put("capabilities", JSONArray(
Capabilities.values().filter { Capabilities.entries.filter {
template.capabilities.contains(it.cap) template.capabilities.contains(it.cap)
}.map { }.map {
it.name it.name

View File

@@ -51,89 +51,38 @@ class MimeUtil {
final String extension = fileName.substring(finalFullStop + 1).toLowerCase(); final String extension = fileName.substring(finalFullStop + 1).toLowerCase();
switch (extension) { return switch (extension) {
case "webm": case "webm" -> "video/webm";
return "video/webm"; case "mpeg", "mpg" -> "video/mpeg";
case "mpeg": case "mp3" -> "audio/mpeg";
case "mpg": case "wasm" -> "application/wasm";
return "video/mpeg"; case "xhtml", "xht", "xhtm" -> "application/xhtml+xml";
case "mp3": case "flac" -> "audio/flac";
return "audio/mpeg"; case "ogg", "oga", "opus" -> "audio/ogg";
case "wasm": case "wav" -> "audio/wav";
return "application/wasm"; case "m4a" -> "audio/x-m4a";
case "xhtml": case "gif" -> "image/gif";
case "xht": case "jpeg", "jpg", "jfif", "pjpeg", "pjp" -> "image/jpeg";
case "xhtm": case "png" -> "image/png";
return "application/xhtml+xml"; case "apng" -> "image/apng";
case "flac": case "svg", "svgz" -> "image/svg+xml";
return "audio/flac"; case "webp" -> "image/webp";
case "ogg": case "mht", "mhtml" -> "multipart/related";
case "oga": case "css" -> "text/css";
case "opus": case "html", "htm", "shtml", "shtm", "ehtml" -> "text/html";
return "audio/ogg"; case "js", "mjs" -> "application/javascript";
case "wav": case "xml" -> "text/xml";
return "audio/wav"; case "mp4", "m4v" -> "video/mp4";
case "m4a": case "ogv", "ogm" -> "video/ogg";
return "audio/x-m4a"; case "ico" -> "image/x-icon";
case "gif": case "woff" -> "application/font-woff";
return "image/gif"; case "gz", "tgz" -> "application/gzip";
case "jpeg": case "json" -> "application/json";
case "jpg": case "pdf" -> "application/pdf";
case "jfif": case "zip" -> "application/zip";
case "pjpeg": case "bmp" -> "image/bmp";
case "pjp": case "tiff", "tif" -> "image/tiff";
return "image/jpeg"; default -> null;
case "png": };
return "image/png";
case "apng":
return "image/apng";
case "svg":
case "svgz":
return "image/svg+xml";
case "webp":
return "image/webp";
case "mht":
case "mhtml":
return "multipart/related";
case "css":
return "text/css";
case "html":
case "htm":
case "shtml":
case "shtm":
case "ehtml":
return "text/html";
case "js":
case "mjs":
return "application/javascript";
case "xml":
return "text/xml";
case "mp4":
case "m4v":
return "video/mp4";
case "ogv":
case "ogm":
return "video/ogg";
case "ico":
return "image/x-icon";
case "woff":
return "application/font-woff";
case "gz":
case "tgz":
return "application/gzip";
case "json":
return "application/json";
case "pdf":
return "application/pdf";
case "zip":
return "application/zip";
case "bmp":
return "image/bmp";
case "tiff":
case "tif":
return "image/tiff";
default:
return null;
}
} }
} }

View File

@@ -13,13 +13,10 @@ import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream; import com.topjohnwu.superuser.io.SuFileInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import me.weishu.kernelsu.ui.util.KsuCliKt;
/** /**
* Handler class to open files from file system by root access * Handler class to open files from file system by root access
* For more information about android storage please refer to * For more information about android storage please refer to
@@ -172,8 +169,7 @@ public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream; return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
} }
public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws FileNotFoundException, public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws IOException {
IOException {
SuFile suFile = new SuFile(file.getAbsolutePath()); SuFile suFile = new SuFile(file.getAbsolutePath());
suFile.setShell(shell); suFile.setShell(shell);
InputStream fis = SuFileInputStream.open(suFile); InputStream fis = SuFileInputStream.open(suFile);

View File

@@ -42,10 +42,6 @@ val androidTargetCompatibility = JavaVersion.VERSION_21
val managerVersionCode by extra(getVersionCode()) val managerVersionCode by extra(getVersionCode())
val managerVersionName by extra(getVersionName()) val managerVersionName by extra(getVersionName())
tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
}
fun getGitCommitCount(): Int { fun getGitCommitCount(): Int {
val out = ByteArrayOutputStream() val out = ByteArrayOutputStream()
exec { exec {

View File

@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement { pluginManagement {