diff --git a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/component/Permissions.kt b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/component/Permissions.kt new file mode 100644 index 000000000..33dbb871a --- /dev/null +++ b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/component/Permissions.kt @@ -0,0 +1,30 @@ +package com.topjohnwu.magisk.ui.component + +import android.Manifest.permission.WRITE_EXTERNAL_STORAGE +import android.widget.Toast +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.platform.LocalContext +import com.topjohnwu.magisk.core.R +import com.topjohnwu.magisk.core.base.IActivityExtension +import com.topjohnwu.magisk.core.ktx.toast + +@Composable +fun rememberExternalStoragePermissionLauncher(onGranted: () -> Unit): () -> Unit { + val context = LocalContext.current + val currentOnGranted by rememberUpdatedState(onGranted) + + return remember(context) { + { + (context as IActivityExtension).withPermission(WRITE_EXTERNAL_STORAGE) { granted -> + if (granted) { + currentOnGranted() + } else { + context.toast(R.string.external_rw_permission_denied, Toast.LENGTH_SHORT) + } + } + } + } +} diff --git a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/flash/FlashScreen.kt b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/flash/FlashScreen.kt index e2bc40cbf..741682f16 100644 --- a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/flash/FlashScreen.kt +++ b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/flash/FlashScreen.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.Const +import com.topjohnwu.magisk.ui.component.rememberExternalStoragePermissionLauncher import com.topjohnwu.magisk.ui.terminal.TerminalScreen import com.topjohnwu.magisk.core.R as CoreR @@ -41,6 +42,9 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) { val showReboot by viewModel.showReboot.collectAsState() val finished = flashState != FlashViewModel.State.FLASHING val useTerminal = action == Const.Value.FLASH_ZIP + val saveLog = rememberExternalStoragePermissionLauncher { + viewModel.saveLog() + } val statusText = when (flashState) { FlashViewModel.State.FLASHING -> stringResource(CoreR.string.flashing) @@ -69,7 +73,7 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) { if (finished) { IconButton( modifier = Modifier.padding(end = 4.dp), - onClick = { viewModel.saveLog() } + onClick = saveLog ) { Icon( painter = painterResource(R.drawable.ic_save), diff --git a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/log/LogScreen.kt b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/log/LogScreen.kt index 4588743d3..c81c6107c 100644 --- a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/log/LogScreen.kt +++ b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/log/LogScreen.kt @@ -62,6 +62,7 @@ import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.topjohnwu.magisk.core.ktx.timeDateFormat import com.topjohnwu.magisk.core.ktx.toTime import com.topjohnwu.magisk.core.model.su.SuLog +import com.topjohnwu.magisk.ui.component.rememberExternalStoragePermissionLauncher import com.topjohnwu.magisk.core.R as CoreR @OptIn(ExperimentalMaterial3Api::class) @@ -74,6 +75,9 @@ fun LogScreen(viewModel: LogViewModel) { stringResource(CoreR.string.magisk) ) val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val saveMagiskLog = rememberExternalStoragePermissionLauncher { + viewModel.saveMagiskLog() + } Scaffold( topBar = { @@ -81,7 +85,7 @@ fun LogScreen(viewModel: LogViewModel) { title = { Text(stringResource(CoreR.string.logs)) }, actions = { if (selectedTab == 1) { - IconButton(onClick = { viewModel.saveMagiskLog() }) { + IconButton(onClick = saveMagiskLog) { Icon( imageVector = Icons.Default.Download, contentDescription = stringResource(CoreR.string.save_log), diff --git a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/module/ActionScreen.kt b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/module/ActionScreen.kt index 0f4743157..36a5e6336 100644 --- a/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/module/ActionScreen.kt +++ b/app/apk-ng/src/main/java/com/topjohnwu/magisk/ui/module/ActionScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.ui.component.rememberExternalStoragePermissionLauncher import com.topjohnwu.magisk.ui.terminal.TerminalScreen import com.topjohnwu.magisk.core.R as CoreR @@ -27,6 +28,9 @@ import com.topjohnwu.magisk.core.R as CoreR fun ActionScreen(viewModel: ActionViewModel, actionName: String, onBack: () -> Unit) { val actionState by viewModel.actionState.collectAsState() val finished = actionState != ActionViewModel.State.RUNNING + val saveLog = rememberExternalStoragePermissionLauncher { + viewModel.saveLog() + } val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() Scaffold( @@ -49,7 +53,7 @@ fun ActionScreen(viewModel: ActionViewModel, actionName: String, onBack: () -> U if (finished) { IconButton( modifier = Modifier.padding(end = 16.dp), - onClick = { viewModel.saveLog() } + onClick = saveLog ) { Icon( painter = painterResource(R.drawable.ic_save),