Add USB services restart warning
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package sh.sar.isodroid.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun UsbWarningDialog(
|
||||
isUnmount: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: (dontShowAgain: Boolean) -> Unit
|
||||
) {
|
||||
var dontShowAgain by remember { mutableStateOf(false) }
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(
|
||||
text = "USB Services Will Restart",
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
text = if (isUnmount) {
|
||||
"Unmounting will restart USB services on your device, including:"
|
||||
} else {
|
||||
"Mounting will restart USB services on your device, including:"
|
||||
},
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = "• MTP file transfer\n• USB ADB\n• USB tethering\n• Other USB functions",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = "Active file transfers may be interrupted and could result in data corruption. Make sure no transfers are in progress.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Checkbox(
|
||||
checked = dontShowAgain,
|
||||
onCheckedChange = { dontShowAgain = it }
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "Don't show this again",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = { onConfirm(dontShowAgain) }
|
||||
) {
|
||||
Text(if (isUnmount) "Unmount" else "Mount")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -49,14 +49,17 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.sar.isodroid.data.IsoFile
|
||||
import sh.sar.isodroid.data.MountOptions
|
||||
import sh.sar.isodroid.ui.components.CreateImgDialog
|
||||
import sh.sar.isodroid.ui.components.FileContextMenu
|
||||
import sh.sar.isodroid.ui.components.FileItemCard
|
||||
import sh.sar.isodroid.ui.components.MountDialog
|
||||
import sh.sar.isodroid.ui.components.StatusCard
|
||||
import sh.sar.isodroid.ui.components.UsbWarningDialog
|
||||
import sh.sar.isodroid.viewmodel.MainViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -69,12 +72,38 @@ fun MainScreen(
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
var selectedFile by remember { mutableStateOf<IsoFile?>(null) }
|
||||
var showMountDialog by remember { mutableStateOf(false) }
|
||||
var showCreateImgDialog by remember { mutableStateOf(false) }
|
||||
var contextMenuFile by remember { mutableStateOf<IsoFile?>(null) }
|
||||
|
||||
// USB warning dialog state
|
||||
var showUsbWarning by remember { mutableStateOf(false) }
|
||||
var pendingMountPath by remember { mutableStateOf<String?>(null) }
|
||||
var pendingMountOptions by remember { mutableStateOf<MountOptions?>(null) }
|
||||
var isUnmountWarning by remember { mutableStateOf(false) }
|
||||
|
||||
val prefs = remember { context.getSharedPreferences("iso_drive_prefs", android.content.Context.MODE_PRIVATE) }
|
||||
val skipUsbWarning = remember { mutableStateOf(prefs.getBoolean("skip_usb_warning", false)) }
|
||||
|
||||
fun showUsbWarningOrProceed(
|
||||
isUnmount: Boolean,
|
||||
mountPath: String? = null,
|
||||
mountOptions: MountOptions? = null,
|
||||
onProceed: () -> Unit
|
||||
) {
|
||||
if (skipUsbWarning.value) {
|
||||
onProceed()
|
||||
} else {
|
||||
isUnmountWarning = isUnmount
|
||||
pendingMountPath = mountPath
|
||||
pendingMountOptions = mountOptions
|
||||
showUsbWarning = true
|
||||
}
|
||||
}
|
||||
|
||||
val pullToRefreshState = rememberPullToRefreshState()
|
||||
|
||||
// Handle pull-to-refresh
|
||||
@@ -150,8 +179,10 @@ fun MainScreen(
|
||||
if (uiState.mountStatus.mounted) {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
viewModel.unmount()
|
||||
showUsbWarningOrProceed(isUnmount = true) {
|
||||
scope.launch {
|
||||
viewModel.unmount()
|
||||
}
|
||||
}
|
||||
},
|
||||
icon = {
|
||||
@@ -295,8 +326,14 @@ fun MainScreen(
|
||||
val filePath = file.path // Capture path before clearing state
|
||||
showMountDialog = false
|
||||
selectedFile = null
|
||||
scope.launch {
|
||||
viewModel.mount(filePath, options)
|
||||
showUsbWarningOrProceed(
|
||||
isUnmount = false,
|
||||
mountPath = filePath,
|
||||
mountOptions = options
|
||||
) {
|
||||
scope.launch {
|
||||
viewModel.mount(filePath, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -337,4 +374,39 @@ fun MainScreen(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// USB warning dialog
|
||||
if (showUsbWarning) {
|
||||
UsbWarningDialog(
|
||||
isUnmount = isUnmountWarning,
|
||||
onDismiss = {
|
||||
showUsbWarning = false
|
||||
pendingMountPath = null
|
||||
pendingMountOptions = null
|
||||
},
|
||||
onConfirm = { dontShowAgain ->
|
||||
if (dontShowAgain) {
|
||||
prefs.edit().putBoolean("skip_usb_warning", true).apply()
|
||||
skipUsbWarning.value = true
|
||||
}
|
||||
|
||||
// Capture values before clearing state
|
||||
val isUnmount = isUnmountWarning
|
||||
val path = pendingMountPath
|
||||
val options = pendingMountOptions
|
||||
|
||||
showUsbWarning = false
|
||||
pendingMountPath = null
|
||||
pendingMountOptions = null
|
||||
|
||||
scope.launch {
|
||||
if (isUnmount) {
|
||||
viewModel.unmount()
|
||||
} else if (path != null && options != null) {
|
||||
viewModel.mount(path, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user