diff --git a/.jules/bolt.md b/.jules/bolt.md index 3f1dfa4..0e2e314 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -7,3 +7,6 @@ ## 2024-08-02 - Debouncing and offloading state derivation in Jetpack Compose **Learning:** In Jetpack Compose, computing expensive operations (like filtering large lists based on user input) directly within a synchronous `remember` block blocks the main UI thread. When this happens on every keystroke in a `TextField`, it causes significant UI stutter and input lag. **Action:** To prevent UI stutter during expensive state derivation, debounce the input using `LaunchedEffect` with `delay` and offload the computation to a background thread using `withContext(Dispatchers.Default)`. This keeps the main thread responsive for typing and animations. +## 2024-08-04 - Code Health Improvement: Use Android's built-in file size formatter +**Learning:** For file size formatting in Android, use `android.text.format.Formatter.formatShortFileSize` or `android.text.format.Formatter.formatFileSize` instead of writing a custom byte conversion function. It's safer, more idiomatic, correctly respects the locale, and reduces boilerplate code. +**Action:** When working with file sizes in a Compose/Android context, default to using the Android framework's built-in `Formatter` utilities instead of custom implementations. diff --git a/app/src/main/java/com/rockmusic/app/presentation/FolderManagerScreen.kt b/app/src/main/java/com/rockmusic/app/presentation/FolderManagerScreen.kt index 54db53f..41fe0b2 100644 --- a/app/src/main/java/com/rockmusic/app/presentation/FolderManagerScreen.kt +++ b/app/src/main/java/com/rockmusic/app/presentation/FolderManagerScreen.kt @@ -7,6 +7,7 @@ import android.net.Uri import android.os.Build import android.provider.Settings import androidx.activity.compose.BackHandler +import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement @@ -317,6 +318,7 @@ private fun FolderRow( enabled: Boolean, onIncludedChange: (Boolean) -> Unit, ) { + val context = LocalContext.current Surface( shape = RoundedCornerShape(20.dp), color = if (included) { @@ -347,7 +349,7 @@ private fun FolderRow( overflow = TextOverflow.Ellipsis, ) Text( - "${folder.songCount} song${if (folder.songCount == 1) "" else "s"} · ${formatBytes(folder.totalBytes)}", + "${folder.songCount} song${if (folder.songCount == 1) "" else "s"} · ${Formatter.formatShortFileSize(context, folder.totalBytes)}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -362,14 +364,3 @@ private fun FolderRow( } } -private fun formatBytes(bytes: Long): String { - if (bytes < 1_024L) return "$bytes B" - val units = arrayOf("KB", "MB", "GB", "TB") - var value = bytes.toDouble() - var unitIndex = -1 - while (value >= 1_024.0 && unitIndex < units.lastIndex) { - value /= 1_024.0 - unitIndex += 1 - } - return String.format(Locale.getDefault(), "%.1f %s", value, units[unitIndex]) -}