diff --git a/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt b/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt index fc0e08e5bc..bb0122bc5b 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt @@ -413,6 +413,7 @@ fun AppContent( AppScaffold( topBarconfig = scaffoldConfig.topBarConfig, bottomBarConfig = scaffoldConfig.bottomBarConfig, + onScaffoldEvent = handleScaffoldEvent, snackbarHostState = snackbarHostState, ) { paddingValues -> // AnimatedNavHost inside the scaffold content diff --git a/examples/llama.android/app/src/main/java/com/example/llama/monitoring/PerformanceMonitor.kt b/examples/llama.android/app/src/main/java/com/example/llama/monitoring/PerformanceMonitor.kt index a69a224e4e..8ef2e7f265 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/monitoring/PerformanceMonitor.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/monitoring/PerformanceMonitor.kt @@ -71,8 +71,8 @@ class PerformanceMonitor(@ApplicationContext private val context: Context) { availableMem = availableMem, totalMem = totalMem, percentUsed = percentUsed, - availableGb = availableGb, - totalGb = totalGb + availableGB = availableGb, + totalGB = totalGb ) } diff --git a/examples/llama.android/app/src/main/java/com/example/llama/monitoring/SystemMetrics.kt b/examples/llama.android/app/src/main/java/com/example/llama/monitoring/SystemMetrics.kt index 95e39c7a22..114c708f2a 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/monitoring/SystemMetrics.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/monitoring/SystemMetrics.kt @@ -15,8 +15,8 @@ data class MemoryMetrics( val availableMem: Long, val totalMem: Long, val percentUsed: Int, - val availableGb: Float, - val totalGb: Float + val availableGB: Float, + val totalGB: Float ) /** diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/AppScaffold.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/AppScaffold.kt index 96a6a1b6ec..f67076509a 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/AppScaffold.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/AppScaffold.kt @@ -51,6 +51,7 @@ sealed class ScaffoldEvent { fun AppScaffold( topBarconfig: TopBarConfig, bottomBarConfig: BottomBarConfig = BottomBarConfig.None, + onScaffoldEvent: (ScaffoldEvent) -> Unit, snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, content: @Composable (PaddingValues) -> Unit ) { @@ -68,6 +69,7 @@ fun AppScaffold( title = topBarconfig.title, memoryMetrics = topBarconfig.memoryMetrics, temperatureDisplay = topBarconfig.temperatureInfo, + onScaffoldEvent = onScaffoldEvent, onNavigateBack = topBarconfig.navigationIcon.backAction, onMenuOpen = topBarconfig.navigationIcon.menuAction, ) @@ -75,6 +77,7 @@ fun AppScaffold( is TopBarConfig.Storage -> StorageTopBar( title = topBarconfig.title, storageMetrics = topBarconfig.storageMetrics, + onScaffoldEvent = onScaffoldEvent, onNavigateBack = topBarconfig.navigationIcon.backAction, ) } diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/PerformanceTopBar.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/PerformanceTopBar.kt index 4363d5a67a..18f33657f0 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/PerformanceTopBar.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/PerformanceTopBar.kt @@ -1,5 +1,6 @@ package com.example.llama.ui.scaffold.topbar +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding @@ -20,10 +21,12 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.example.llama.monitoring.MemoryMetrics import com.example.llama.monitoring.TemperatureMetrics import com.example.llama.monitoring.TemperatureWarningLevel +import com.example.llama.ui.scaffold.ScaffoldEvent import java.util.Locale @OptIn(ExperimentalMaterial3Api::class) @@ -32,6 +35,7 @@ fun PerformanceTopBar( title: String, memoryMetrics: MemoryMetrics?, temperatureDisplay: Pair?, + onScaffoldEvent: (ScaffoldEvent) -> Unit, onNavigateBack: (() -> Unit)? = null, onMenuOpen: (() -> Unit)? = null, ) { @@ -63,7 +67,8 @@ fun PerformanceTopBar( temperatureDisplay?.let { (temperatureMetrics, useFahrenheit) -> TemperatureIndicator( temperatureMetrics = temperatureMetrics, - useFahrenheit = useFahrenheit + useFahrenheit = useFahrenheit, + onScaffoldEvent = onScaffoldEvent, ) Spacer(modifier = Modifier.width(8.dp)) @@ -71,7 +76,7 @@ fun PerformanceTopBar( // Memory indicator memoryMetrics?.let { - MemoryIndicator(memoryUsage = it) + MemoryIndicator(memoryUsage = it, onScaffoldEvent = onScaffoldEvent) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -82,17 +87,28 @@ fun PerformanceTopBar( } @Composable -private fun MemoryIndicator(memoryUsage: MemoryMetrics) { +private fun MemoryIndicator( + memoryUsage: MemoryMetrics, + onScaffoldEvent: (ScaffoldEvent) -> Unit, +) { + val availableGB = String.format(Locale.getDefault(), "%.1f", memoryUsage.availableGB) + val totalGB = String.format(Locale.getDefault(), "%.1f", memoryUsage.totalGB) + Row( - modifier = Modifier.padding(end = 8.dp), + modifier = Modifier.padding(end = 8.dp).clickable(role = Role.Button) { + onScaffoldEvent(ScaffoldEvent.ShowSnackbar( + message = "Free RAM available: $availableGB GB\nTotal RAM on your device: $totalGB GB", + withDismissAction = true, + )) + }, verticalAlignment = Alignment.CenterVertically, ) { Icon( imageVector = Icons.Default.Memory, contentDescription = "RAM usage", tint = when { - memoryUsage.availableGb < 1 -> MaterialTheme.colorScheme.error - memoryUsage.availableGb < 3 -> MaterialTheme.colorScheme.tertiary + memoryUsage.availableGB < 1 -> MaterialTheme.colorScheme.error + memoryUsage.availableGB < 3 -> MaterialTheme.colorScheme.tertiary else -> MaterialTheme.colorScheme.onSurface } ) @@ -100,17 +116,35 @@ private fun MemoryIndicator(memoryUsage: MemoryMetrics) { Spacer(modifier = Modifier.width(4.dp)) Text( - text = String.format( - Locale.getDefault(), "%.1f / %.1f GB", memoryUsage.availableGb, memoryUsage.totalGb - ), + text = "$availableGB / $totalGB GB", style = MaterialTheme.typography.bodySmall, ) } } @Composable -private fun TemperatureIndicator(temperatureMetrics: TemperatureMetrics, useFahrenheit: Boolean) { - Row(verticalAlignment = Alignment.CenterVertically) { +private fun TemperatureIndicator( + temperatureMetrics: TemperatureMetrics, + useFahrenheit: Boolean, + onScaffoldEvent: (ScaffoldEvent) -> Unit, +) { + val temperatureDisplay = temperatureMetrics.getDisplay(useFahrenheit) + + val temperatureWarning = when (temperatureMetrics.warningLevel) { + TemperatureWarningLevel.HIGH -> "Your device is HEATED UP to $temperatureDisplay, please cool it down before continue using the app." + TemperatureWarningLevel.MEDIUM -> "Your device is warming up to $temperatureDisplay." + else -> "Your device's temperature is $temperatureDisplay." + } + val warningDismissible = temperatureMetrics.warningLevel == TemperatureWarningLevel.HIGH + + Row( + modifier = Modifier.clickable(role = Role.Button) { + onScaffoldEvent(ScaffoldEvent.ShowSnackbar( + message = temperatureWarning, + withDismissAction = warningDismissible, + )) + }, + verticalAlignment = Alignment.CenterVertically) { Icon( imageVector = when (temperatureMetrics.warningLevel) { TemperatureWarningLevel.HIGH -> Icons.Default.WarningAmber @@ -127,7 +161,7 @@ private fun TemperatureIndicator(temperatureMetrics: TemperatureMetrics, useFahr Spacer(modifier = Modifier.width(2.dp)) Text( - text = temperatureMetrics.getDisplay(useFahrenheit), + text = temperatureDisplay, style = MaterialTheme.typography.bodySmall, color = when (temperatureMetrics.warningLevel) { TemperatureWarningLevel.HIGH -> MaterialTheme.colorScheme.error diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/StorageTopBar.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/StorageTopBar.kt index c88ae046c7..062bb89845 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/StorageTopBar.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/topbar/StorageTopBar.kt @@ -1,5 +1,6 @@ package com.example.llama.ui.scaffold.topbar +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding @@ -17,8 +18,10 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.example.llama.monitoring.StorageMetrics +import com.example.llama.ui.scaffold.ScaffoldEvent import java.util.Locale @OptIn(ExperimentalMaterial3Api::class) @@ -26,6 +29,7 @@ import java.util.Locale fun StorageTopBar( title: String, storageMetrics: StorageMetrics?, + onScaffoldEvent: (ScaffoldEvent) -> Unit, onNavigateBack: (() -> Unit)? = null, ) { TopAppBar( @@ -42,7 +46,7 @@ fun StorageTopBar( }, actions = { storageMetrics?.let { - StorageIndicator(storageMetrics = it) + StorageIndicator(storageMetrics = it, onScaffoldEvent = onScaffoldEvent) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -53,20 +57,29 @@ fun StorageTopBar( } @Composable -private fun StorageIndicator(storageMetrics: StorageMetrics) { - val usedGb = storageMetrics.usedGB - val availableGb = storageMetrics.availableGB +private fun StorageIndicator( + storageMetrics: StorageMetrics, + onScaffoldEvent: (ScaffoldEvent) -> Unit, +) { + + val usedGb = String.format(Locale.getDefault(), "%.1f", storageMetrics.usedGB) + val availableGb = String.format(Locale.getDefault(), "%.1f", storageMetrics.availableGB) Row( - modifier = Modifier.padding(end = 8.dp), + modifier = Modifier.padding(end = 8.dp).clickable(role = Role.Button) { + onScaffoldEvent(ScaffoldEvent.ShowSnackbar( + message = "Your models occupy $usedGb GB storage\nRemaining free space available: $availableGb GB", + withDismissAction = true, + )) + }, verticalAlignment = Alignment.CenterVertically ) { Icon( imageVector = Icons.Default.SdStorage, contentDescription = "Storage", tint = when { - availableGb < 5.0f -> MaterialTheme.colorScheme.error - availableGb < 10.0f -> MaterialTheme.colorScheme.tertiary + storageMetrics.availableGB < 5.0f -> MaterialTheme.colorScheme.error + storageMetrics.availableGB < 10.0f -> MaterialTheme.colorScheme.tertiary else -> MaterialTheme.colorScheme.onSurface } ) @@ -74,12 +87,7 @@ private fun StorageIndicator(storageMetrics: StorageMetrics) { Spacer(modifier = Modifier.width(2.dp)) Text( - text = String.format( - Locale.getDefault(), - "%.1f / %.1f GB", - usedGb, - availableGb - ), + text = "$usedGb / $availableGb GB", style = MaterialTheme.typography.bodySmall ) }