diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts
index 7cfb9959..7d3792f4 100644
--- a/manager/app/build.gradle.kts
+++ b/manager/app/build.gradle.kts
@@ -61,7 +61,6 @@ android {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
-
kotlin.sourceSets {
getByName(name) {
kotlin.srcDir("build/generated/ksp/$name/kotlin")
@@ -90,10 +89,9 @@ dependencies {
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
- implementation(libs.com.google.accompanist.systemuicontroller)
implementation(libs.com.google.accompanist.webview)
- implementation(libs.compose.destinations.animations.core)
+ implementation(libs.compose.destinations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.topjohnwu.libsu.core)
diff --git a/manager/app/src/main/AndroidManifest.xml b/manager/app/src/main/AndroidManifest.xml
index 32c920ab..618dd974 100644
--- a/manager/app/src/main/AndroidManifest.xml
+++ b/manager/app/src/main/AndroidManifest.xml
@@ -22,7 +22,6 @@
android:theme="@style/Theme.KernelSU">
-
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt
index 042155fb..469bf18f 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt
@@ -1,9 +1,15 @@
package me.weishu.kernelsu.ui
+import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
@@ -21,12 +27,12 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.ramcosta.composedestinations.DestinationsNavHost
-import com.ramcosta.composedestinations.navigation.popBackStack
+import com.ramcosta.composedestinations.generated.NavGraphs
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
+import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.screen.BottomBarDestination
-import me.weishu.kernelsu.ui.screen.NavGraphs
import me.weishu.kernelsu.ui.theme.KernelSUTheme
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.rootAvailable
@@ -34,6 +40,13 @@ import me.weishu.kernelsu.ui.util.rootAvailable
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
+
+ // Enable edge to edge
+ enableEdgeToEdge()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ window.isNavigationBarContrastEnforced = false
+ }
+
super.onCreate(savedInstanceState)
setContent {
@@ -42,7 +55,8 @@ class MainActivity : ComponentActivity() {
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
bottomBar = { BottomBar(navController) },
- snackbarHost = { SnackbarHost(snackbarHostState) }
+ snackbarHost = { SnackbarHost(snackbarHostState) },
+ contentWindowInsets = WindowInsets(0, 0, 0, 0)
) { innerPadding ->
CompositionLocalProvider(
LocalSnackbarHost provides snackbarHostState,
@@ -61,9 +75,13 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
+ val navigator = navController.rememberDestinationsNavigator()
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
- NavigationBar(tonalElevation = 8.dp) {
+ NavigationBar(
+ tonalElevation = 8.dp,
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom + WindowInsetsSides.Horizontal)
+ ) {
BottomBarDestination.entries.forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
@@ -71,11 +89,10 @@ private fun BottomBar(navController: NavHostController) {
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
- navController.popBackStack(destination.direction, false)
+ navigator.popBackStack(destination.direction, false)
}
-
- navController.navigate(destination.direction.route) {
- popUpTo(NavGraphs.root.route) {
+ navigator.navigate(destination.direction) {
+ popUpTo(NavGraphs.root) {
saveState = true
}
launchSingleTop = true
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
index e2c3fa45..27adc3f0 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/Dialog.kt
@@ -1,6 +1,7 @@
package me.weishu.kernelsu.ui.component
import android.graphics.text.LineBreaker
+import android.os.Build
import android.os.Parcelable
import android.text.Layout
import android.text.method.LinkMovementMethod
@@ -96,8 +97,8 @@ interface ConfirmDialogHandle : DialogHandle {
}
private abstract class DialogHandleBase(
- protected val visible: MutableState,
- protected val coroutineScope: CoroutineScope
+ val visible: MutableState,
+ val coroutineScope: CoroutineScope
) : DialogHandle {
override val isShown: Boolean
get() = visible.value
@@ -432,7 +433,9 @@ private fun MarkdownContent(content: String) {
TextView(context).apply {
movementMethod = LinkMovementMethod.getInstance()
setSpannableFactory(NoCopySpannableFactory.getInstance())
- breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
+ }
hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
index 8195cddd..b6f7dbe7 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/SearchBar.kt
@@ -5,8 +5,12 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@@ -132,7 +136,8 @@ fun SearchAppBar(
dropdownContent()
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
index d2cb3f34..1a39dcc3 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/RootProfileConfig.kt
@@ -1,11 +1,10 @@
-@file:OptIn(ExperimentalMaterial3Api::class)
-
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
@@ -20,12 +19,14 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -86,7 +87,7 @@ fun RootProfileConfig(
) {
OutlinedTextField(
modifier = Modifier
- .menuAnchor()
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_namespace)) },
@@ -184,7 +185,7 @@ fun RootProfileConfig(
}
}
-@OptIn(ExperimentalLayoutApi::class)
+@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@Composable
fun GroupsPanel(selected: List, closeSelection: (selection: Set) -> Unit) {
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
@@ -234,14 +235,20 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set)
)
}
- OutlinedCard(modifier = Modifier
- .fillMaxWidth()
- .padding(16.dp)
- .clickable {
- selectGroupsDialog.show()
- }) {
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ ) {
- Column(modifier = Modifier.padding(16.dp)) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ selectGroupsDialog.show()
+ }
+ .padding(16.dp)
+ ) {
Text(stringResource(R.string.profile_groups))
FlowRow {
selected.forEach { group ->
@@ -256,7 +263,7 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set)
}
}
-@OptIn(ExperimentalLayoutApi::class)
+@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@Composable
fun CapsPanel(
selected: Collection,
@@ -299,14 +306,20 @@ fun CapsPanel(
)
}
- OutlinedCard(modifier = Modifier
- .fillMaxWidth()
- .padding(16.dp)
- .clickable {
- selectCapabilitiesDialog.show()
- }) {
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ ) {
- Column(modifier = Modifier.padding(16.dp)) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ selectCapabilitiesDialog.show()
+ }
+ .padding(16.dp)
+ ) {
Text(stringResource(R.string.profile_capabilities))
FlowRow {
selected.forEach { group ->
@@ -329,10 +342,10 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
mutableStateOf(false)
}
var lastValidUid by remember {
- mutableStateOf(uid)
+ mutableIntStateOf(uid)
}
-
val keyboardController = LocalSoftwareKeyboardController.current
+
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
@@ -365,6 +378,7 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
})
}
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SELinuxPanel(
profile: Natives.Profile,
@@ -452,7 +466,7 @@ private fun SELinuxPanel(
),
label = { Text(text = stringResource(R.string.profile_selinux_context)) },
value = profile.context,
- onValueChange = { },
+ onValueChange = { }
)
})
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
index d09a2343..b60e8ea4 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/profile/TemplateConfig.kt
@@ -12,6 +12,7 @@ import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
+import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -54,7 +55,7 @@ fun TemplateConfig(
) {
OutlinedTextField(
modifier = Modifier
- .menuAnchor()
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
index ca53388f..f7035a67 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt
@@ -7,10 +7,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -50,6 +54,9 @@ import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
@@ -58,8 +65,6 @@ import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.component.profile.TemplateConfig
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.forceStopApp
import me.weishu.kernelsu.ui.util.getSepolicy
@@ -73,7 +78,7 @@ import me.weishu.kernelsu.ui.viewmodel.getTemplateInfoById
* @author weishu
* @date 2023/5/16.
*/
-@Destination
+@Destination
@Composable
fun AppProfileScreen(
navigator: DestinationsNavigator,
@@ -82,10 +87,8 @@ fun AppProfileScreen(
val context = LocalContext.current
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
- val failToUpdateAppProfile =
- stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
- val failToUpdateSepolicy =
- stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
+ val failToUpdateAppProfile = stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
+ val failToUpdateSepolicy = stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val packageName = appInfo.packageName
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
@@ -98,6 +101,7 @@ fun AppProfileScreen(
Scaffold(
topBar = { TopBar { navigator.popBackStack() } },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { paddingValues ->
AppProfileInner(
modifier = Modifier
@@ -248,6 +252,7 @@ private fun TopBar(onBack: () -> Unit) {
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
index 9345ced5..c9637ed2 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/BottomBarDestination.kt
@@ -5,11 +5,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
import androidx.compose.ui.graphics.vector.ImageVector
+import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
import me.weishu.kernelsu.R
-import me.weishu.kernelsu.ui.screen.destinations.HomeScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.SuperUserScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.ModuleScreenDestination
enum class BottomBarDestination(
val direction: DirectionDestinationSpec,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
index 1e3d48fd..3afdfb85 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt
@@ -4,8 +4,12 @@ import android.net.Uri
import android.os.Environment
import android.os.Parcelable
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -35,6 +39,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -66,7 +71,7 @@ enum class FlashingStatus {
* @date 2023/1/1.
*/
@Composable
-@Destination
+@Destination
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
var text by rememberSaveable { mutableStateOf("") }
@@ -139,8 +144,8 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
text = { Text(text = reboot) },
)
}
-
- }
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
KeyEventBlocker {
it.key == Key.VolumeDown || it.key == Key.VolumeUp
@@ -227,7 +232,8 @@ private fun TopBar(status: FlashingStatus, onBack: () -> Unit = {}, onSave: () -
contentDescription = "Localized description"
)
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
index b1e99888..7fcbb2df 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt
@@ -27,32 +27,35 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.core.content.pm.PackageInfoCompat
import com.ramcosta.composedestinations.annotation.Destination
-import com.ramcosta.composedestinations.annotation.RootNavGraph
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.*
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
-import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
-@RootNavGraph(start = true)
-@Destination
+@Destination(start = true)
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
val kernelVersion = getKernelVersion()
- Scaffold(topBar = {
- TopBar(kernelVersion, onSettingsClick = {
- navigator.navigate(SettingScreenDestination)
- }, onInstallClick = {
- navigator.navigate(InstallScreenDestination)
- })
- }) { innerPadding ->
+ Scaffold(
+ topBar = {
+ TopBar(kernelVersion, onSettingsClick = {
+ navigator.navigate(SettingScreenDestination)
+ }, onInstallClick = {
+ navigator.navigate(InstallScreenDestination)
+ })
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ ) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
@@ -103,12 +106,11 @@ fun UpdateCard() {
val context = LocalContext.current
val latestVersionInfo = LatestVersionInfo()
val newVersion by produceState(initialValue = latestVersionInfo) {
- value = withContext(Dispatchers.IO){
+ value = withContext(Dispatchers.IO) {
checkNewVersion()
}
}
-
val currentVersionCode = getManagerVersion(context).second
val newVersionCode = newVersion.versionCode
val newVersionUrl = newVersion.downloadUrl
@@ -158,50 +160,54 @@ private fun TopBar(
onInstallClick: () -> Unit,
onSettingsClick: () -> Unit
) {
- TopAppBar(title = { Text(stringResource(R.string.app_name)) }, actions = {
- if (kernelVersion.isGKI()) {
- IconButton(onClick = onInstallClick) {
+ TopAppBar(
+ title = { Text(stringResource(R.string.app_name)) },
+ actions = {
+ if (kernelVersion.isGKI()) {
+ IconButton(onClick = onInstallClick) {
+ Icon(
+ imageVector = Icons.Filled.Archive,
+ contentDescription = stringResource(id = R.string.install)
+ )
+ }
+ }
+
+ var showDropdown by remember { mutableStateOf(false) }
+ IconButton(onClick = {
+ showDropdown = true
+ }) {
Icon(
- imageVector = Icons.Filled.Archive,
- contentDescription = stringResource(id = R.string.install)
+ imageVector = Icons.Filled.Refresh,
+ contentDescription = stringResource(id = R.string.reboot)
+ )
+
+ DropdownMenu(expanded = showDropdown, onDismissRequest = {
+ showDropdown = false
+ }) {
+
+ RebootDropdownItem(id = R.string.reboot)
+
+ val pm =
+ LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
+ RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
+ }
+ RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
+ RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
+ RebootDropdownItem(id = R.string.reboot_download, reason = "download")
+ RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
+ }
+ }
+
+ IconButton(onClick = onSettingsClick) {
+ Icon(
+ imageVector = Icons.Filled.Settings,
+ contentDescription = stringResource(id = R.string.settings)
)
}
- }
-
- var showDropdown by remember { mutableStateOf(false) }
- IconButton(onClick = {
- showDropdown = true
- }) {
- Icon(
- imageVector = Icons.Filled.Refresh,
- contentDescription = stringResource(id = R.string.reboot)
- )
-
- DropdownMenu(expanded = showDropdown, onDismissRequest = {
- showDropdown = false
- }) {
-
- RebootDropdownItem(id = R.string.reboot)
-
- val pm =
- LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) {
- RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace")
- }
- RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery")
- RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader")
- RebootDropdownItem(id = R.string.reboot_download, reason = "download")
- RebootDropdownItem(id = R.string.reboot_edl, reason = "edl")
- }
- }
-
- IconButton(onClick = onSettingsClick) {
- Icon(
- imageVector = Icons.Filled.Settings,
- contentDescription = stringResource(id = R.string.settings)
- )
- }
- })
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ )
}
@Composable
@@ -415,9 +421,10 @@ private fun InfoCard() {
}
}
-fun getManagerVersion(context: Context): Pair {
+fun getManagerVersion(context: Context): Pair {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)!!
- return Pair(packageInfo.versionName!!, packageInfo.versionCode)
+ val versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)
+ return Pair(packageInfo.versionName!!, versionCode)
}
@Preview
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
index 71b5c975..b0f5d7ac 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt
@@ -9,8 +9,12 @@ import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload
@@ -40,13 +44,14 @@ import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.DialogHandle
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.LkmSelection
import me.weishu.kernelsu.ui.util.getCurrentKmi
import me.weishu.kernelsu.ui.util.getSupportedKmis
@@ -58,7 +63,7 @@ import me.weishu.kernelsu.ui.util.rootAvailable
* @author weishu
* @date 2024/3/12.
*/
-@Destination
+@Destination
@Composable
fun InstallScreen(navigator: DestinationsNavigator) {
var installMethod by remember {
@@ -113,11 +118,14 @@ fun InstallScreen(navigator: DestinationsNavigator) {
})
}
- Scaffold(topBar = {
- TopBar(
- onBack = { navigator.popBackStack() }, onLkmUpload = onLkmUpload
- )
- }) {
+ Scaffold(
+ topBar = {
+ TopBar(
+ onBack = { navigator.popBackStack() }, onLkmUpload = onLkmUpload
+ )
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ ) {
Column(modifier = Modifier.padding(it)) {
SelectInstallMethod { method ->
installMethod = method
@@ -293,15 +301,18 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) {
- TopAppBar(title = { Text(stringResource(R.string.install)) }, navigationIcon = {
- IconButton(
- onClick = onBack
- ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
- }, actions = {
- IconButton(onClick = onLkmUpload) {
- Icon(Icons.Filled.FileUpload, contentDescription = null)
- }
- })
+ TopAppBar(
+ title = { Text(stringResource(R.string.install)) }, navigationIcon = {
+ IconButton(
+ onClick = onBack
+ ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ }, actions = {
+ IconButton(onClick = onLkmUpload) {
+ Icon(Icons.Filled.FileUpload, contentDescription = null)
+ }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ )
}
@Composable
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
index 9812e87e..c224dfa3 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt
@@ -14,11 +14,15 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -29,7 +33,6 @@ import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.Button
-import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
@@ -64,6 +67,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -73,7 +78,6 @@ import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.DownloadListener
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.download
@@ -85,7 +89,7 @@ import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
import me.weishu.kernelsu.ui.webui.WebUIActivity
import okhttp3.OkHttpClient
-@Destination
+@Destination
@Composable
fun ModuleScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel()
@@ -102,41 +106,46 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val hideInstallButton = isSafeMode || hasMagisk
- Scaffold(topBar = {
- TopBar()
- }, floatingActionButton = if (hideInstallButton) {
- { /* Empty */ }
- } else {
- {
- val moduleInstall = stringResource(id = R.string.module_install)
- val selectZipLauncher = rememberLauncherForActivityResult(
- contract = ActivityResultContracts.StartActivityForResult()
- ) {
- if (it.resultCode != RESULT_OK) {
- return@rememberLauncherForActivityResult
+ Scaffold(
+ topBar = {
+ TopBar()
+ },
+ floatingActionButton = {
+ if (hideInstallButton) {
+ /* Empty */
+ } else {
+ val moduleInstall = stringResource(id = R.string.module_install)
+ val selectZipLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.StartActivityForResult()
+ ) {
+ if (it.resultCode != RESULT_OK) {
+ return@rememberLauncherForActivityResult
+ }
+ val data = it.data ?: return@rememberLauncherForActivityResult
+ val uri = data.data ?: return@rememberLauncherForActivityResult
+
+ navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
+
+ viewModel.markNeedRefresh()
+
+ Log.i("ModuleScreen", "select zip result: ${it.data}")
}
- val data = it.data ?: return@rememberLauncherForActivityResult
- val uri = data.data ?: return@rememberLauncherForActivityResult
- navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
+ ExtendedFloatingActionButton(
+ onClick = {
+ // select the zip file to install
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = "application/zip"
+ selectZipLauncher.launch(intent)
+ },
+ icon = { Icon(Icons.Filled.Add, moduleInstall) },
+ text = { Text(text = moduleInstall) },
+ )
- viewModel.markNeedRefresh()
-
- Log.i("ModuleScreen", "select zip result: ${it.data}")
}
-
- ExtendedFloatingActionButton(
- onClick = {
- // select the zip file to install
- val intent = Intent(Intent.ACTION_GET_CONTENT)
- intent.type = "application/zip"
- selectZipLauncher.launch(intent)
- },
- icon = { Icon(Icons.Filled.Add, moduleInstall) },
- text = { Text(text = moduleInstall) },
- )
- }
- }) { innerPadding ->
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ ) { innerPadding ->
when {
hasMagisk -> {
@@ -163,10 +172,11 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it)))
}, onClickModule = { id, name, hasWebUi ->
if (hasWebUi) {
- context.startActivity(Intent(context, WebUIActivity::class.java)
- .setData(Uri.parse("kernelsu://webui/$id"))
- .putExtra("id", id)
- .putExtra("name", name)
+ context.startActivity(
+ Intent(context, WebUIActivity::class.java)
+ .setData(Uri.parse("kernelsu://webui/$id"))
+ .putExtra("id", id)
+ .putExtra("name", name)
)
}
})
@@ -419,7 +429,10 @@ private fun ModuleList(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar() {
- TopAppBar(title = { Text(stringResource(R.string.module)) })
+ TopAppBar(
+ title = { Text(stringResource(R.string.module)) },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ )
}
@Composable
@@ -433,13 +446,16 @@ private fun ModuleItem(
onClick: (ModuleViewModel.ModuleInfo) -> Unit
) {
ElevatedCard(
- modifier = Modifier.fillMaxWidth(),
- colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface)
+ modifier = Modifier.fillMaxWidth()
) {
val textDecoration = if (!module.remove) null else TextDecoration.LineThrough
- Column(modifier = Modifier.clickable { onClick(module) }.padding(24.dp, 16.dp, 24.dp, 0.dp)) {
+ Column(
+ modifier = Modifier
+ .clickable { onClick(module) }
+ .padding(24.dp, 16.dp, 24.dp, 0.dp)
+ ) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
index 4f970f7e..a0f32d80 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
@@ -1,18 +1,18 @@
package me.weishu.kernelsu.ui.screen
-import android.content.ContentResolver
import android.content.Context
import android.content.Intent
-import android.database.Cursor
import android.net.Uri
-import android.provider.OpenableColumns
-import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Update
-import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -62,6 +61,9 @@ import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
+import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
@@ -77,20 +79,16 @@ import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
-import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
import me.weishu.kernelsu.ui.util.getFileNameFromUri
import me.weishu.kernelsu.ui.util.shrinkModules
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
/**
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
-@Destination
+@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
Scaffold(
@@ -98,7 +96,8 @@ fun SettingScreen(navigator: DestinationsNavigator) {
TopBar(onBack = {
navigator.popBackStack()
})
- }
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { paddingValues ->
val aboutDialog = rememberCustomDialog {
AboutDialog(it)
@@ -184,17 +183,20 @@ fun SettingScreen(navigator: DestinationsNavigator) {
showBottomsheet = true
}
)
- if (showBottomsheet){
+ if (showBottomsheet) {
ModalBottomSheet(
onDismissRequest = { showBottomsheet = false },
content = {
- Row(modifier = Modifier.padding(10.dp)
- .align(Alignment.CenterHorizontally)
+ Row(
+ modifier = Modifier
+ .padding(10.dp)
+ .align(Alignment.CenterHorizontally)
) {
- Box{
+ Box {
Column(
- modifier = Modifier.padding(16.dp)
+ modifier = Modifier
+ .padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
@@ -209,14 +211,15 @@ fun SettingScreen(navigator: DestinationsNavigator) {
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
- val filename = getFileNameFromUri(context , uri)
- val savefile = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
- addCategory(Intent.CATEGORY_OPENABLE)
- type = "application/zip"
- putExtra(Intent.EXTRA_STREAM, uri)
- putExtra(Intent.EXTRA_TITLE, filename)
- flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- }
+ val filename = getFileNameFromUri(context, uri)
+ val savefile =
+ Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "application/zip"
+ putExtra(Intent.EXTRA_STREAM, uri)
+ putExtra(Intent.EXTRA_TITLE, filename)
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ }
context.startActivity(
Intent.createChooser(
savefile,
@@ -245,9 +248,10 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
- Box{
+ Box {
Column(
- modifier = Modifier.padding(16.dp)
+ modifier = Modifier
+ .padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
@@ -350,6 +354,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
}
+
@Composable
fun UninstallItem(
navigator: DestinationsNavigator,
@@ -374,11 +379,9 @@ fun UninstallItem(
UninstallType.PERMANENT -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashUninstall)
)
-
UninstallType.RESTORE_STOCK_IMAGE -> navigator.navigate(
FlashScreenDestination(FlashIt.FlashRestore)
)
-
UninstallType.NONE -> Unit
}
}
@@ -464,6 +467,7 @@ private fun TopBar(onBack: () -> Unit = {}) {
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
},
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
)
}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
index 2eb2e770..e41345b0 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/SuperUser.kt
@@ -26,16 +26,17 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.AppProfileScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SearchAppBar
-import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
@OptIn(ExperimentalMaterialApi::class)
-@Destination
+@Destination
@Composable
fun SuperUserScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel()
@@ -92,7 +93,8 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
}
},
)
- }
+ },
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
index bf353b0a..1ba58059 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Template.kt
@@ -7,8 +7,12 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
@@ -47,13 +51,14 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.result.getOr
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.weishu.kernelsu.R
-import me.weishu.kernelsu.ui.screen.destinations.TemplateEditorScreenDestination
import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
/**
@@ -62,7 +67,7 @@ import me.weishu.kernelsu.ui.viewmodel.TemplateViewModel
*/
@OptIn(ExperimentalMaterialApi::class)
-@Destination
+@Destination
@Composable
fun AppProfileTemplateScreen(
navigator: DestinationsNavigator,
@@ -141,6 +146,7 @@ fun AppProfileTemplateScreen(
text = { Text(stringResource(id = R.string.app_profile_template_create)) },
)
},
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
@@ -254,6 +260,7 @@ private fun TopBar(
})
}
}
- }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
)
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
index b6b7cc80..53f5beff 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/TemplateEditor.kt
@@ -3,8 +3,12 @@ package me.weishu.kernelsu.ui.screen
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -37,6 +41,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
@@ -52,7 +57,7 @@ import me.weishu.kernelsu.ui.viewmodel.toJSON
* @date 2023/10/20.
*/
@OptIn(ExperimentalComposeUiApi::class)
-@Destination
+@Destination
@Composable
fun TemplateEditorScreen(
navigator: ResultBackNavigator,
@@ -108,6 +113,7 @@ fun TemplateEditorScreen(
}
})
},
+ contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
) { innerPadding ->
Column(
modifier = Modifier
@@ -242,37 +248,40 @@ private fun TopBar(
onDelete: () -> Unit = {},
onSave: () -> Unit = {}
) {
- TopAppBar(title = {
- Column {
- Text(title)
- if (summary.isNotBlank()) {
- Text(
- text = summary,
- style = MaterialTheme.typography.bodyMedium,
+ TopAppBar(
+ title = {
+ Column {
+ Text(title)
+ if (summary.isNotBlank()) {
+ Text(
+ text = summary,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+ }
+ }, navigationIcon = {
+ IconButton(
+ onClick = onBack
+ ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
+ }, actions = {
+ if (readOnly) {
+ return@TopAppBar
+ }
+ IconButton(onClick = onDelete) {
+ Icon(
+ Icons.Filled.DeleteForever,
+ contentDescription = stringResource(id = R.string.app_profile_template_delete)
)
}
- }
- }, navigationIcon = {
- IconButton(
- onClick = onBack
- ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
- }, actions = {
- if (readOnly) {
- return@TopAppBar
- }
- IconButton(onClick = onDelete) {
- Icon(
- Icons.Filled.DeleteForever,
- contentDescription = stringResource(id = R.string.app_profile_template_delete)
- )
- }
- IconButton(onClick = onSave) {
- Icon(
- imageVector = Icons.Filled.Save,
- contentDescription = stringResource(id = R.string.app_profile_template_save)
- )
- }
- })
+ IconButton(onClick = onSave) {
+ Icon(
+ imageVector = Icons.Filled.Save,
+ contentDescription = stringResource(id = R.string.app_profile_template_save)
+ )
+ }
+ },
+ windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
+ )
}
@Composable
@@ -289,17 +298,16 @@ private fun TextEdit(
value = text,
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
- suffix =
- if (errorHint.isNotBlank()) {
- {
+ suffix = {
+ if (errorHint.isNotBlank()) {
Text(
text = if (isError) errorHint else "",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error
)
+ } else {
+ null
}
- } else {
- null
},
isError = isError,
keyboardOptions = KeyboardOptions(
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
index 3b3945d0..903ee94e 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt
@@ -7,12 +7,8 @@ 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.SideEffect
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.unit.dp
-import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorScheme = darkColorScheme(
primary = YELLOW,
@@ -42,20 +38,6 @@ fun KernelSUTheme(
else -> LightColorScheme
}
- val systemUiController = rememberSystemUiController()
- SideEffect {
- systemUiController.setStatusBarColor(
- color = colorScheme.surface,
- darkIcons = !darkTheme
- )
-
- // To match the App Navbar color
- systemUiController.setNavigationBarColor(
- color = colorScheme.surfaceColorAtElevation(8.dp),
- darkIcons = !darkTheme,
- )
- }
-
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
index 19eb1df1..a8363120 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
@@ -1,16 +1,12 @@
package me.weishu.kernelsu.ui.util
-import android.content.ContentResolver
import android.content.Context
-import android.net.Uri
import android.os.Build
-import android.os.ParcelFileDescriptor
import android.system.Os
import com.topjohnwu.superuser.ShellUtils
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ui.screen.getManagerVersion
import java.io.File
-import java.io.FileOutputStream
import java.io.FileWriter
import java.io.PrintWriter
import java.time.LocalDateTime
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
index 78346dd9..6b0d704e 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
@@ -1,7 +1,7 @@
package me.weishu.kernelsu.ui.util
-import androidx.compose.ui.res.stringResource
import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.R
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
index 18774910..d926d7ea 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
@@ -2,13 +2,18 @@ package me.weishu.kernelsu.ui.webui
import android.annotation.SuppressLint
import android.app.ActivityManager
-import android.content.Context
+import android.os.Build
import android.os.Bundle
+import android.view.ViewGroup.MarginLayoutParams
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
+import androidx.activity.enableEdgeToEdge
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
import androidx.webkit.WebViewAssetLoader
import com.topjohnwu.superuser.Shell
import me.weishu.kernelsu.ui.util.createRootShell
@@ -21,12 +26,26 @@ class WebUIActivity : ComponentActivity() {
private var rootShell: Shell? = null
override fun onCreate(savedInstanceState: Bundle?) {
+
+ // Enable edge to edge
+ enableEdgeToEdge()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ window.isNavigationBarContrastEnforced = false
+ }
+
super.onCreate(savedInstanceState)
+
val moduleId = intent.getStringExtra("id")!!
val name = intent.getStringExtra("name")!!
- setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ @Suppress("DEPRECATION")
+ setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
+ } else {
+ val taskDescription = ActivityManager.TaskDescription.Builder().setLabel("KernelSU - $name").build()
+ setTaskDescription(taskDescription)
+ }
- val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
+ val prefs = getSharedPreferences("settings", MODE_PRIVATE)
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false))
val moduleDir = "/data/adb/modules/${moduleId}"
@@ -50,6 +69,16 @@ class WebUIActivity : ComponentActivity() {
}
val webView = WebView(this).apply {
+ ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
+ val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
+ view.updateLayoutParams {
+ leftMargin = inset.left
+ rightMargin = inset.right
+ topMargin = inset.top
+ bottomMargin = inset.bottom
+ }
+ return@setOnApplyWindowInsetsListener insets
+ }
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
index 394c237f..00fcde65 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
@@ -9,21 +9,24 @@ import android.view.Window
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.Toast
-import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.internal.UiThreadHandler
-import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.createRootShell
+import me.weishu.kernelsu.ui.util.listModules
import me.weishu.kernelsu.ui.util.withNewRootShell
import org.json.JSONArray
import org.json.JSONObject
-import java.util.concurrent.CompletableFuture
import java.io.File
+import java.util.concurrent.CompletableFuture
-class WebViewInterface(val context: Context, private val webView: WebView, private val modDir: String) {
+class WebViewInterface(
+ val context: Context,
+ private val webView: WebView,
+ private val modDir: String
+) {
@JavascriptInterface
fun exec(cmd: String): String {
@@ -187,28 +190,20 @@ class WebViewInterface(val context: Context, private val webView: WebView, priva
}
var keys = currentInfo.keys()
- for(key in keys) {
- currentModuleInfo.put(key, currentInfo.get(key));
+ for (key in keys) {
+ currentModuleInfo.put(key, currentInfo.get(key))
}
- break;
+ break
}
- return currentModuleInfo.toString();
+ return currentModuleInfo.toString()
}
}
-fun hideSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, false)
+fun hideSystemUI(window: Window) =
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
- controller.systemBarsBehavior =
- WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
-}
-fun showSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, true)
- WindowInsetsControllerCompat(
- window,
- window.decorView
- ).show(WindowInsetsCompat.Type.systemBars())
-}
\ No newline at end of file
+fun showSystemUI(window: Window) =
+ WindowInsetsControllerCompat(window, window.decorView).show(WindowInsetsCompat.Type.systemBars())
diff --git a/manager/app/src/main/res/values-night-v27/themes.xml b/manager/app/src/main/res/values-night-v27/themes.xml
deleted file mode 100644
index 10a773b1..00000000
--- a/manager/app/src/main/res/values-night-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-night/themes.xml b/manager/app/src/main/res/values-night/themes.xml
index 91abf657..d76ba8e6 100644
--- a/manager/app/src/main/res/values-night/themes.xml
+++ b/manager/app/src/main/res/values-night/themes.xml
@@ -1,10 +1,10 @@
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-v27/themes.xml b/manager/app/src/main/res/values-v27/themes.xml
deleted file mode 100644
index 325416c0..00000000
--- a/manager/app/src/main/res/values-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values/themes.xml b/manager/app/src/main/res/values/themes.xml
index 7d41d8ec..31721d39 100644
--- a/manager/app/src/main/res/values/themes.xml
+++ b/manager/app/src/main/res/values/themes.xml
@@ -1,10 +1,13 @@
-
+
-
+
+
\ No newline at end of file
diff --git a/manager/gradle/libs.versions.toml b/manager/gradle/libs.versions.toml
index 4201fdd8..30c2bf85 100644
--- a/manager/gradle/libs.versions.toml
+++ b/manager/gradle/libs.versions.toml
@@ -1,18 +1,18 @@
[versions]
-agp = "8.5.2"
+agp = "8.6.1"
kotlin = "2.0.20"
-ksp = "2.0.20-1.0.24"
-compose-bom = "2024.08.00"
-lifecycle = "2.8.4"
-accompanist = "0.34.0"
-navigation = "2.7.7"
-activity-compose = "1.9.1"
-kotlinx-coroutines = "1.8.1"
+ksp = "2.0.20-1.0.25"
+compose-bom = "2024.09.02"
+lifecycle = "2.8.6"
+accompanist = "0.36.0"
+navigation = "2.8.1"
+activity-compose = "1.9.2"
+kotlinx-coroutines = "1.9.0"
coil-compose = "2.7.0"
-compose-destination = "1.10.2"
+compose-destination = "2.1.0-beta12"
sheets-compose-dialogs = "1.3.0"
markdown = "4.6.2"
-webkit = "1.11.0"
+webkit = "1.12.0"
appiconloader-coil = "1.5.0"
parcelablelist = "2.0.1"
libsu = "6.0.0"
@@ -53,7 +53,6 @@ androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
com-google-accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
com-google-accompanist-navigation-animation = { group = "com.google.accompanist", name = "accompanist-navigation-animation", version.ref = "accompanist" }
-com-google-accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
com-google-accompanist-webview = { group = "com.google.accompanist", name = "accompanist-webview", version.ref = "accompanist" }
com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
@@ -68,7 +67,7 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version.ref = "appiconloader-coil" }
-compose-destinations-animations-core = { group = "io.github.raamcosta.compose-destinations", name = "animations-core", version.ref = "compose-destination" }
+compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destination" }
compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" }
sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs" }