Skip to content

Commit

Permalink
manager: allow multiple modules to be installed sequentially
Browse files Browse the repository at this point in the history
  • Loading branch information
rifsxd committed Jan 15, 2025
1 parent af05e5d commit 2f42ebd
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 13 deletions.
44 changes: 44 additions & 0 deletions manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Flash.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
Expand All @@ -76,6 +77,43 @@ enum class FlashingStatus {
FAILED
}

// Lets you flash modules sequentially when mutiple zipUris are selected
fun flashModulesSequentially(
uris: List<Uri>,
onFinish: (Boolean, Int) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
) {
val iterator = uris.iterator()

// Start processing from the first module inside a coroutine
CoroutineScope(Dispatchers.IO).launch {
// Define the recursive function within the coroutine
suspend fun processNext() {
if (iterator.hasNext()) {
// Flash the current module
flashModule(iterator.next(), onFinish = { showReboot, code ->
// If successful, continue to the next one
if (code == 0) {
// Recursively call to process the next module
launch {
processNext()
}
} else {
onFinish(showReboot, code) // If failed, finish the process
}
}, onStdout, onStderr)
} else {
// No more modules to process, finish the process
onFinish(true, 0)
}
}

// Start the process
processNext()
}
}

/**
* @author weishu
* @date 2023/1/1.
Expand Down Expand Up @@ -202,6 +240,8 @@ sealed class FlashIt : Parcelable {

data class FlashModule(val uri: Uri) : FlashIt()

data class FlashModules(val uris: List<Uri>) : FlashIt()

data object FlashRestore : FlashIt()

data object FlashUninstall : FlashIt()
Expand All @@ -224,6 +264,10 @@ fun flashIt(

is FlashIt.FlashModule -> flashModule(flashIt.uri, onFinish, onStdout, onStderr)

is FlashIt.FlashModules -> {
flashModulesSequentially(flashIt.uris, onFinish, onStdout, onStderr)
}

FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr)

FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr)
Expand Down
34 changes: 21 additions & 13 deletions manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())

var zipUri by remember { mutableStateOf<Uri?>(null) }
var zipUris by remember { mutableStateOf<List<Uri>>(emptyList()) }

var showConfirmDialog by remember { mutableStateOf(false) }

val webUILauncher = rememberLauncherForActivityResult(
Expand Down Expand Up @@ -216,18 +218,27 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
return@rememberLauncherForActivityResult
}
val data = result.data ?: return@rememberLauncherForActivityResult
val uri = data.data ?: return@rememberLauncherForActivityResult
val clipData = data.clipData

val uris = mutableListOf<Uri>()
if (clipData != null) {
for (i in 0 until clipData.itemCount) {
clipData.getItemAt(i)?.uri?.let { uris.add(it) }
}
} else {
data.data?.let { uris.add(it) }
}

// save the selected Uri and trigger confirmation dialog
zipUri = uri
showConfirmDialog = true
zipUris = uris
showConfirmDialog = uris.isNotEmpty()
}

ExtendedFloatingActionButton(
onClick = {
// select the zip file to install
// Select the zip files to install
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "application/zip"
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
selectZipLauncher.launch(intent)
},
Expand All @@ -239,17 +250,16 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
snackbarHost = { SnackbarHost(hostState = snackBarHost) }
) { innerPadding ->
// confirmation dialog
if (showConfirmDialog && zipUri != null) {
val moduleName = getFileName(context, zipUri!!)
// Confirmation dialog
if (showConfirmDialog && zipUris.isNotEmpty()) {
val moduleNames = zipUris.joinToString("\n") { getFileName(context, it) }

AlertDialog(
onDismissRequest = { showConfirmDialog = false },
confirmButton = {
TextButton(onClick = {
showConfirmDialog = false
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(zipUri!!)))

navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(zipUris)))
viewModel.markNeedRefresh()
}) {
Text(stringResource(R.string.confirm))
Expand All @@ -263,13 +273,11 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
title = { Text(stringResource(R.string.module)) },
text = {
Text(
stringResource(R.string.module_install_prompt_with_name, moduleName)
stringResource(R.string.module_install_prompt_with_name, moduleNames)
)
}
)
}


when {
hasMagisk -> {
Box(
Expand Down

0 comments on commit 2f42ebd

Please sign in to comment.