diff --git a/manager/app/src/main/AndroidManifest.xml b/manager/app/src/main/AndroidManifest.xml index c3ec0dea..9c4fdfea 100644 --- a/manager/app/src/main/AndroidManifest.xml +++ b/manager/app/src/main/AndroidManifest.xml @@ -24,6 +24,15 @@ + + + + + + + + + { + intent.data ?: intent.getParcelableExtra(Intent.EXTRA_STREAM) + } + else -> null + }?.takeIf { it.toString().endsWith(".zip", ignoreCase = true) } + setContent { // Read AMOLED mode preference val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE) @@ -82,6 +94,18 @@ class MainActivity : ComponentActivity() { val snackBarHostState = remember { SnackbarHostState() } val currentDestination = navController.currentBackStackEntryAsState()?.value?.destination + val navigator = navController.rememberDestinationsNavigator() + + LaunchedEffect(zipUri) { + if (zipUri != null) { + navigator.navigate( + FlashScreenDestination( + FlashIt.FlashModules(listOf(zipUri)) + ) + ) + } + } + val showBottomBar = when (currentDestination?.route) { FlashScreenDestination.route -> false // Hide for FlashScreenDestination ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Flash.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Flash.kt index b3b9e82a..9d5bbb63 100644 --- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Flash.kt +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Flash.kt @@ -63,6 +63,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import com.rifsxd.ksunext.R +import com.rifsxd.ksunext.ui.component.rememberConfirmDialog +import com.rifsxd.ksunext.ui.component.ConfirmResult import com.rifsxd.ksunext.ui.component.KeyEventBlocker import com.rifsxd.ksunext.ui.util.FlashResult import com.rifsxd.ksunext.ui.util.LkmSelection @@ -138,12 +140,41 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { // Disable back button if flashing is running } - LaunchedEffect(Unit) { - if (text.isNotEmpty()) { - return@LaunchedEffect + val confirmDialog = rememberConfirmDialog() + var confirmed by rememberSaveable { mutableStateOf(flashIt !is FlashIt.FlashModules) } + var pendingFlashIt by rememberSaveable { mutableStateOf(null) } + + LaunchedEffect(flashIt) { + if (flashIt is FlashIt.FlashModules && !confirmed) { + val uris = flashIt.uris + val moduleNames = + uris.mapIndexed { index, uri -> "\n${index + 1}. ${uri.getFileName(context)}" } + .joinToString("") + val confirmContent = + context.getString(R.string.module_install_prompt_with_name, moduleNames) + val confirmTitle = context.getString(R.string.module) + val result = confirmDialog.awaitConfirm( + title = confirmTitle, + content = confirmContent, + markdown = true + ) + if (result == ConfirmResult.Confirmed) { + confirmed = true + pendingFlashIt = flashIt + } else { + // User cancelled, go back + navigator.popBackStack() + } + } else { + confirmed = true + pendingFlashIt = flashIt } + } + + LaunchedEffect(confirmed, pendingFlashIt) { + if (!confirmed || pendingFlashIt == null || text.isNotEmpty()) return@LaunchedEffect withContext(Dispatchers.IO) { - flashIt(flashIt, onStdout = { + flashIt(pendingFlashIt!!, onStdout = { tempText = "$it\n" if (tempText.startsWith("")) { // clear command text = tempText.substring(6) @@ -282,6 +313,19 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { } } +fun Uri.getFileName(context: Context): String { + val contentResolver = context.contentResolver + val cursor = contentResolver.query(this, null, null, null, null) + return cursor?.use { + val nameIndex = it.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME) + if (it.moveToFirst() && nameIndex != -1) { + it.getString(nameIndex) + } else { + this.lastPathSegment ?: "unknown.zip" + } + } ?: (this.lastPathSegment ?: "unknown.zip") +} + @Parcelize sealed class FlashIt : Parcelable { data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) : diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt index 525c557f..a82bdc14 100644 --- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt @@ -291,15 +291,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) { floatingActionButton = { if (!hideInstallButton) { val moduleInstall = stringResource(id = R.string.module_install) - val confirmTitle = stringResource(R.string.module) - var zipUris by remember { mutableStateOf>(emptyList()) } - val confirmDialog = rememberConfirmDialog(onConfirm = { - if (viewModel.zipUris.isNotEmpty()) { - navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(viewModel.zipUris))) - viewModel.clearZipUris() - viewModel.markNeedRefresh() - } - }) val selectZipLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { result -> @@ -322,19 +313,9 @@ fun ModuleScreen(navigator: DestinationsNavigator) { viewModel.updateZipUris(uris) - // Show confirm dialog with selected zip file(s) name(s) - val moduleNames = - uris.mapIndexed { index, uri -> "\n${index + 1}. ${uri.getFileName(context)}" } - .joinToString("") - val confirmContent = - context.getString(R.string.module_install_prompt_with_name, moduleNames) - zipUris = uris - confirmDialog.showConfirm( - title = confirmTitle, - content = confirmContent, - markdown = true - ) - + navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(uris))) + viewModel.clearZipUris() + viewModel.markNeedRefresh() } ExtendedFloatingActionButton(