manager: add a simple manager updater, close #627

This commit is contained in:
weishu
2023-06-23 00:31:36 +08:00
parent 12761ee167
commit 37f4045499
4 changed files with 131 additions and 82 deletions

View File

@@ -19,6 +19,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
@@ -28,6 +29,8 @@ import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph
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.screen.destinations.SettingScreenDestination
@@ -37,13 +40,11 @@ import me.weishu.kernelsu.ui.util.*
@Destination
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
Scaffold(
topBar = {
TopBar(onSettingsClick = {
navigator.navigate(SettingScreenDestination)
})
}
) { innerPadding ->
Scaffold(topBar = {
TopBar(onSettingsClick = {
navigator.navigate(SettingScreenDestination)
})
}) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
@@ -62,11 +63,11 @@ fun HomeScreen(navigator: DestinationsNavigator) {
if (isManager && Natives.requireNewKernel()) {
WarningCard(
stringResource(id = R.string.require_kernel_version).format(
ksuVersion,
Natives.MINIMAL_SUPPORTED_KERNEL
ksuVersion, Natives.MINIMAL_SUPPORTED_KERNEL
)
)
}
UpdateCard()
InfoCard()
DonateCard()
LearnMoreCard()
@@ -75,6 +76,25 @@ fun HomeScreen(navigator: DestinationsNavigator) {
}
}
@Composable
fun UpdateCard() {
val context = LocalContext.current
val newVersion by produceState(initialValue = 0 to "") {
value = withContext(Dispatchers.IO) { checkNewVersion() }
}
val currentVersionCode = getManagerVersion(context).second
val newVersionCode = newVersion.first
val newVersionUrl = newVersion.second
if (newVersionCode <= currentVersionCode) {
return
}
val uriHandler = LocalUriHandler.current
WarningCard(message = stringResource(id = R.string.new_version_available).format(newVersionCode)) {
uriHandler.openUri(newVersionUrl)
}
}
@Composable
fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
DropdownMenuItem(text = {
@@ -87,44 +107,41 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onSettingsClick: () -> Unit) {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
actions = {
var showDropdown by remember { mutableStateOf(false) }
IconButton(onClick = {
showDropdown = true
TopAppBar(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
}) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(id = R.string.reboot)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
RebootDropdownItem(id = R.string.reboot)
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")
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")
}
}
IconButton(onClick = onSettingsClick) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = stringResource(id = R.string.settings)
)
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)
)
}
})
}
@Composable
@@ -136,17 +153,14 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
})
) {
val uriHandler = LocalUriHandler.current
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
if (kernelVersion.isGKI() && ksuVersion == null) {
uriHandler.openUri("https://kernelsu.org/guide/installation.html")
}
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
if (kernelVersion.isGKI() && ksuVersion == null) {
uriHandler.openUri("https://kernelsu.org/guide/installation.html")
}
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
when {
ksuVersion != null -> {
val appendText = if (Natives.isSafeMode) {
@@ -168,10 +182,8 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(
R.string.home_superuser_count,
getSuperuserCount()
),
style = MaterialTheme.typography.bodyMedium
R.string.home_superuser_count, getSuperuserCount()
), style = MaterialTheme.typography.bodyMedium
)
Spacer(Modifier.height(4.dp))
Text(
@@ -217,22 +229,25 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
}
@Composable
fun WarningCard(message: String) {
fun WarningCard(
message: String, color: Color = MaterialTheme.colorScheme.error, onClick: () -> Unit = {}
) {
ElevatedCard(
colors = CardDefaults.elevatedCardColors(
containerColor = MaterialTheme.colorScheme.error
containerColor = color
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
.padding(24.dp)
.clickable {
onClick()
}, verticalAlignment = Alignment.CenterVertically
) {
Column() {
Text(
text = message,
style = MaterialTheme.typography.bodyMedium
text = message, style = MaterialTheme.typography.bodyMedium
)
}
}
@@ -246,15 +261,12 @@ fun LearnMoreCard() {
ElevatedCard {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri(url)
}
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri(url)
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
Column() {
Text(
text = stringResource(R.string.home_learn_kernelsu),
@@ -276,15 +288,12 @@ fun DonateCard() {
ElevatedCard {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri("https://patreon.com/weishu")
}
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri("https://patreon.com/weishu")
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
Column() {
Text(
text = stringResource(R.string.home_support_title),
@@ -323,7 +332,11 @@ private fun InfoCard() {
InfoCardItem(stringResource(R.string.home_kernel), uname.release)
Spacer(Modifier.height(16.dp))
InfoCardItem(stringResource(R.string.home_manager_version), getManagerVersion(context))
val managerVersion = getManagerVersion(context)
InfoCardItem(
stringResource(R.string.home_manager_version),
"${managerVersion.first} (${managerVersion.second})"
)
Spacer(Modifier.height(16.dp))
InfoCardItem(stringResource(R.string.home_fingerprint), Build.FINGERPRINT)
@@ -334,9 +347,9 @@ private fun InfoCard() {
}
}
fun getManagerVersion(context: Context): String {
fun getManagerVersion(context: Context): Pair<String, Int> {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
return "${packageInfo.versionName} (${packageInfo.versionCode})"
return Pair(packageInfo.versionName, packageInfo.versionCode)
}
@Preview

View File

@@ -60,6 +60,40 @@ fun download(
downloadManager.enqueue(request)
}
fun checkNewVersion(): Pair<Int, String> {
val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest"
val defaultValue = 0 to ""
runCatching {
okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute()
.use { response ->
if (!response.isSuccessful) {
return defaultValue
}
val body = response.body?.string() ?: return defaultValue
val json = org.json.JSONObject(body)
val assets = json.getJSONArray("assets")
for (i in 0 until assets.length()) {
val asset = assets.getJSONObject(i)
val name = asset.getString("name")
if (!name.endsWith(".apk")) {
continue
}
val regex = Regex("v(.+?)_(\\d+)-")
val matchResult = regex.find(name) ?: continue
val versionName = matchResult.groupValues[1]
val versionCode = matchResult.groupValues[2].toInt()
val downloadUrl = asset.getString("browser_download_url")
return versionCode to downloadUrl
}
}
}
return defaultValue
}
@Composable
fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) {
DisposableEffect(context) {

View File

@@ -74,4 +74,5 @@
<string name="module_update">更新</string>
<string name="module_downloading">正在下载模块:%s</string>
<string name="module_start_downloading">开始下载:%s</string>
<string name="new_version_available">发现新版本:%d点击下载</string>
</resources>

View File

@@ -79,4 +79,5 @@
<string name="module_update">Update</string>
<string name="module_downloading">Downloading module: %s</string>
<string name="module_start_downloading">Start downloading: %s</string>
<string name="new_version_available">New version: %s is available, click to download</string>
</resources>