Cherry-pick commit 00ae4f9

This commit is contained in:
ShirkNeko
2025-03-19 20:08:23 +08:00
parent f231cb2249
commit 3208a916e2

View File

@@ -3,15 +3,19 @@ package shirkneko.zako.sukisu.ui.screen
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.app.AlertDialog
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.widget.Toast import android.widget.Toast
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -20,15 +24,19 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.FileUpload import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource 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.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.documentfile.provider.DocumentFile
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
@@ -49,6 +57,12 @@ import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import shirkneko.zako.sukisu.ui.util.*
import shirkneko.zako.sukisu.utils.AssetsUtil
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
/** /**
* @author weishu * @author weishu
@@ -68,6 +82,33 @@ fun InstallScreen(navigator: DestinationsNavigator) {
showRebootDialog = true showRebootDialog = true
} }
if (showRebootDialog) {
RebootDialog(
show = true,
onDismiss = { showRebootDialog = false },
onConfirm = {
showRebootDialog = false
try {
val process = Runtime.getRuntime().exec("su")
process.outputStream.bufferedWriter().use { writer ->
writer.write("svc power reboot\n")
writer.write("exit\n")
}
} catch (e: Exception) {
Toast.makeText(context, R.string.failed_reboot, Toast.LENGTH_SHORT).show()
}
}
)
var installMethod by remember { mutableStateOf<InstallMethod?>(null) }
var lkmSelection by remember { mutableStateOf<LkmSelection>(LkmSelection.KmiNone) }
val context = LocalContext.current
var showRebootDialog by remember { mutableStateOf(false) }
val onFlashComplete = {
showRebootDialog = true
}
if (showRebootDialog) { if (showRebootDialog) {
RebootDialog( RebootDialog(
show = true, show = true,
@@ -108,9 +149,32 @@ fun InstallScreen(navigator: DestinationsNavigator) {
} }
} }
} }
Unit
when (method) {
is InstallMethod.HorizonKernel -> {
method.uri?.let { uri ->
val worker = HorizonKernelWorker(context)
worker.uri = uri
worker.setOnFlashCompleteListener(onFlashComplete)
worker.start()
}
}
else -> {
val flashIt = FlashIt.FlashBoot(
boot = if (method is InstallMethod.SelectFile) method.uri else null,
lkm = lkmSelection,
ota = method is InstallMethod.DirectInstallToInactiveSlot
)
navigator.navigate(FlashScreenDestination(flashIt))
}
}
}
Unit Unit
} }
val currentKmi by produceState(initialValue = "") {
value = getCurrentKmi()
}
val currentKmi by produceState(initialValue = "") { val currentKmi by produceState(initialValue = "") {
value = getCurrentKmi() value = getCurrentKmi()
} }
@@ -129,8 +193,18 @@ fun InstallScreen(navigator: DestinationsNavigator) {
onInstall() onInstall()
} }
Unit Unit
Unit
} }
val selectLkmLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
it.data?.data?.let { uri ->
lkmSelection = LkmSelection.LkmUri(uri)
}
}
}
val selectLkmLauncher = rememberLauncherForActivityResult( val selectLkmLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult() contract = ActivityResultContracts.StartActivityForResult()
) { ) {
@@ -152,6 +226,7 @@ fun InstallScreen(navigator: DestinationsNavigator) {
Scaffold( Scaffold(
topBar = { topBar = {
TopBar( TopBar(
onBack = { navigator.popBackStack() },
onBack = { navigator.popBackStack() }, onBack = { navigator.popBackStack() },
onLkmUpload = onLkmUpload, onLkmUpload = onLkmUpload,
scrollBehavior = scrollBehavior scrollBehavior = scrollBehavior
@@ -160,6 +235,9 @@ fun InstallScreen(navigator: DestinationsNavigator) {
contentWindowInsets = WindowInsets.safeDrawing.only( contentWindowInsets = WindowInsets.safeDrawing.only(
WindowInsetsSides.Top + WindowInsetsSides.Horizontal WindowInsetsSides.Top + WindowInsetsSides.Horizontal
) )
contentWindowInsets = WindowInsets.safeDrawing.only(
WindowInsetsSides.Top + WindowInsetsSides.Horizontal
)
) { innerPadding -> ) { innerPadding ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -184,10 +262,14 @@ fun InstallScreen(navigator: DestinationsNavigator) {
) )
) )
} }
Button(
modifier = Modifier.fillMaxWidth(),
Button( Button(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = installMethod != null, enabled = installMethod != null,
onClick = onClickNext onClick = onClickNext
) {
onClick = onClickNext
) { ) {
Text( Text(
stringResource(id = R.string.install_next), stringResource(id = R.string.install_next),
@@ -382,6 +464,12 @@ sealed class InstallMethod {
override val summary: String? = null override val summary: String? = null
) : InstallMethod() ) : InstallMethod()
data class HorizonKernel(
val uri: Uri? = null,
@StringRes override val label: Int = R.string.horizon_kernel,
override val summary: String? = null
) : InstallMethod()
abstract val label: Int abstract val label: Int
open val summary: String? = null open val summary: String? = null
} }
@@ -393,8 +481,15 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
val selectFileTip = stringResource( val selectFileTip = stringResource(
id = R.string.select_file_tip, id = R.string.select_file_tip,
if (isInitBoot()) "init_boot" else "boot" if (isInitBoot()) "init_boot" else "boot"
id = R.string.select_file_tip,
if (isInitBoot()) "init_boot" else "boot"
) )
val radioOptions = mutableListOf<InstallMethod>(
InstallMethod.SelectFile(summary = selectFileTip)
)
val radioOptions = mutableListOf<InstallMethod>( val radioOptions = mutableListOf<InstallMethod>(
InstallMethod.SelectFile(summary = selectFileTip) InstallMethod.SelectFile(summary = selectFileTip)
) )
@@ -405,11 +500,14 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
radioOptions.add(InstallMethod.DirectInstallToInactiveSlot) radioOptions.add(InstallMethod.DirectInstallToInactiveSlot)
} }
radioOptions.add(InstallMethod.HorizonKernel(summary = "Flashing the Anykernel3 Kernel")) radioOptions.add(InstallMethod.HorizonKernel(summary = "Flashing the Anykernel3 Kernel"))
radioOptions.add(InstallMethod.HorizonKernel(summary = "Flashing the Anykernel3 Kernel"))
} }
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) }
var currentSelectingMethod by remember { mutableStateOf<InstallMethod?>(null) }
val selectImageLauncher = rememberLauncherForActivityResult( val selectImageLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult() contract = ActivityResultContracts.StartActivityForResult()
) { ) {
@@ -425,6 +523,17 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
onSelected(it) onSelected(it)
} }
} }
}
val option = when (currentSelectingMethod) {
is InstallMethod.SelectFile -> InstallMethod.SelectFile(uri, summary = selectFileTip)
is InstallMethod.HorizonKernel -> InstallMethod.HorizonKernel(uri, summary = " Flashing the Anykernel3 Kernel")
else -> null
}
option?.let {
selectedOption = it
onSelected(it)
}
}
} }
} }
@@ -436,12 +545,22 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
onDismiss = null onDismiss = null
) )
val confirmDialog = rememberConfirmDialog(
onConfirm = {
selectedOption = InstallMethod.DirectInstallToInactiveSlot
onSelected(InstallMethod.DirectInstallToInactiveSlot)
},
onDismiss = null
)
val dialogTitle = stringResource(id = android.R.string.dialog_alert_title) val dialogTitle = stringResource(id = android.R.string.dialog_alert_title)
val dialogContent = stringResource(id = R.string.install_inactive_slot_warning) val dialogContent = stringResource(id = R.string.install_inactive_slot_warning)
val onClick = { option: InstallMethod -> val onClick = { option: InstallMethod ->
currentSelectingMethod = option
currentSelectingMethod = option currentSelectingMethod = option
when (option) { when (option) {
is InstallMethod.SelectFile, is InstallMethod.HorizonKernel -> {
is InstallMethod.SelectFile, is InstallMethod.HorizonKernel -> { is InstallMethod.SelectFile, is InstallMethod.HorizonKernel -> {
selectImageLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { selectImageLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply {
type = "application/*" type = "application/*"
@@ -468,6 +587,7 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
.toggleable( .toggleable(
value = option.javaClass == selectedOption?.javaClass, value = option.javaClass == selectedOption?.javaClass,
onValueChange = { onClick(option) }, onValueChange = { onClick(option) },
onValueChange = { onClick(option) },
role = Role.RadioButton, role = Role.RadioButton,
indication = LocalIndication.current, indication = LocalIndication.current,
interactionSource = interactionSource interactionSource = interactionSource
@@ -476,6 +596,7 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
RadioButton( RadioButton(
selected = option.javaClass == selectedOption?.javaClass, selected = option.javaClass == selectedOption?.javaClass,
onClick = { onClick(option) }, onClick = { onClick(option) },
onClick = { onClick(option) },
interactionSource = interactionSource interactionSource = interactionSource
) )
Column( Column(
@@ -509,8 +630,10 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
value = getSupportedKmis() value = getSupportedKmis()
} }
val options = supportedKmi.map { value -> val options = supportedKmi.map { value ->
ListOption(titleText = value) ListOption(titleText = value)
ListOption(titleText = value)
} }
var selection by remember { mutableStateOf<String?>(null) } var selection by remember { mutableStateOf<String?>(null) }
@@ -535,6 +658,27 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
selection = option.titleText selection = option.titleText
} }
) )
ListDialog(
state = rememberUseCaseState(
visible = true,
onFinishedRequest = {
onSelected(selection)
},
onCloseRequest = {
dismiss()
}
),
header = Header.Default(
title = stringResource(R.string.select_kmi),
),
selection = ListSelection.Single(
showRadioButtons = true,
options = options,
) { _, option ->
selection = option.titleText
}
)
} }
} }
@@ -546,6 +690,13 @@ private fun TopBar(
scrollBehavior: TopAppBarScrollBehavior? = null scrollBehavior: TopAppBarScrollBehavior? = null
) { ) {
TopAppBar( TopAppBar(
title = { Text(stringResource(R.string.install)) },
navigationIcon = {
IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
}
},
actions = {
title = { Text(stringResource(R.string.install)) }, title = { Text(stringResource(R.string.install)) },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
@@ -560,10 +711,14 @@ private fun TopBar(
windowInsets = WindowInsets.safeDrawing.only( windowInsets = WindowInsets.safeDrawing.only(
WindowInsetsSides.Top + WindowInsetsSides.Horizontal WindowInsetsSides.Top + WindowInsetsSides.Horizontal
), ),
windowInsets = WindowInsets.safeDrawing.only(
WindowInsetsSides.Top + WindowInsetsSides.Horizontal
),
scrollBehavior = scrollBehavior scrollBehavior = scrollBehavior
) )
} }
@Preview
@Preview @Preview
@Composable @Composable
fun SelectInstallPreview() { fun SelectInstallPreview() {