refactor(util): extract FormatUtils and deduplicate byte formatting
Consolidate formatBytes and formatDuration into util/FormatUtils. Use in SystemScreen and MemoryScreen, backed by unit tests.
This commit is contained in:
@@ -62,6 +62,7 @@ import com.m57.hermescontrol.ui.common.listContentPadding
|
|||||||
import com.m57.hermescontrol.ui.common.listItemSpacing
|
import com.m57.hermescontrol.ui.common.listItemSpacing
|
||||||
import com.m57.hermescontrol.ui.plugins.memoryProviderStatusLabel
|
import com.m57.hermescontrol.ui.plugins.memoryProviderStatusLabel
|
||||||
import com.m57.hermescontrol.ui.plugins.memoryProviderStatusType
|
import com.m57.hermescontrol.ui.plugins.memoryProviderStatusType
|
||||||
|
import com.m57.hermescontrol.util.formatBytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory management home — owns the memory surface that used to live in the
|
* Memory management home — owns the memory surface that used to live in the
|
||||||
@@ -425,10 +426,3 @@ private fun MemoryProviderRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatBytes(bytes: Long): String =
|
|
||||||
when {
|
|
||||||
bytes >= 1024 * 1024 -> "%.1f MB".format(bytes / (1024.0 * 1024.0))
|
|
||||||
bytes >= 1024 -> "%.1f KB".format(bytes / 1024.0)
|
|
||||||
else -> "$bytes B"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -96,31 +96,12 @@ import com.m57.hermescontrol.ui.common.StatusBadgeType
|
|||||||
import com.m57.hermescontrol.ui.common.ToastEffect
|
import com.m57.hermescontrol.ui.common.ToastEffect
|
||||||
import com.m57.hermescontrol.ui.system.components.CredentialEntryRow
|
import com.m57.hermescontrol.ui.system.components.CredentialEntryRow
|
||||||
import com.m57.hermescontrol.ui.system.components.HookCard
|
import com.m57.hermescontrol.ui.system.components.HookCard
|
||||||
|
import com.m57.hermescontrol.util.formatBytes
|
||||||
|
import com.m57.hermescontrol.util.formatDuration
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
private fun formatBytes(bytes: Long): String =
|
|
||||||
when {
|
|
||||||
bytes < 1024 -> "$bytes B"
|
|
||||||
bytes < 1024 * 1024 -> "${bytes / 1024} KB"
|
|
||||||
bytes < 1024 * 1024 * 1024 -> "${bytes / (1024 * 1024)} MB"
|
|
||||||
else -> "${"%.1f".format(bytes.toDouble() / (1024 * 1024 * 1024))} GB"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun formatDuration(totalSeconds: Double): String {
|
|
||||||
val days = (totalSeconds / 86400).toInt()
|
|
||||||
val hours = ((totalSeconds % 86400) / 3600).toInt()
|
|
||||||
val minutes = ((totalSeconds % 3600) / 60).toInt()
|
|
||||||
return buildString {
|
|
||||||
if (days > 0) append("${days}d ")
|
|
||||||
if (hours > 0 || days > 0) append("${hours}h ")
|
|
||||||
append("${minutes}m")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(androidx.compose.foundation.layout.ExperimentalLayoutApi::class)
|
@OptIn(androidx.compose.foundation.layout.ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SystemScreen(
|
fun SystemScreen(
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.m57.hermescontrol.util
|
||||||
|
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a byte count into human-readable B, KB, MB, or GB.
|
||||||
|
*/
|
||||||
|
fun formatBytes(bytes: Long): String =
|
||||||
|
when {
|
||||||
|
bytes < 1024 -> "$bytes B"
|
||||||
|
bytes < 1024 * 1024 -> "${bytes / 1024} KB"
|
||||||
|
bytes < 1024 * 1024 * 1024 -> "${bytes / (1024 * 1024)} MB"
|
||||||
|
else -> String.format(Locale.US, "%.1f GB", bytes.toDouble() / (1024 * 1024 * 1024))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats seconds into a human-readable duration (e.g. "2d 4h 15m").
|
||||||
|
*/
|
||||||
|
fun formatDuration(totalSeconds: Double): String {
|
||||||
|
val days = (totalSeconds / 86400).toInt()
|
||||||
|
val hours = ((totalSeconds % 86400) / 3600).toInt()
|
||||||
|
val minutes = ((totalSeconds % 3600) / 60).toInt()
|
||||||
|
return buildString {
|
||||||
|
if (days > 0) append("${days}d ")
|
||||||
|
if (hours > 0 || days > 0) append("${hours}h ")
|
||||||
|
append("${minutes}m")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.m57.hermescontrol.util
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class FormatUtilsTest {
|
||||||
|
@Test
|
||||||
|
fun testFormatBytes_bytes() {
|
||||||
|
assertEquals("0 B", formatBytes(0L))
|
||||||
|
assertEquals("500 B", formatBytes(500L))
|
||||||
|
assertEquals("1023 B", formatBytes(1023L))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatBytes_kilobytes() {
|
||||||
|
assertEquals("1 KB", formatBytes(1024L))
|
||||||
|
assertEquals("2 KB", formatBytes(2048L))
|
||||||
|
assertEquals("1023 KB", formatBytes(1024 * 1024 - 1L))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatBytes_megabytes() {
|
||||||
|
assertEquals("1 MB", formatBytes(1024 * 1024L))
|
||||||
|
assertEquals("500 MB", formatBytes(500 * 1024 * 1024L))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatBytes_gigabytes() {
|
||||||
|
assertEquals("1.0 GB", formatBytes(1024 * 1024 * 1024L))
|
||||||
|
assertEquals("2.5 GB", formatBytes((2.5 * 1024 * 1024 * 1024).toLong()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatDuration_minutes() {
|
||||||
|
assertEquals("0m", formatDuration(0.0))
|
||||||
|
assertEquals("0m", formatDuration(45.0))
|
||||||
|
assertEquals("1m", formatDuration(60.0))
|
||||||
|
assertEquals("59m", formatDuration(3540.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatDuration_hoursAndMinutes() {
|
||||||
|
assertEquals("1h 0m", formatDuration(3600.0))
|
||||||
|
assertEquals("1h 1m", formatDuration(3660.0))
|
||||||
|
assertEquals("23h 59m", formatDuration(86399.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatDuration_daysHoursMinutes() {
|
||||||
|
assertEquals("1d 0h 0m", formatDuration(86400.0))
|
||||||
|
assertEquals("1d 1h 1m", formatDuration(90060.0))
|
||||||
|
assertEquals("3d 5h 30m", formatDuration(3 * 86400.0 + 5 * 3600.0 + 30 * 60.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user