Fix flickering status card on app startup

This commit is contained in:
2026-03-10 14:04:36 +05:00
parent 569b946200
commit 67392cbdae
6 changed files with 29 additions and 16 deletions

View File

@@ -0,0 +1 @@
archlinux.svg

View File

@@ -0,0 +1 @@
artixlinux.svg

View File

@@ -33,16 +33,25 @@ import sh.sar.isodroid.ui.theme.UnmountedGray
@Composable @Composable
fun StatusCard( fun StatusCard(
mountStatus: MountStatus, mountStatus: MountStatus,
rootAvailable: Boolean, rootAvailable: Boolean?,
deviceSupported: Boolean, deviceSupported: Boolean?,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
// Only show errors when explicitly false (not null = checking)
val showRootError = rootAvailable == false
val showSupportError = deviceSupported == false
val hasError = showRootError || showSupportError
// Hide card completely until checks are done
if (rootAvailable == null || (rootAvailable == true && deviceSupported == null)) {
return
}
Card( Card(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = when { containerColor = when {
!rootAvailable -> MaterialTheme.colorScheme.errorContainer hasError -> MaterialTheme.colorScheme.errorContainer
!deviceSupported -> MaterialTheme.colorScheme.errorContainer
mountStatus.mounted -> MaterialTheme.colorScheme.primaryContainer mountStatus.mounted -> MaterialTheme.colorScheme.primaryContainer
else -> MaterialTheme.colorScheme.surfaceVariant else -> MaterialTheme.colorScheme.surfaceVariant
} }
@@ -61,13 +70,13 @@ fun StatusCard(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon( Icon(
imageVector = when { imageVector = when {
!rootAvailable || !deviceSupported -> Icons.Default.Error hasError -> Icons.Default.Error
mountStatus.mounted -> Icons.Default.CheckCircle mountStatus.mounted -> Icons.Default.CheckCircle
else -> Icons.Default.Usb else -> Icons.Default.Usb
}, },
contentDescription = null, contentDescription = null,
tint = when { tint = when {
!rootAvailable || !deviceSupported -> ErrorRed hasError -> ErrorRed
mountStatus.mounted -> MountedGreen mountStatus.mounted -> MountedGreen
else -> UnmountedGray else -> UnmountedGray
}, },
@@ -77,21 +86,21 @@ fun StatusCard(
Column { Column {
Text( Text(
text = when { text = when {
!rootAvailable -> "Root Access Required" showRootError -> "Root Access Required"
!deviceSupported -> "Device Not Supported" showSupportError -> "Device Not Supported"
mountStatus.mounted -> "Mounted" mountStatus.mounted -> "Mounted"
else -> "Not Mounted" else -> "Not Mounted"
}, },
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
if (!rootAvailable) { if (showRootError) {
Text( Text(
text = "Grant root access to use ISODroid", text = "Grant root access to use ISODroid",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} else if (!deviceSupported) { } else if (showSupportError) {
Text( Text(
text = "USB gadget not supported on this device", text = "USB gadget not supported on this device",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,

View File

@@ -92,7 +92,7 @@ fun MainScreen(
actions = { actions = {
IconButton( IconButton(
onClick = { showCreateImgDialog = true }, onClick = { showCreateImgDialog = true },
enabled = uiState.hasRoot && uiState.isSupported enabled = uiState.hasRoot == true && uiState.isSupported == true
) { ) {
Icon( Icon(
imageVector = Icons.Default.Add, imageVector = Icons.Default.Add,
@@ -163,7 +163,7 @@ fun MainScreen(
) { ) {
CircularProgressIndicator() CircularProgressIndicator()
} }
} else if (uiState.hasRoot && uiState.isSupported) { } else if (uiState.hasRoot == true && uiState.isSupported == true) {
FileBrowser( FileBrowser(
files = uiState.isoFiles, files = uiState.isoFiles,
currentPath = uiState.currentPath, currentPath = uiState.currentPath,

View File

@@ -163,7 +163,7 @@ fun SettingsScreen(
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) { ) {
// Root Access status // Root Access status
val hasRoot = uiState.hasRoot val hasRoot = uiState.hasRoot ?: false
val rootDenied = uiState.rootDenied val rootDenied = uiState.rootDenied
PermissionStatusItem( PermissionStatusItem(
icon = Icons.Default.Security, icon = Icons.Default.Security,

View File

@@ -178,6 +178,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
loadFiles() loadFiles()
checkMountStatus() checkMountStatus()
} }
} else {
_uiState.update { it.copy(isSupported = false) }
} }
_uiState.update { it.copy(isLoading = false) } _uiState.update { it.copy(isLoading = false) }
@@ -380,7 +382,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
viewModelScope.launch { viewModelScope.launch {
// Check cached status (no popup) // Check cached status (no popup)
val cachedStatus = RootManager.isRootGrantedCached() val cachedStatus = RootManager.isRootGrantedCached()
if (cachedStatus == true && !_uiState.value.hasRoot) { if (cachedStatus == true && _uiState.value.hasRoot != true) {
// Root was granted externally (e.g., in Magisk settings) // Root was granted externally (e.g., in Magisk settings)
_uiState.update { it.copy(hasRoot = true, rootDenied = false) } _uiState.update { it.copy(hasRoot = true, rootDenied = false) }
@@ -546,9 +548,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
data class MainUiState( data class MainUiState(
val isLoading: Boolean = true, val isLoading: Boolean = true,
val hasRoot: Boolean = false, val hasRoot: Boolean? = null, // null = checking, true = granted, false = denied
val rootDenied: Boolean = false, // True if user denied root in Magisk val rootDenied: Boolean = false, // True if user denied root in Magisk
val isSupported: Boolean = false, val isSupported: Boolean? = null, // null = checking, true = supported, false = not supported
val mountStatus: MountStatus = MountStatus.UNMOUNTED, val mountStatus: MountStatus = MountStatus.UNMOUNTED,
val isoFiles: List<IsoFile> = emptyList(), val isoFiles: List<IsoFile> = emptyList(),
val currentPath: String = "", val currentPath: String = "",