UI: show corresponding system metrics detailed info upon tapping RAM / storage / temperature indicator
This commit is contained in:
parent
50cea70de3
commit
2e9de7c99c
|
|
@ -413,6 +413,7 @@ fun AppContent(
|
||||||
AppScaffold(
|
AppScaffold(
|
||||||
topBarconfig = scaffoldConfig.topBarConfig,
|
topBarconfig = scaffoldConfig.topBarConfig,
|
||||||
bottomBarConfig = scaffoldConfig.bottomBarConfig,
|
bottomBarConfig = scaffoldConfig.bottomBarConfig,
|
||||||
|
onScaffoldEvent = handleScaffoldEvent,
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
// AnimatedNavHost inside the scaffold content
|
// AnimatedNavHost inside the scaffold content
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ class PerformanceMonitor(@ApplicationContext private val context: Context) {
|
||||||
availableMem = availableMem,
|
availableMem = availableMem,
|
||||||
totalMem = totalMem,
|
totalMem = totalMem,
|
||||||
percentUsed = percentUsed,
|
percentUsed = percentUsed,
|
||||||
availableGb = availableGb,
|
availableGB = availableGb,
|
||||||
totalGb = totalGb
|
totalGB = totalGb
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ data class MemoryMetrics(
|
||||||
val availableMem: Long,
|
val availableMem: Long,
|
||||||
val totalMem: Long,
|
val totalMem: Long,
|
||||||
val percentUsed: Int,
|
val percentUsed: Int,
|
||||||
val availableGb: Float,
|
val availableGB: Float,
|
||||||
val totalGb: Float
|
val totalGB: Float
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ sealed class ScaffoldEvent {
|
||||||
fun AppScaffold(
|
fun AppScaffold(
|
||||||
topBarconfig: TopBarConfig,
|
topBarconfig: TopBarConfig,
|
||||||
bottomBarConfig: BottomBarConfig = BottomBarConfig.None,
|
bottomBarConfig: BottomBarConfig = BottomBarConfig.None,
|
||||||
|
onScaffoldEvent: (ScaffoldEvent) -> Unit,
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
@ -68,6 +69,7 @@ fun AppScaffold(
|
||||||
title = topBarconfig.title,
|
title = topBarconfig.title,
|
||||||
memoryMetrics = topBarconfig.memoryMetrics,
|
memoryMetrics = topBarconfig.memoryMetrics,
|
||||||
temperatureDisplay = topBarconfig.temperatureInfo,
|
temperatureDisplay = topBarconfig.temperatureInfo,
|
||||||
|
onScaffoldEvent = onScaffoldEvent,
|
||||||
onNavigateBack = topBarconfig.navigationIcon.backAction,
|
onNavigateBack = topBarconfig.navigationIcon.backAction,
|
||||||
onMenuOpen = topBarconfig.navigationIcon.menuAction,
|
onMenuOpen = topBarconfig.navigationIcon.menuAction,
|
||||||
)
|
)
|
||||||
|
|
@ -75,6 +77,7 @@ fun AppScaffold(
|
||||||
is TopBarConfig.Storage -> StorageTopBar(
|
is TopBarConfig.Storage -> StorageTopBar(
|
||||||
title = topBarconfig.title,
|
title = topBarconfig.title,
|
||||||
storageMetrics = topBarconfig.storageMetrics,
|
storageMetrics = topBarconfig.storageMetrics,
|
||||||
|
onScaffoldEvent = onScaffoldEvent,
|
||||||
onNavigateBack = topBarconfig.navigationIcon.backAction,
|
onNavigateBack = topBarconfig.navigationIcon.backAction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.example.llama.ui.scaffold.topbar
|
package com.example.llama.ui.scaffold.topbar
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -20,10 +21,12 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.llama.monitoring.MemoryMetrics
|
import com.example.llama.monitoring.MemoryMetrics
|
||||||
import com.example.llama.monitoring.TemperatureMetrics
|
import com.example.llama.monitoring.TemperatureMetrics
|
||||||
import com.example.llama.monitoring.TemperatureWarningLevel
|
import com.example.llama.monitoring.TemperatureWarningLevel
|
||||||
|
import com.example.llama.ui.scaffold.ScaffoldEvent
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -32,6 +35,7 @@ fun PerformanceTopBar(
|
||||||
title: String,
|
title: String,
|
||||||
memoryMetrics: MemoryMetrics?,
|
memoryMetrics: MemoryMetrics?,
|
||||||
temperatureDisplay: Pair<TemperatureMetrics, Boolean>?,
|
temperatureDisplay: Pair<TemperatureMetrics, Boolean>?,
|
||||||
|
onScaffoldEvent: (ScaffoldEvent) -> Unit,
|
||||||
onNavigateBack: (() -> Unit)? = null,
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
onMenuOpen: (() -> Unit)? = null,
|
onMenuOpen: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -63,7 +67,8 @@ fun PerformanceTopBar(
|
||||||
temperatureDisplay?.let { (temperatureMetrics, useFahrenheit) ->
|
temperatureDisplay?.let { (temperatureMetrics, useFahrenheit) ->
|
||||||
TemperatureIndicator(
|
TemperatureIndicator(
|
||||||
temperatureMetrics = temperatureMetrics,
|
temperatureMetrics = temperatureMetrics,
|
||||||
useFahrenheit = useFahrenheit
|
useFahrenheit = useFahrenheit,
|
||||||
|
onScaffoldEvent = onScaffoldEvent,
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
@ -71,7 +76,7 @@ fun PerformanceTopBar(
|
||||||
|
|
||||||
// Memory indicator
|
// Memory indicator
|
||||||
memoryMetrics?.let {
|
memoryMetrics?.let {
|
||||||
MemoryIndicator(memoryUsage = it)
|
MemoryIndicator(memoryUsage = it, onScaffoldEvent = onScaffoldEvent)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
|
@ -82,17 +87,28 @@ fun PerformanceTopBar(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@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(
|
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,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Memory,
|
imageVector = Icons.Default.Memory,
|
||||||
contentDescription = "RAM usage",
|
contentDescription = "RAM usage",
|
||||||
tint = when {
|
tint = when {
|
||||||
memoryUsage.availableGb < 1 -> MaterialTheme.colorScheme.error
|
memoryUsage.availableGB < 1 -> MaterialTheme.colorScheme.error
|
||||||
memoryUsage.availableGb < 3 -> MaterialTheme.colorScheme.tertiary
|
memoryUsage.availableGB < 3 -> MaterialTheme.colorScheme.tertiary
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -100,17 +116,35 @@ private fun MemoryIndicator(memoryUsage: MemoryMetrics) {
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = String.format(
|
text = "$availableGB / $totalGB GB",
|
||||||
Locale.getDefault(), "%.1f / %.1f GB", memoryUsage.availableGb, memoryUsage.totalGb
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TemperatureIndicator(temperatureMetrics: TemperatureMetrics, useFahrenheit: Boolean) {
|
private fun TemperatureIndicator(
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
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(
|
Icon(
|
||||||
imageVector = when (temperatureMetrics.warningLevel) {
|
imageVector = when (temperatureMetrics.warningLevel) {
|
||||||
TemperatureWarningLevel.HIGH -> Icons.Default.WarningAmber
|
TemperatureWarningLevel.HIGH -> Icons.Default.WarningAmber
|
||||||
|
|
@ -127,7 +161,7 @@ private fun TemperatureIndicator(temperatureMetrics: TemperatureMetrics, useFahr
|
||||||
Spacer(modifier = Modifier.width(2.dp))
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = temperatureMetrics.getDisplay(useFahrenheit),
|
text = temperatureDisplay,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = when (temperatureMetrics.warningLevel) {
|
color = when (temperatureMetrics.warningLevel) {
|
||||||
TemperatureWarningLevel.HIGH -> MaterialTheme.colorScheme.error
|
TemperatureWarningLevel.HIGH -> MaterialTheme.colorScheme.error
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.example.llama.ui.scaffold.topbar
|
package com.example.llama.ui.scaffold.topbar
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -17,8 +18,10 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.llama.monitoring.StorageMetrics
|
import com.example.llama.monitoring.StorageMetrics
|
||||||
|
import com.example.llama.ui.scaffold.ScaffoldEvent
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -26,6 +29,7 @@ import java.util.Locale
|
||||||
fun StorageTopBar(
|
fun StorageTopBar(
|
||||||
title: String,
|
title: String,
|
||||||
storageMetrics: StorageMetrics?,
|
storageMetrics: StorageMetrics?,
|
||||||
|
onScaffoldEvent: (ScaffoldEvent) -> Unit,
|
||||||
onNavigateBack: (() -> Unit)? = null,
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
|
@ -42,7 +46,7 @@ fun StorageTopBar(
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
storageMetrics?.let {
|
storageMetrics?.let {
|
||||||
StorageIndicator(storageMetrics = it)
|
StorageIndicator(storageMetrics = it, onScaffoldEvent = onScaffoldEvent)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
|
@ -53,20 +57,29 @@ fun StorageTopBar(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun StorageIndicator(storageMetrics: StorageMetrics) {
|
private fun StorageIndicator(
|
||||||
val usedGb = storageMetrics.usedGB
|
storageMetrics: StorageMetrics,
|
||||||
val availableGb = storageMetrics.availableGB
|
onScaffoldEvent: (ScaffoldEvent) -> Unit,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val usedGb = String.format(Locale.getDefault(), "%.1f", storageMetrics.usedGB)
|
||||||
|
val availableGb = String.format(Locale.getDefault(), "%.1f", storageMetrics.availableGB)
|
||||||
|
|
||||||
Row(
|
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
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.SdStorage,
|
imageVector = Icons.Default.SdStorage,
|
||||||
contentDescription = "Storage",
|
contentDescription = "Storage",
|
||||||
tint = when {
|
tint = when {
|
||||||
availableGb < 5.0f -> MaterialTheme.colorScheme.error
|
storageMetrics.availableGB < 5.0f -> MaterialTheme.colorScheme.error
|
||||||
availableGb < 10.0f -> MaterialTheme.colorScheme.tertiary
|
storageMetrics.availableGB < 10.0f -> MaterialTheme.colorScheme.tertiary
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -74,12 +87,7 @@ private fun StorageIndicator(storageMetrics: StorageMetrics) {
|
||||||
Spacer(modifier = Modifier.width(2.dp))
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = String.format(
|
text = "$usedGb / $availableGb GB",
|
||||||
Locale.getDefault(),
|
|
||||||
"%.1f / %.1f GB",
|
|
||||||
usedGb,
|
|
||||||
availableGb
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.bodySmall
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue