manager: add menu bar for home screen
This commit is contained in:
@@ -4,19 +4,21 @@ import android.content.ClipData
|
|||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.PowerManager
|
||||||
import android.system.Os
|
import android.system.Os
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
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.filled.Refresh
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material.icons.outlined.Block
|
import androidx.compose.material.icons.outlined.Block
|
||||||
import androidx.compose.material.icons.outlined.CheckCircle
|
import androidx.compose.material.icons.outlined.CheckCircle
|
||||||
import androidx.compose.material.icons.outlined.Warning
|
import androidx.compose.material.icons.outlined.Warning
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -27,19 +29,26 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||||
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.weishu.kernelsu.*
|
import me.weishu.kernelsu.*
|
||||||
import me.weishu.kernelsu.R
|
import me.weishu.kernelsu.R
|
||||||
|
import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
|
||||||
import me.weishu.kernelsu.ui.util.LinkifyText
|
import me.weishu.kernelsu.ui.util.LinkifyText
|
||||||
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
||||||
|
import me.weishu.kernelsu.ui.util.reboot
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@RootNavGraph(start = true)
|
@RootNavGraph(start = true)
|
||||||
@Destination
|
@Destination
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen() {
|
fun HomeScreen(navigator: DestinationsNavigator) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { TopBar() }
|
topBar = {
|
||||||
|
TopBar(onSettingsClick = {
|
||||||
|
navigator.navigate(SettingScreenDestination)
|
||||||
|
})
|
||||||
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -60,11 +69,54 @@ fun HomeScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
|
||||||
|
DropdownMenuItem(text = {
|
||||||
|
Text(stringResource(id))
|
||||||
|
}, onClick = {
|
||||||
|
reboot(reason)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun TopBar() {
|
private fun TopBar(onSettingsClick: () -> Unit) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(R.string.app_name)) }
|
title = { Text(stringResource(R.string.app_name)) },
|
||||||
|
actions = {
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package me.weishu.kernelsu.ui.screen
|
package me.weishu.kernelsu.ui.screen
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
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.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.filled.Add
|
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
@@ -30,7 +27,7 @@ import me.weishu.kernelsu.R
|
|||||||
import me.weishu.kernelsu.ksuApp
|
import me.weishu.kernelsu.ksuApp
|
||||||
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
||||||
import me.weishu.kernelsu.ui.util.installModule
|
import me.weishu.kernelsu.ui.util.installModule
|
||||||
import me.weishu.kernelsu.ui.util.rebootUserSpace
|
import me.weishu.kernelsu.ui.util.reboot
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -92,7 +89,7 @@ fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {
|
|||||||
onClick = {
|
onClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
rebootUserSpace()
|
reboot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package me.weishu.kernelsu.ui.screen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
|
import me.weishu.kernelsu.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author weishu
|
||||||
|
* @date 2023/1/1.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Destination
|
||||||
|
@Composable
|
||||||
|
fun SettingScreen(navigator: DestinationsNavigator) {
|
||||||
|
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopBar(onBack = {
|
||||||
|
navigator.popBackStack()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
) { paddingValues ->
|
||||||
|
|
||||||
|
Column(modifier = Modifier.padding(paddingValues)) {
|
||||||
|
Text(text = stringResource(id = R.string.settings))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun TopBar(onBack: () -> Unit = {}) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(stringResource(R.string.settings)) },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(
|
||||||
|
onClick = onBack
|
||||||
|
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -69,12 +69,11 @@ fun installModule(uri: Uri, onFinish: (Boolean)->Unit, onOutput: (String) -> Uni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rebootUserSpace() {
|
fun reboot(reason: String = "") {
|
||||||
val pm = ksuApp.getSystemService(Context.POWER_SERVICE) as PowerManager
|
|
||||||
val shell = ksuApp.createRootShell()
|
val shell = ksuApp.createRootShell()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm.isRebootingUserspaceSupported) {
|
if (reason == "recovery") {
|
||||||
ShellUtils.fastCmdResult(shell, "svc power reboot userspace")
|
// KEYCODE_POWER = 26, hide incorrect "Factory data reset" message
|
||||||
} else {
|
ShellUtils.fastCmd(shell, "/system/bin/input keyevent 26")
|
||||||
ShellUtils.fastCmdResult(shell, "reboot")
|
|
||||||
}
|
}
|
||||||
|
ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
|
||||||
}
|
}
|
||||||
@@ -22,4 +22,10 @@
|
|||||||
<string name="module_install">Install</string>
|
<string name="module_install">Install</string>
|
||||||
<string name="install">Install</string>
|
<string name="install">Install</string>
|
||||||
<string name="reboot">Reboot</string>
|
<string name="reboot">Reboot</string>
|
||||||
|
<string name="settings">Settings</string>
|
||||||
|
<string name="reboot_userspace">Soft reboot</string>
|
||||||
|
<string name="reboot_recovery">Reboot to recovery</string>
|
||||||
|
<string name="reboot_bootloader">Reboot to Bootloader</string>
|
||||||
|
<string name="reboot_download">Reboot to Download</string>
|
||||||
|
<string name="reboot_edl">Reboot to EDL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user