From 3a4acd9a16e428cfc127040805cf63dac6603849 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Tue, 10 Mar 2026 14:15:28 +0500 Subject: [PATCH] show OS icon in status banner --- .../sar/isodroid/ui/components/FileBrowser.kt | 10 +- .../sar/isodroid/ui/components/StatusCard.kt | 107 +++++++++++++++--- 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/sh/sar/isodroid/ui/components/FileBrowser.kt b/app/src/main/java/sh/sar/isodroid/ui/components/FileBrowser.kt index 6da334e..925bb83 100644 --- a/app/src/main/java/sh/sar/isodroid/ui/components/FileBrowser.kt +++ b/app/src/main/java/sh/sar/isodroid/ui/components/FileBrowser.kt @@ -20,9 +20,9 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import androidx.compose.material.icons.filled.Album import androidx.compose.material.icons.filled.Folder -import androidx.compose.material.icons.filled.InsertDriveFile import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon @@ -200,8 +200,8 @@ private fun FileItem( Icon( imageVector = when { isIso -> Icons.Default.Album - isImg -> Icons.Default.InsertDriveFile - else -> Icons.Default.InsertDriveFile + isImg -> Icons.AutoMirrored.Filled.InsertDriveFile + else -> Icons.AutoMirrored.Filled.InsertDriveFile }, contentDescription = null, tint = MaterialTheme.colorScheme.onPrimary, @@ -219,8 +219,8 @@ private fun FileItem( imageVector = when { isDirectory -> Icons.Default.Folder isIso -> Icons.Default.Album - isImg -> Icons.Default.InsertDriveFile - else -> Icons.Default.InsertDriveFile + isImg -> Icons.AutoMirrored.Filled.InsertDriveFile + else -> Icons.AutoMirrored.Filled.InsertDriveFile }, contentDescription = null, tint = when { diff --git a/app/src/main/java/sh/sar/isodroid/ui/components/StatusCard.kt b/app/src/main/java/sh/sar/isodroid/ui/components/StatusCard.kt index 0feb2ca..1edfd8b 100644 --- a/app/src/main/java/sh/sar/isodroid/ui/components/StatusCard.kt +++ b/app/src/main/java/sh/sar/isodroid/ui/components/StatusCard.kt @@ -1,15 +1,20 @@ package sh.sar.isodroid.ui.components +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import androidx.compose.material.icons.filled.Album import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Error @@ -22,13 +27,44 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import coil.decode.SvgDecoder +import coil.request.ImageRequest import sh.sar.isodroid.data.MountStatus import sh.sar.isodroid.data.MountType import sh.sar.isodroid.ui.theme.ErrorRed import sh.sar.isodroid.ui.theme.MountedGreen import sh.sar.isodroid.ui.theme.UnmountedGray +import java.io.File + +/** + * Finds a matching OS icon filename for a given file by dynamically checking available icons. + */ +private fun findOsIcon(context: android.content.Context, filename: String): String? { + return try { + val availableIcons = context.assets.list("osicons") + ?.filter { it.endsWith(".svg", ignoreCase = true) } + ?.map { it.removeSuffix(".svg").lowercase() } + ?: emptyList() + + val lowerFilename = filename.lowercase() + + availableIcons + .filter { lowerFilename.contains(it) } + .maxWithOrNull(compareBy( + { it.length }, + { -lowerFilename.indexOf(it) } + )) + ?.let { "$it.svg" } + } catch (e: Exception) { + null + } +} @Composable fun StatusCard( @@ -37,6 +73,8 @@ fun StatusCard( deviceSupported: Boolean?, modifier: Modifier = Modifier ) { + val context = LocalContext.current + // Only show errors when explicitly false (not null = checking) val showRootError = rootAvailable == false val showSupportError = deviceSupported == false @@ -47,6 +85,12 @@ fun StatusCard( return } + // Extract filename and find OS icon if mounted + val fileName = mountStatus.path?.let { File(it).name } + val osIcon = fileName?.let { findOsIcon(context, it) } + val isIso = fileName?.lowercase()?.endsWith(".iso") == true + val isImg = fileName?.lowercase()?.endsWith(".img") == true + Card( modifier = modifier.fillMaxWidth(), colors = CardDefaults.cardColors( @@ -111,24 +155,61 @@ fun StatusCard( } if (mountStatus.mounted) { - Icon( - imageVector = if (mountStatus.type == MountType.CDROM) - Icons.Default.Album - else - Icons.Default.Usb, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(24.dp) - ) + Box(modifier = Modifier.size(40.dp)) { + if (osIcon != null) { + // Show OS icon with file type badge + AsyncImage( + model = ImageRequest.Builder(context) + .data("file:///android_asset/osicons/$osIcon") + .decoderFactory(SvgDecoder.Factory()) + .build(), + contentDescription = fileName, + modifier = Modifier.size(40.dp), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary) + ) + + // Small file type badge in bottom-right corner + Icon( + imageVector = when { + isIso -> Icons.Default.Album + isImg -> Icons.AutoMirrored.Filled.InsertDriveFile + else -> Icons.AutoMirrored.Filled.InsertDriveFile + }, + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier + .size(16.dp) + .align(Alignment.BottomEnd) + .offset(x = 2.dp, y = 2.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary) + .padding(2.dp) + ) + } else { + // Fallback to file type icon + Icon( + imageVector = if (isIso) + Icons.Default.Album + else if (isImg) + Icons.AutoMirrored.Filled.InsertDriveFile + else + Icons.Default.Usb, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(40.dp) + ) + } + } } } - if (mountStatus.mounted && mountStatus.path != null) { + if (mountStatus.mounted && fileName != null) { Spacer(modifier = Modifier.height(12.dp)) Text( - text = mountStatus.path, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant + text = fileName, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.onSurface ) Spacer(modifier = Modifier.height(4.dp)) Row {