Fix flickering status card on app startup
This commit is contained in:
1
app/src/main/assets/osicons/arch.svg
Symbolic link
1
app/src/main/assets/osicons/arch.svg
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
archlinux.svg
|
||||||
1
app/src/main/assets/osicons/artix.svg
Symbolic link
1
app/src/main/assets/osicons/artix.svg
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
artixlinux.svg
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 = "",
|
||||||
|
|||||||
Reference in New Issue
Block a user