From 9aa79e02bc565cf080706ae60db676ec4014e042 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Tue, 10 Mar 2026 13:06:07 +0500 Subject: [PATCH] show OS icon in home file manager --- app/src/main/assets/osicons/alpinelinux.svg | 1 + app/src/main/assets/osicons/artixlinux.svg | 1 + app/src/main/assets/osicons/garudalinux.svg | 1 + app/src/main/assets/osicons/kalilinux.svg | 1 + app/src/main/assets/osicons/linux.svg | 1 + app/src/main/assets/osicons/mxlinux.svg | 1 + app/src/main/assets/osicons/nobaralinux.svg | 1 + app/src/main/assets/osicons/proxmox.svg | 1 + app/src/main/assets/osicons/rockylinux.svg | 1 + app/src/main/assets/osicons/voidlinux.svg | 1 + .../sar/isodroid/ui/components/FileBrowser.kt | 111 ++++++++++++++++-- 11 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 app/src/main/assets/osicons/alpinelinux.svg create mode 100644 app/src/main/assets/osicons/artixlinux.svg create mode 100644 app/src/main/assets/osicons/garudalinux.svg create mode 100644 app/src/main/assets/osicons/kalilinux.svg create mode 100644 app/src/main/assets/osicons/linux.svg create mode 100644 app/src/main/assets/osicons/mxlinux.svg create mode 100644 app/src/main/assets/osicons/nobaralinux.svg create mode 100644 app/src/main/assets/osicons/proxmox.svg create mode 100644 app/src/main/assets/osicons/rockylinux.svg create mode 100644 app/src/main/assets/osicons/voidlinux.svg diff --git a/app/src/main/assets/osicons/alpinelinux.svg b/app/src/main/assets/osicons/alpinelinux.svg new file mode 100644 index 0000000..c554fb8 --- /dev/null +++ b/app/src/main/assets/osicons/alpinelinux.svg @@ -0,0 +1 @@ +Alpine Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/artixlinux.svg b/app/src/main/assets/osicons/artixlinux.svg new file mode 100644 index 0000000..4b653dd --- /dev/null +++ b/app/src/main/assets/osicons/artixlinux.svg @@ -0,0 +1 @@ +Artix Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/garudalinux.svg b/app/src/main/assets/osicons/garudalinux.svg new file mode 100644 index 0000000..d0f7d8b --- /dev/null +++ b/app/src/main/assets/osicons/garudalinux.svg @@ -0,0 +1 @@ +Garuda Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/kalilinux.svg b/app/src/main/assets/osicons/kalilinux.svg new file mode 100644 index 0000000..f308f11 --- /dev/null +++ b/app/src/main/assets/osicons/kalilinux.svg @@ -0,0 +1 @@ +Kali Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/linux.svg b/app/src/main/assets/osicons/linux.svg new file mode 100644 index 0000000..381d3d8 --- /dev/null +++ b/app/src/main/assets/osicons/linux.svg @@ -0,0 +1 @@ +Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/mxlinux.svg b/app/src/main/assets/osicons/mxlinux.svg new file mode 100644 index 0000000..7805a52 --- /dev/null +++ b/app/src/main/assets/osicons/mxlinux.svg @@ -0,0 +1 @@ +MX Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/nobaralinux.svg b/app/src/main/assets/osicons/nobaralinux.svg new file mode 100644 index 0000000..6ce9e46 --- /dev/null +++ b/app/src/main/assets/osicons/nobaralinux.svg @@ -0,0 +1 @@ +Nobara Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/proxmox.svg b/app/src/main/assets/osicons/proxmox.svg new file mode 100644 index 0000000..395ffb8 --- /dev/null +++ b/app/src/main/assets/osicons/proxmox.svg @@ -0,0 +1 @@ +Proxmox \ No newline at end of file diff --git a/app/src/main/assets/osicons/rockylinux.svg b/app/src/main/assets/osicons/rockylinux.svg new file mode 100644 index 0000000..af412a5 --- /dev/null +++ b/app/src/main/assets/osicons/rockylinux.svg @@ -0,0 +1 @@ +Rocky Linux \ No newline at end of file diff --git a/app/src/main/assets/osicons/voidlinux.svg b/app/src/main/assets/osicons/voidlinux.svg new file mode 100644 index 0000000..a664c64 --- /dev/null +++ b/app/src/main/assets/osicons/voidlinux.svg @@ -0,0 +1 @@ +Void Linux \ No newline at end of file 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 622e2ed..6da334e 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 @@ -1,8 +1,10 @@ package sh.sar.isodroid.ui.components import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -10,11 +12,13 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize 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.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.filled.Album import androidx.compose.material.icons.filled.Folder @@ -27,12 +31,48 @@ 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.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import coil.decode.SvgDecoder +import coil.request.ImageRequest import sh.sar.isodroid.data.IsoFile +/** + * Finds a matching OS icon filename for a given file by dynamically checking available icons. + * Returns the icon filename (e.g., "archlinux.svg") if a match is found, null otherwise. + * When multiple matches exist (e.g., "nixos" and "linux"), prioritizes: + * 1. Longest match (most specific) + * 2. Earliest position in filename (if same length) + */ +private fun findOsIcon(context: android.content.Context, filename: String): String? { + return try { + // Dynamically load available icon files from assets + val availableIcons = context.assets.list("osicons") + ?.filter { it.endsWith(".svg", ignoreCase = true) } + ?.map { it.removeSuffix(".svg").lowercase() } + ?: emptyList() + + val lowerFilename = filename.lowercase() + + // Find ALL matching icons, then return the best match + availableIcons + .filter { lowerFilename.contains(it) } + .maxWithOrNull(compareBy( + { it.length }, // Prefer longer matches + { -lowerFilename.indexOf(it) } // Then prefer earlier position (negated for descending) + )) + ?.let { "$it.svg" } + } catch (e: Exception) { + null + } +} + @Composable fun FileBrowser( files: List, @@ -95,6 +135,7 @@ fun FileBrowser( name = file.name, size = file.formattedSize, isIso = file.name.lowercase().endsWith(".iso"), + isImg = file.name.lowercase().endsWith(".img"), onClick = { onFileClick(file) }, onLongClick = { hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) @@ -114,9 +155,14 @@ private fun FileItem( size: String, isDirectory: Boolean = false, isIso: Boolean = true, + isImg: Boolean = false, onClick: () -> Unit, onLongClick: (() -> Unit)? ) { + val context = LocalContext.current + val osIcon = if (!isDirectory) findOsIcon(context, name) else null + val iconTint = MaterialTheme.colorScheme.primary + Card( modifier = Modifier .fillMaxWidth() @@ -134,20 +180,59 @@ private fun FileItem( .padding(12.dp), verticalAlignment = Alignment.CenterVertically ) { - Icon( - imageVector = when { - isDirectory -> Icons.Default.Folder - isIso -> Icons.Default.Album - else -> Icons.Default.InsertDriveFile - }, - contentDescription = null, - tint = when { - isDirectory -> MaterialTheme.colorScheme.primary - isIso -> MaterialTheme.colorScheme.primary - else -> MaterialTheme.colorScheme.secondary - }, + // Icon with file type indicator + Box( modifier = Modifier.size(40.dp) - ) + ) { + if (osIcon != null) { + // Show OS icon from SVG + AsyncImage( + model = ImageRequest.Builder(context) + .data("file:///android_asset/osicons/$osIcon") + .decoderFactory(SvgDecoder.Factory()) + .build(), + contentDescription = name, + modifier = Modifier.fillMaxSize(), + colorFilter = ColorFilter.tint(iconTint) + ) + + // Small file type indicator in bottom-right corner + Icon( + imageVector = when { + isIso -> Icons.Default.Album + isImg -> Icons.Default.InsertDriveFile + else -> Icons.Default.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 standard Material icons + Icon( + imageVector = when { + isDirectory -> Icons.Default.Folder + isIso -> Icons.Default.Album + isImg -> Icons.Default.InsertDriveFile + else -> Icons.Default.InsertDriveFile + }, + contentDescription = null, + tint = when { + isDirectory -> MaterialTheme.colorScheme.primary + isIso -> MaterialTheme.colorScheme.primary + else -> MaterialTheme.colorScheme.secondary + }, + modifier = Modifier.fillMaxSize() + ) + } + } + Spacer(modifier = Modifier.width(12.dp)) Column(modifier = Modifier.weight(1f)) { Text(