manager: hide root related features if kernelsu not available (#2555)

Without KernelSU installed, root-related features did not take any
effect. So, better to hide it.

Improving this pr:
https://github.com/tiann/KernelSU/pull/2483

Also attempt to address this:
https://github.com/tiann/KernelSU/pull/2483#issuecomment-2692048907

Tested-by: Faris <90097027+rsuntk@users.noreply.github.com>

Co-authored-by: Rifat Azad <33044977+rifsxd@users.noreply.github.com>

---------

Signed-off-by: Faris <90097027+rsuntk@users.noreply.github.com>
Co-authored-by: Rifat Azad <33044977+rifsxd@users.noreply.github.com>
This commit is contained in:
Faris
2025-05-03 21:07:47 +07:00
committed by GitHub
parent 1946876626
commit 2d6890ce05
3 changed files with 106 additions and 73 deletions

View File

@@ -0,0 +1,17 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.runtime.Composable
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
@Composable
fun KsuIsValid(
content: @Composable () -> Unit
) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val ksuVersion = if (isManager) Natives.version else null
if (ksuVersion != null) {
content()
}
}

View File

@@ -39,6 +39,7 @@ 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.component.KsuIsValid
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
@@ -180,29 +181,31 @@ private fun TopBar(
}
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
KsuIsValid() {
IconButton(onClick = {
showDropdown = true
}) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(id = R.string.reboot)
)
RebootDropdownItem(id = R.string.reboot)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
val pm = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
@Suppress("DEPRECATION")
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)
val pm = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager?
@Suppress("DEPRECATION")
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")
}
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")
}
}

View File

@@ -85,6 +85,7 @@ import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.DialogHandle
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.KsuIsValid
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
@@ -150,42 +151,49 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
val profileTemplate = stringResource(id = R.string.settings_profile_template)
ListItem(
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
headlineContent = { Text(profileTemplate) },
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
modifier = Modifier.clickable {
navigator.navigate(AppProfileTemplateScreenDestination)
}
)
KsuIsValid() {
ListItem(
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
headlineContent = { Text(profileTemplate) },
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
modifier = Modifier.clickable {
navigator.navigate(AppProfileTemplateScreenDestination)
}
)
}
var umountChecked by rememberSaveable {
mutableStateOf(Natives.isDefaultUmountModules())
}
SwitchItem(
icon = Icons.Filled.FolderDelete,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
KsuIsValid() {
SwitchItem(
icon = Icons.Filled.FolderDelete,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
}
}
}
if (Natives.version >= Natives.MINIMAL_SUPPORTED_SU_COMPAT) {
var isSuDisabled by rememberSaveable {
mutableStateOf(!Natives.isSuEnabled())
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_disable_su),
summary = stringResource(id = R.string.settings_disable_su_summary),
checked = isSuDisabled,
) { checked ->
val shouldEnable = !checked
if (Natives.setSuEnabled(shouldEnable)) {
isSuDisabled = !shouldEnable
KsuIsValid() {
if (Natives.version >= Natives.MINIMAL_SUPPORTED_SU_COMPAT) {
var isSuDisabled by rememberSaveable {
mutableStateOf(!Natives.isSuEnabled())
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_disable_su),
summary = stringResource(id = R.string.settings_disable_su_summary),
checked = isSuDisabled,
) { checked ->
val shouldEnable = !checked
if (Natives.setSuEnabled(shouldEnable)) {
isSuDisabled = !shouldEnable
}
}
}
}
@@ -211,14 +219,17 @@ fun SettingScreen(navigator: DestinationsNavigator) {
prefs.getBoolean("enable_web_debugging", false)
)
}
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
KsuIsValid() {
SwitchItem(
icon = Icons.Filled.DeveloperMode,
title = stringResource(id = R.string.enable_web_debugging),
summary = stringResource(id = R.string.enable_web_debugging_summary),
checked = enableWebDebugging
) {
prefs.edit().putBoolean("enable_web_debugging", it).apply()
enableWebDebugging = it
}
}
var showBottomsheet by remember { mutableStateOf(false) }
@@ -332,25 +343,27 @@ fun SettingScreen(navigator: DestinationsNavigator) {
val shrink = stringResource(id = R.string.shrink_sparse_image)
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
ListItem(
leadingContent = {
Icon(
Icons.Filled.Compress,
shrink
)
},
headlineContent = { Text(shrink) },
modifier = Modifier.clickable {
scope.launch {
val result = shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage)
if (result == ConfirmResult.Confirmed) {
loadingDialog.withLoading {
shrinkModules()
KsuIsValid() {
ListItem(
leadingContent = {
Icon(
Icons.Filled.Compress,
shrink
)
},
headlineContent = { Text(shrink) },
modifier = Modifier.clickable {
scope.launch {
val result = shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage)
if (result == ConfirmResult.Confirmed) {
loadingDialog.withLoading {
shrinkModules()
}
}
}
}
}
)
)
}
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
if (lkmMode) {