manager: Expand the option to directly open the file and flash the anykernel3 kernel package
This commit is contained in:
@@ -27,6 +27,7 @@ import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationSty
|
|||||||
import com.ramcosta.composedestinations.generated.NavGraphs
|
import com.ramcosta.composedestinations.generated.NavGraphs
|
||||||
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
||||||
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
||||||
|
import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
|
||||||
import com.ramcosta.composedestinations.spec.NavHostGraphSpec
|
import com.ramcosta.composedestinations.spec.NavHostGraphSpec
|
||||||
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
|
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
|
||||||
import com.sukisu.ultra.Natives
|
import com.sukisu.ultra.Natives
|
||||||
@@ -40,8 +41,14 @@ import com.sukisu.ultra.ui.webui.initPlatform
|
|||||||
import com.sukisu.ultra.ui.screen.FlashIt
|
import com.sukisu.ultra.ui.screen.FlashIt
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import zako.zako.zako.zakoui.activity.component.BottomBar
|
import zako.zako.zako.zakoui.activity.component.BottomBar
|
||||||
import zako.zako.zako.zakoui.activity.util.*
|
import zako.zako.zako.zakoui.activity.util.*
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.sukisu.ultra.ui.util.rootAvailable
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private lateinit var superUserViewModel: SuperUserViewModel
|
private lateinit var superUserViewModel: SuperUserViewModel
|
||||||
@@ -113,11 +120,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
LaunchedEffect(zipUri) {
|
LaunchedEffect(zipUri) {
|
||||||
if (!zipUri.isNullOrEmpty()) {
|
if (!zipUri.isNullOrEmpty()) {
|
||||||
navigator.navigate(
|
// 检测 ZIP 文件类型并导航到相应界面
|
||||||
FlashScreenDestination(
|
detectZipTypeAndNavigate(zipUri, navigator)
|
||||||
FlashIt.FlashModules(zipUri)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +201,115 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class ZipType {
|
||||||
|
MODULE,
|
||||||
|
KERNEL,
|
||||||
|
UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectZipType(uri: Uri): ZipType {
|
||||||
|
return try {
|
||||||
|
contentResolver.openInputStream(uri)?.use { inputStream ->
|
||||||
|
ZipInputStream(inputStream).use { zipStream ->
|
||||||
|
var hasModuleProp = false
|
||||||
|
var hasToolsFolder = false
|
||||||
|
var hasAnykernelSh = false
|
||||||
|
|
||||||
|
var entry = zipStream.nextEntry
|
||||||
|
while (entry != null) {
|
||||||
|
val entryName = entry.name.lowercase()
|
||||||
|
|
||||||
|
when {
|
||||||
|
entryName == "module.prop" || entryName.endsWith("/module.prop") -> {
|
||||||
|
hasModuleProp = true
|
||||||
|
}
|
||||||
|
entryName.startsWith("tools/") || entryName == "tools" -> {
|
||||||
|
hasToolsFolder = true
|
||||||
|
}
|
||||||
|
entryName == "anykernel.sh" || entryName.endsWith("/anykernel.sh") -> {
|
||||||
|
hasAnykernelSh = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zipStream.closeEntry()
|
||||||
|
entry = zipStream.nextEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
when {
|
||||||
|
hasModuleProp -> ZipType.MODULE
|
||||||
|
hasToolsFolder && hasAnykernelSh -> ZipType.KERNEL
|
||||||
|
else -> ZipType.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: ZipType.UNKNOWN
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
ZipType.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun detectZipTypeAndNavigate(
|
||||||
|
zipUris: ArrayList<Uri>,
|
||||||
|
navigator: com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
|
) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val moduleUris = mutableListOf<Uri>()
|
||||||
|
val kernelUris = mutableListOf<Uri>()
|
||||||
|
|
||||||
|
for (uri in zipUris) {
|
||||||
|
val zipType = detectZipType(uri)
|
||||||
|
when (zipType) {
|
||||||
|
ZipType.MODULE -> moduleUris.add(uri)
|
||||||
|
ZipType.KERNEL -> kernelUris.add(uri)
|
||||||
|
ZipType.UNKNOWN -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据检测结果导航
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
when {
|
||||||
|
// 内核文件
|
||||||
|
kernelUris.isNotEmpty() && moduleUris.isEmpty() -> {
|
||||||
|
if (kernelUris.size == 1 && rootAvailable()) {
|
||||||
|
navigator.navigate(
|
||||||
|
InstallScreenDestination(
|
||||||
|
preselectedKernelUri = kernelUris.first().toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setAutoExitAfterFlash()
|
||||||
|
}
|
||||||
|
// 模块文件
|
||||||
|
moduleUris.isNotEmpty() -> {
|
||||||
|
navigator.navigate(
|
||||||
|
FlashScreenDestination(
|
||||||
|
FlashIt.FlashModules(ArrayList(moduleUris))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setAutoExitAfterFlash()
|
||||||
|
}
|
||||||
|
// 如果没有识别出任何类型的文件,则直接退出
|
||||||
|
else -> {
|
||||||
|
(this@MainActivity as? ComponentActivity)?.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
(this@MainActivity as? ComponentActivity)?.finish()
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAutoExitAfterFlash() {
|
||||||
|
val sharedPref = getSharedPreferences("kernel_flash_prefs", MODE_PRIVATE)
|
||||||
|
sharedPref.edit {
|
||||||
|
putBoolean("auto_exit_after_flash", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeViewModels() {
|
private fun initializeViewModels() {
|
||||||
superUserViewModel = SuperUserViewModel()
|
superUserViewModel = SuperUserViewModel()
|
||||||
homeViewModel = HomeViewModel()
|
homeViewModel = HomeViewModel()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.sukisu.ultra.ui.screen
|
package com.sukisu.ultra.ui.screen
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
@@ -50,6 +51,7 @@ import kotlinx.parcelize.Parcelize
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ShirkNeko
|
* @author ShirkNeko
|
||||||
@@ -122,6 +124,11 @@ fun setModuleVerificationStatus(uri: Uri, isVerified: Boolean) {
|
|||||||
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val shouldAutoExit = remember {
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.getBoolean("auto_exit_after_flash", false)
|
||||||
|
}
|
||||||
|
|
||||||
// 是否通过从外部启动的模块安装
|
// 是否通过从外部启动的模块安装
|
||||||
val isExternalInstall = remember {
|
val isExternalInstall = remember {
|
||||||
when (flashIt) {
|
when (flashIt) {
|
||||||
@@ -231,10 +238,14 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
}
|
}
|
||||||
hasUpdateCompleted = true
|
hasUpdateCompleted = true
|
||||||
|
|
||||||
// 如果是外部安装的模块更新且不需要重启,延迟后自动返回
|
// 如果是外部安装或需要自动退出的模块更新且不需要重启,延迟后自动返回
|
||||||
if (isExternalInstall) {
|
if (isExternalInstall || shouldAutoExit) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
kotlinx.coroutines.delay(2000)
|
kotlinx.coroutines.delay(2000)
|
||||||
|
if (shouldAutoExit) {
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
|
}
|
||||||
(context as? ComponentActivity)?.finish()
|
(context as? ComponentActivity)?.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,16 +341,24 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
kotlinx.coroutines.delay(500)
|
kotlinx.coroutines.delay(500)
|
||||||
navigator.navigate(FlashScreenDestination(nextFlashIt))
|
navigator.navigate(FlashScreenDestination(nextFlashIt))
|
||||||
}
|
}
|
||||||
} else if (isExternalInstall && flashIt is FlashIt.FlashModules && flashIt.currentIndex >= flashIt.uris.size - 1) {
|
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModules && flashIt.currentIndex >= flashIt.uris.size - 1) {
|
||||||
// 如果是外部安装且是最后一个模块,安装完成后自动返回
|
// 如果是外部安装或需要自动退出且是最后一个模块,安装完成后自动返回
|
||||||
scope.launch {
|
scope.launch {
|
||||||
kotlinx.coroutines.delay(2000)
|
kotlinx.coroutines.delay(2000)
|
||||||
|
if (shouldAutoExit) {
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
|
}
|
||||||
(context as? ComponentActivity)?.finish()
|
(context as? ComponentActivity)?.finish()
|
||||||
}
|
}
|
||||||
} else if (isExternalInstall && flashIt is FlashIt.FlashModule) {
|
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModule) {
|
||||||
// 如果是外部安装单个模块,安装完成后自动返回
|
// 如果是外部安装或需要自动退出的单个模块,安装完成后自动返回
|
||||||
scope.launch {
|
scope.launch {
|
||||||
kotlinx.coroutines.delay(2000)
|
kotlinx.coroutines.delay(2000)
|
||||||
|
if (shouldAutoExit) {
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
|
}
|
||||||
(context as? ComponentActivity)?.finish()
|
(context as? ComponentActivity)?.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,7 +687,7 @@ private fun TopBar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getModuleNameFromUri(context: android.content.Context, uri: Uri): String {
|
suspend fun getModuleNameFromUri(context: Context, uri: Uri): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
if (uri == Uri.EMPTY) {
|
if (uri == Uri.EMPTY) {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import androidx.compose.material.icons.filled.*
|
|||||||
import androidx.compose.material.icons.outlined.Block
|
import androidx.compose.material.icons.outlined.Block
|
||||||
import androidx.compose.material.icons.outlined.TaskAlt
|
import androidx.compose.material.icons.outlined.TaskAlt
|
||||||
import androidx.compose.material.icons.outlined.Warning
|
import androidx.compose.material.icons.outlined.Warning
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
@@ -139,7 +138,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
|
|||||||
StatusCard(
|
StatusCard(
|
||||||
systemStatus = viewModel.systemStatus,
|
systemStatus = viewModel.systemStatus,
|
||||||
onClickInstall = {
|
onClickInstall = {
|
||||||
navigator.navigate(InstallScreenDestination)
|
navigator.navigate(InstallScreenDestination(preselectedKernelUri = null))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.maxkeppeker.sheets.core.models.base.Header
|
import com.maxkeppeker.sheets.core.models.base.Header
|
||||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||||
import com.maxkeppeler.sheets.list.ListDialog
|
import com.maxkeppeler.sheets.list.ListDialog
|
||||||
@@ -71,19 +72,45 @@ enum class KpmPatchOption {
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Destination<RootGraph>
|
@Destination<RootGraph>
|
||||||
@Composable
|
@Composable
|
||||||
fun InstallScreen(navigator: DestinationsNavigator) {
|
fun InstallScreen(
|
||||||
|
navigator: DestinationsNavigator,
|
||||||
|
preselectedKernelUri: String? = null
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
var installMethod by remember { mutableStateOf<InstallMethod?>(null) }
|
var installMethod by remember { mutableStateOf<InstallMethod?>(null) }
|
||||||
var lkmSelection by remember { mutableStateOf<LkmSelection>(LkmSelection.KmiNone) }
|
var lkmSelection by remember { mutableStateOf<LkmSelection>(LkmSelection.KmiNone) }
|
||||||
var kpmPatchOption by remember { mutableStateOf(KpmPatchOption.FOLLOW_KERNEL) }
|
var kpmPatchOption by remember { mutableStateOf(KpmPatchOption.FOLLOW_KERNEL) }
|
||||||
val context = LocalContext.current
|
|
||||||
var showRebootDialog by remember { mutableStateOf(false) }
|
var showRebootDialog by remember { mutableStateOf(false) }
|
||||||
var showSlotSelectionDialog by remember { mutableStateOf(false) }
|
var showSlotSelectionDialog by remember { mutableStateOf(false) }
|
||||||
|
var showKpmPatchDialog by remember { mutableStateOf(false) }
|
||||||
var tempKernelUri by remember { mutableStateOf<Uri?>(null) }
|
var tempKernelUri by remember { mutableStateOf<Uri?>(null) }
|
||||||
val kernelVersion = getKernelVersion()
|
val kernelVersion = getKernelVersion()
|
||||||
val isGKI = kernelVersion.isGKI()
|
val isGKI = kernelVersion.isGKI()
|
||||||
val isAbDevice = isAbDevice()
|
val isAbDevice = isAbDevice()
|
||||||
val summary = stringResource(R.string.horizon_kernel_summary)
|
val summary = stringResource(R.string.horizon_kernel_summary)
|
||||||
|
|
||||||
|
// 处理预选的内核文件
|
||||||
|
LaunchedEffect(preselectedKernelUri) {
|
||||||
|
preselectedKernelUri?.let { uriString ->
|
||||||
|
try {
|
||||||
|
val preselectedUri = uriString.toUri()
|
||||||
|
val horizonMethod = InstallMethod.HorizonKernel(
|
||||||
|
uri = preselectedUri,
|
||||||
|
summary = summary
|
||||||
|
)
|
||||||
|
installMethod = horizonMethod
|
||||||
|
tempKernelUri = preselectedUri
|
||||||
|
if (isAbDevice) {
|
||||||
|
showSlotSelectionDialog = true
|
||||||
|
} else {
|
||||||
|
showKpmPatchDialog = true
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showRebootDialog) {
|
if (showRebootDialog) {
|
||||||
RebootDialog(
|
RebootDialog(
|
||||||
show = true,
|
show = true,
|
||||||
@@ -143,6 +170,19 @@ fun InstallScreen(navigator: DestinationsNavigator) {
|
|||||||
summary = summary
|
summary = summary
|
||||||
)
|
)
|
||||||
installMethod = horizonMethod
|
installMethod = horizonMethod
|
||||||
|
if (preselectedKernelUri != null) {
|
||||||
|
showKpmPatchDialog = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
KpmPatchSelectionDialog(
|
||||||
|
show = showKpmPatchDialog,
|
||||||
|
currentOption = kpmPatchOption,
|
||||||
|
onDismiss = { showKpmPatchDialog = false },
|
||||||
|
onOptionSelected = { option ->
|
||||||
|
kpmPatchOption = option
|
||||||
|
showKpmPatchDialog = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -194,6 +234,7 @@ fun InstallScreen(navigator: DestinationsNavigator) {
|
|||||||
showSlotSelectionDialog = true
|
showSlotSelectionDialog = true
|
||||||
} else {
|
} else {
|
||||||
installMethod = method
|
installMethod = method
|
||||||
|
showKpmPatchDialog = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
installMethod = method
|
installMethod = method
|
||||||
@@ -316,6 +357,47 @@ fun InstallScreen(navigator: DestinationsNavigator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun KpmPatchSelectionDialog(
|
||||||
|
show: Boolean,
|
||||||
|
currentOption: KpmPatchOption,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onOptionSelected: (KpmPatchOption) -> Unit
|
||||||
|
) {
|
||||||
|
if (show) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
title = { Text(stringResource(R.string.kpm_patch_options)) },
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.kpm_patch_description),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
KpmPatchOptionGroup(
|
||||||
|
selectedOption = currentOption,
|
||||||
|
onOptionChanged = onOptionSelected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = { onOptionSelected(currentOption) }
|
||||||
|
) {
|
||||||
|
Text(stringResource(android.R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = onDismiss) {
|
||||||
|
Text(stringResource(android.R.string.cancel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RebootDialog(
|
private fun RebootDialog(
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
@@ -404,6 +486,10 @@ private fun SelectInstallMethod(
|
|||||||
var selectedOption by remember { mutableStateOf<InstallMethod?>(null) }
|
var selectedOption by remember { mutableStateOf<InstallMethod?>(null) }
|
||||||
var currentSelectingMethod by remember { mutableStateOf<InstallMethod?>(null) }
|
var currentSelectingMethod by remember { mutableStateOf<InstallMethod?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(selectedMethod) {
|
||||||
|
selectedOption = selectedMethod
|
||||||
|
}
|
||||||
|
|
||||||
val selectImageLauncher = rememberLauncherForActivityResult(
|
val selectImageLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.StartActivityForResult()
|
contract = ActivityResultContracts.StartActivityForResult()
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package zako.zako.zako.zakoui.screen
|
package zako.zako.zako.zakoui.screen
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -27,6 +29,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.content.edit
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
@@ -73,6 +76,12 @@ fun KernelFlashScreen(
|
|||||||
kpmUndoPatch: Boolean = false
|
kpmUndoPatch: Boolean = false
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val shouldAutoExit = remember {
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.getBoolean("auto_exit_after_flash", false)
|
||||||
|
}
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
val snackBarHost = LocalSnackbarHost.current
|
val snackBarHost = LocalSnackbarHost.current
|
||||||
@@ -105,6 +114,16 @@ fun KernelFlashScreen(
|
|||||||
val onFlashComplete = {
|
val onFlashComplete = {
|
||||||
showFloatAction = true
|
showFloatAction = true
|
||||||
KernelFlashStateHolder.isFlashing = false
|
KernelFlashStateHolder.isFlashing = false
|
||||||
|
|
||||||
|
// 如果需要自动退出,延迟3秒后退出
|
||||||
|
if (shouldAutoExit) {
|
||||||
|
scope.launch {
|
||||||
|
delay(3000)
|
||||||
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
|
(context as? ComponentActivity)?.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始刷写
|
// 开始刷写
|
||||||
@@ -165,6 +184,17 @@ fun KernelFlashScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose {
|
||||||
|
KernelFlashStateHolder.currentState = null
|
||||||
|
KernelFlashStateHolder.currentUri = null
|
||||||
|
KernelFlashStateHolder.currentSlot = null
|
||||||
|
KernelFlashStateHolder.currentKpmPatchEnabled = false
|
||||||
|
KernelFlashStateHolder.currentKpmUndoPatch = false
|
||||||
|
KernelFlashStateHolder.isFlashing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BackHandler(enabled = true) {
|
BackHandler(enabled = true) {
|
||||||
onBack()
|
onBack()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user