UI: refactor top app bars
This commit is contained in:
parent
2a41c0e354
commit
5e4972e93e
|
|
@ -245,8 +245,6 @@ fun AppContent() {
|
||||||
// Need to unload model before going back
|
// Need to unload model before going back
|
||||||
handleBackWithModelCheck()
|
handleBackWithModelCheck()
|
||||||
},
|
},
|
||||||
drawerState = drawerState,
|
|
||||||
navigationActions = navigationActions,
|
|
||||||
viewModel = viewModel
|
viewModel = viewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -284,9 +282,6 @@ fun AppContent() {
|
||||||
composable(AppDestinations.MODELS_MANAGEMENT_ROUTE) {
|
composable(AppDestinations.MODELS_MANAGEMENT_ROUTE) {
|
||||||
ModelsManagementScreen(
|
ModelsManagementScreen(
|
||||||
onBackPressed = { navController.popBackStack() },
|
onBackPressed = { navController.popBackStack() },
|
||||||
drawerState = drawerState,
|
|
||||||
navigationActions = navigationActions,
|
|
||||||
onMenuClicked = openDrawer
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,13 +106,13 @@ class PerformanceMonitor(private val context: Context) {
|
||||||
val tempC = tempTenthsC / 10.0f
|
val tempC = tempTenthsC / 10.0f
|
||||||
|
|
||||||
val warningLevel = when {
|
val warningLevel = when {
|
||||||
tempC >= 45.0f -> TemperatureWarningLevel.HIGH
|
tempC >= 40.0f -> TemperatureWarningLevel.HIGH
|
||||||
tempC >= 40.0f -> TemperatureWarningLevel.MEDIUM
|
tempC >= 35.0f -> TemperatureWarningLevel.MEDIUM
|
||||||
else -> TemperatureWarningLevel.NORMAL
|
else -> TemperatureWarningLevel.NORMAL
|
||||||
}
|
}
|
||||||
|
|
||||||
return TemperatureMetrics(
|
return TemperatureMetrics(
|
||||||
temperature = tempC,
|
tempCelsiusValue = tempC,
|
||||||
warningLevel = warningLevel
|
warningLevel = warningLevel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -162,6 +162,15 @@ enum class TemperatureWarningLevel {
|
||||||
* Data class containing temperature information.
|
* Data class containing temperature information.
|
||||||
*/
|
*/
|
||||||
data class TemperatureMetrics(
|
data class TemperatureMetrics(
|
||||||
val temperature: Float,
|
private val tempCelsiusValue: Float,
|
||||||
val warningLevel: TemperatureWarningLevel
|
val warningLevel: TemperatureWarningLevel
|
||||||
)
|
) {
|
||||||
|
val celsiusDisplay: String
|
||||||
|
get() = "${tempCelsiusValue.toInt()}°C"
|
||||||
|
|
||||||
|
val fahrenheitDisplay: String
|
||||||
|
get() = "${(tempCelsiusValue * 9/5 + 32).toInt()}°F"
|
||||||
|
|
||||||
|
fun getDisplay(useFahrenheit: Boolean) =
|
||||||
|
if (useFahrenheit) fahrenheitDisplay else celsiusDisplay
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
package com.example.llama.revamp.ui.components
|
package com.example.llama.revamp.ui.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.material3.DrawerState
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.material3.DrawerValue
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.rememberDrawerState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -16,25 +13,41 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.llama.revamp.data.preferences.UserPreferences
|
import com.example.llama.revamp.data.preferences.UserPreferences
|
||||||
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
|
||||||
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
||||||
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
||||||
|
|
||||||
/**
|
// DefaultAppScaffold.kt
|
||||||
* Main scaffold for the app that provides the top bar with system status
|
|
||||||
* and wraps content in a consistent layout.
|
|
||||||
*/
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppScaffold(
|
fun DefaultAppScaffold(
|
||||||
title: String,
|
title: String,
|
||||||
navigationActions: NavigationActions,
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
drawerState: DrawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
|
onMenuOpen: (() -> Unit)? = null,
|
||||||
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
|
content: @Composable (PaddingValues) -> Unit
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
DefaultTopBar(
|
||||||
|
title = title,
|
||||||
|
onNavigateBack = onNavigateBack,
|
||||||
|
onMenuOpen = onMenuOpen
|
||||||
|
)
|
||||||
|
},
|
||||||
|
snackbarHost = {
|
||||||
|
SnackbarHost(hostState = snackbarHostState)
|
||||||
|
},
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PerformanceAppScaffold.kt
|
||||||
|
@Composable
|
||||||
|
fun PerformanceAppScaffold(
|
||||||
|
title: String,
|
||||||
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
|
onMenuOpen: (() -> Unit)? = null,
|
||||||
|
showTemperature: Boolean = false,
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
onBackPressed: (() -> Unit)? = null,
|
|
||||||
onMenuPressed: (() -> Unit)? = null,
|
|
||||||
onRerunPressed: (() -> Unit)? = null,
|
|
||||||
onSharePressed: (() -> Unit)? = null,
|
|
||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit
|
||||||
) {
|
) {
|
||||||
// Create dependencies for PerformanceViewModel
|
// Create dependencies for PerformanceViewModel
|
||||||
|
|
@ -50,22 +63,45 @@ fun AppScaffold(
|
||||||
|
|
||||||
// Collect performance metrics
|
// Collect performance metrics
|
||||||
val memoryUsage by performanceViewModel.memoryUsage.collectAsState()
|
val memoryUsage by performanceViewModel.memoryUsage.collectAsState()
|
||||||
val batteryInfo by performanceViewModel.batteryInfo.collectAsState()
|
|
||||||
val temperatureInfo by performanceViewModel.temperatureInfo.collectAsState()
|
val temperatureInfo by performanceViewModel.temperatureInfo.collectAsState()
|
||||||
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
SystemStatusTopBar(
|
PerformanceTopBar(
|
||||||
title = title,
|
title = title,
|
||||||
memoryUsage = memoryUsage,
|
memoryMetrics = memoryUsage,
|
||||||
batteryLevel = batteryInfo.level,
|
temperatureMetrics = temperatureInfo,
|
||||||
temperature = temperatureInfo.temperature,
|
onNavigateBack = onNavigateBack,
|
||||||
|
onMenuOpen = onMenuOpen,
|
||||||
|
showTemperature = showTemperature,
|
||||||
useFahrenheit = useFahrenheit,
|
useFahrenheit = useFahrenheit,
|
||||||
onBackPressed = onBackPressed,
|
)
|
||||||
onMenuPressed = onMenuPressed,
|
},
|
||||||
onRerunPressed = onRerunPressed,
|
snackbarHost = {
|
||||||
onSharePressed = onSharePressed
|
SnackbarHost(hostState = snackbarHostState)
|
||||||
|
},
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageAppScaffold.kt
|
||||||
|
@Composable
|
||||||
|
fun StorageAppScaffold(
|
||||||
|
title: String,
|
||||||
|
storageUsed: Float,
|
||||||
|
storageTotal: Float,
|
||||||
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
|
content: @Composable (PaddingValues) -> Unit
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
StorageTopBar(
|
||||||
|
title = title,
|
||||||
|
storageUsed = storageUsed,
|
||||||
|
storageTotal = storageTotal,
|
||||||
|
onNavigateBack = onNavigateBack,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = {
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
package com.example.llama.revamp.ui.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
|
||||||
import androidx.compose.material.icons.filled.BatteryAlert
|
|
||||||
import androidx.compose.material.icons.filled.BatteryFull
|
|
||||||
import androidx.compose.material.icons.filled.BatteryStd
|
|
||||||
import androidx.compose.material.icons.filled.Memory
|
|
||||||
import androidx.compose.material.icons.filled.Menu
|
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
|
||||||
import androidx.compose.material.icons.filled.Share
|
|
||||||
import androidx.compose.material.icons.filled.Thermostat
|
|
||||||
import androidx.compose.material.icons.filled.WarningAmber
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.example.llama.revamp.monitoring.MemoryMetrics
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Top app bar that displays system status information and navigation controls.
|
|
||||||
*/
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun SystemStatusTopBar(
|
|
||||||
title: String,
|
|
||||||
memoryUsage: MemoryMetrics,
|
|
||||||
batteryLevel: Int,
|
|
||||||
temperature: Float,
|
|
||||||
useFahrenheit: Boolean = false,
|
|
||||||
onBackPressed: (() -> Unit)? = null,
|
|
||||||
onMenuPressed: (() -> Unit)? = null,
|
|
||||||
onRerunPressed: (() -> Unit)? = null,
|
|
||||||
onSharePressed: (() -> Unit)? = null
|
|
||||||
) {
|
|
||||||
TopAppBar(
|
|
||||||
title = { Text(title) },
|
|
||||||
navigationIcon = {
|
|
||||||
when {
|
|
||||||
onBackPressed != null -> {
|
|
||||||
IconButton(onClick = onBackPressed) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
|
||||||
contentDescription = "Back"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onMenuPressed != null -> {
|
|
||||||
IconButton(onClick = onMenuPressed) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Menu,
|
|
||||||
contentDescription = "Menu"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
// Memory usage
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Memory,
|
|
||||||
contentDescription = "RAM space",
|
|
||||||
tint = when {
|
|
||||||
memoryUsage.availableGb < 1 -> MaterialTheme.colorScheme.error
|
|
||||||
memoryUsage.availableGb < 3 -> MaterialTheme.colorScheme.tertiary
|
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(2.dp))
|
|
||||||
|
|
||||||
val memoryText = String.format("%.1f / %.1f GB", memoryUsage.availableGb, memoryUsage.totalGb)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = memoryText,
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
modifier = Modifier.padding(end = 8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Battery icon and percentage
|
|
||||||
Icon(
|
|
||||||
imageVector = when {
|
|
||||||
batteryLevel > 70 -> Icons.Default.BatteryFull
|
|
||||||
batteryLevel > 30 -> Icons.Default.BatteryStd
|
|
||||||
else -> Icons.Default.BatteryAlert
|
|
||||||
},
|
|
||||||
contentDescription = "Battery level",
|
|
||||||
tint = when {
|
|
||||||
batteryLevel <= 15 -> MaterialTheme.colorScheme.error
|
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "$batteryLevel%",
|
|
||||||
style = MaterialTheme.typography.bodySmall
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(2.dp))
|
|
||||||
|
|
||||||
// Temperature icon and display
|
|
||||||
Icon(
|
|
||||||
imageVector = when {
|
|
||||||
temperature > 40 -> Icons.Default.WarningAmber
|
|
||||||
else -> Icons.Default.Thermostat
|
|
||||||
},
|
|
||||||
contentDescription = "Device temperature",
|
|
||||||
tint = when {
|
|
||||||
temperature > 40 -> MaterialTheme.colorScheme.error
|
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val tempDisplay = if (useFahrenheit) {
|
|
||||||
"${(temperature * 9/5 + 32).toInt()}°F"
|
|
||||||
} else {
|
|
||||||
"${temperature.toInt()}°C"
|
|
||||||
}
|
|
||||||
|
|
||||||
val tempTint = when {
|
|
||||||
temperature >= 45 -> MaterialTheme.colorScheme.error
|
|
||||||
temperature >= 35 -> MaterialTheme.colorScheme.tertiary
|
|
||||||
else -> MaterialTheme.colorScheme.onSurface
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = tempDisplay,
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = tempTint
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional action buttons
|
|
||||||
onRerunPressed?.let {
|
|
||||||
IconButton(onClick = it) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Refresh,
|
|
||||||
contentDescription = "Rerun benchmark"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSharePressed?.let {
|
|
||||||
IconButton(onClick = it) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Share,
|
|
||||||
contentDescription = "Share results"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
|
||||||
titleContentColor = MaterialTheme.colorScheme.onSurface
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
package com.example.llama.revamp.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Memory
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.SdStorage
|
||||||
|
import androidx.compose.material.icons.filled.Storage
|
||||||
|
import androidx.compose.material.icons.filled.Thermostat
|
||||||
|
import androidx.compose.material.icons.filled.WarningAmber
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.llama.revamp.monitoring.MemoryMetrics
|
||||||
|
import com.example.llama.revamp.monitoring.TemperatureMetrics
|
||||||
|
import com.example.llama.revamp.monitoring.TemperatureWarningLevel
|
||||||
|
|
||||||
|
// TopAppBars.kt
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun DefaultTopBar(
|
||||||
|
title: String,
|
||||||
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
|
onMenuOpen: (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(title) },
|
||||||
|
navigationIcon = {
|
||||||
|
when {
|
||||||
|
onNavigateBack != null -> {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = "Back"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMenuOpen != null -> {
|
||||||
|
IconButton(onClick = onMenuOpen) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Menu,
|
||||||
|
contentDescription = "Menu"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
titleContentColor = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun PerformanceTopBar(
|
||||||
|
title: String,
|
||||||
|
memoryMetrics: MemoryMetrics,
|
||||||
|
temperatureMetrics: TemperatureMetrics,
|
||||||
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
|
onMenuOpen: (() -> Unit)? = null,
|
||||||
|
showTemperature: Boolean = false,
|
||||||
|
useFahrenheit: Boolean = false,
|
||||||
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(title) },
|
||||||
|
navigationIcon = {
|
||||||
|
when {
|
||||||
|
onNavigateBack != null -> {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = "Back"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMenuOpen != null -> {
|
||||||
|
IconButton(onClick = onMenuOpen) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Menu,
|
||||||
|
contentDescription = "Menu"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
// Temperature indicator (optional)
|
||||||
|
if (showTemperature) {
|
||||||
|
TemperatureIndicator(
|
||||||
|
temperature = temperatureMetrics,
|
||||||
|
useFahrenheit = useFahrenheit
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory indicator
|
||||||
|
MemoryIndicator(memoryUsage = memoryMetrics)
|
||||||
|
},
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
titleContentColor = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun StorageTopBar(
|
||||||
|
title: String,
|
||||||
|
storageUsed: Float,
|
||||||
|
storageTotal: Float,
|
||||||
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(title) },
|
||||||
|
navigationIcon = {
|
||||||
|
if (onNavigateBack != null) {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = "Back"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
StorageIndicator(usedGB = storageUsed, totalGB = storageTotal)
|
||||||
|
},
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
titleContentColor = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MemoryIndicator(memoryUsage: MemoryMetrics) {
|
||||||
|
Row(modifier = Modifier.padding(end = 8.dp), 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
|
||||||
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
|
||||||
|
val memoryText = String.format("%.1f / %.1f GB", memoryUsage.availableGb, memoryUsage.totalGb)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = memoryText,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TemperatureIndicator(temperature: TemperatureMetrics, useFahrenheit: Boolean) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
imageVector = when (temperature.warningLevel) {
|
||||||
|
TemperatureWarningLevel.HIGH -> Icons.Default.WarningAmber
|
||||||
|
else -> Icons.Default.Thermostat
|
||||||
|
},
|
||||||
|
contentDescription = "Device temperature",
|
||||||
|
tint = when (temperature.warningLevel) {
|
||||||
|
TemperatureWarningLevel.HIGH -> MaterialTheme.colorScheme.error
|
||||||
|
TemperatureWarningLevel.MEDIUM -> MaterialTheme.colorScheme.tertiary
|
||||||
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
|
||||||
|
val tempDisplay = if (useFahrenheit) temperature.fahrenheitDisplay else temperature.celsiusDisplay
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = tempDisplay,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = when (temperature.warningLevel) {
|
||||||
|
TemperatureWarningLevel.HIGH -> MaterialTheme.colorScheme.error
|
||||||
|
TemperatureWarningLevel.MEDIUM -> MaterialTheme.colorScheme.tertiary
|
||||||
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StorageIndicator(usedGB: Float, totalGB: Float) {
|
||||||
|
Row(modifier = Modifier.padding(end = 8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.SdStorage,
|
||||||
|
contentDescription = "Storage",
|
||||||
|
tint = when {
|
||||||
|
usedGB / totalGB > 0.9f -> MaterialTheme.colorScheme.error
|
||||||
|
usedGB / totalGB > 0.7f -> MaterialTheme.colorScheme.tertiary
|
||||||
|
else -> MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = String.format("%.1f / %.1f GB", usedGB, totalGB),
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.llama.revamp.engine.InferenceEngine
|
import com.example.llama.revamp.engine.InferenceEngine
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
import com.example.llama.revamp.ui.components.PerformanceAppScaffold
|
||||||
import com.example.llama.revamp.ui.theme.MonospacedTextStyle
|
import com.example.llama.revamp.ui.theme.MonospacedTextStyle
|
||||||
import com.example.llama.revamp.viewmodel.MainViewModel
|
import com.example.llama.revamp.viewmodel.MainViewModel
|
||||||
|
|
||||||
|
|
@ -42,13 +42,10 @@ fun BenchmarkScreen(
|
||||||
val benchmarkResults by viewModel.benchmarkResults.collectAsState()
|
val benchmarkResults by viewModel.benchmarkResults.collectAsState()
|
||||||
val selectedModel by viewModel.selectedModel.collectAsState()
|
val selectedModel by viewModel.selectedModel.collectAsState()
|
||||||
|
|
||||||
AppScaffold(
|
PerformanceAppScaffold(
|
||||||
title = "Benchmark Results",
|
title = "Chat",
|
||||||
drawerState = drawerState,
|
onNavigateBack = onBackPressed,
|
||||||
navigationActions = navigationActions,
|
showTemperature = true
|
||||||
onBackPressed = onBackPressed,
|
|
||||||
onRerunPressed = onRerunPressed,
|
|
||||||
onSharePressed = onSharePressed
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import androidx.compose.material.icons.filled.Send
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.DrawerState
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -61,11 +60,9 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import com.example.llama.revamp.engine.InferenceEngine
|
import com.example.llama.revamp.engine.InferenceEngine
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.ui.components.PerformanceAppScaffold
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
|
||||||
import com.example.llama.revamp.viewmodel.MainViewModel
|
import com.example.llama.revamp.viewmodel.MainViewModel
|
||||||
import com.example.llama.revamp.viewmodel.Message
|
import com.example.llama.revamp.viewmodel.Message
|
||||||
import com.example.llama.revamp.viewmodel.TokenMetrics
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,8 +71,6 @@ import kotlinx.coroutines.launch
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationScreen(
|
fun ConversationScreen(
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
drawerState: DrawerState,
|
|
||||||
navigationActions: NavigationActions,
|
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel
|
||||||
) {
|
) {
|
||||||
val engineState by viewModel.engineState.collectAsState()
|
val engineState by viewModel.engineState.collectAsState()
|
||||||
|
|
@ -121,11 +116,10 @@ fun ConversationScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppScaffold(
|
PerformanceAppScaffold(
|
||||||
title = "Chat",
|
title = "Chat",
|
||||||
drawerState = drawerState,
|
onNavigateBack = onBackPressed,
|
||||||
navigationActions = navigationActions,
|
showTemperature = true
|
||||||
onBackPressed = onBackPressed
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ import com.example.llama.revamp.data.model.SystemPrompt
|
||||||
import com.example.llama.revamp.data.repository.SystemPromptRepository
|
import com.example.llama.revamp.data.repository.SystemPromptRepository
|
||||||
import com.example.llama.revamp.engine.InferenceEngine
|
import com.example.llama.revamp.engine.InferenceEngine
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
import com.example.llama.revamp.ui.components.PerformanceAppScaffold
|
||||||
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
||||||
import com.example.llama.revamp.viewmodel.SystemPromptViewModel
|
import com.example.llama.revamp.viewmodel.SystemPromptViewModel
|
||||||
|
|
||||||
|
|
@ -108,11 +108,10 @@ fun ModelLoadingScreen(
|
||||||
engineState !is InferenceEngine.State.LibraryLoaded &&
|
engineState !is InferenceEngine.State.LibraryLoaded &&
|
||||||
engineState !is InferenceEngine.State.AwaitingUserPrompt
|
engineState !is InferenceEngine.State.AwaitingUserPrompt
|
||||||
|
|
||||||
AppScaffold(
|
PerformanceAppScaffold(
|
||||||
title = "Select Mode",
|
title = "Load Model",
|
||||||
drawerState = drawerState,
|
onNavigateBack = onBackPressed,
|
||||||
navigationActions = navigationActions,
|
showTemperature = false
|
||||||
onBackPressed = onBackPressed
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.llama.revamp.data.model.ModelInfo
|
import com.example.llama.revamp.data.model.ModelInfo
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
import com.example.llama.revamp.ui.components.PerformanceAppScaffold
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
@ -45,11 +45,10 @@ fun ModelSelectionScreen(
|
||||||
// For demo purposes, we'll use sample models
|
// For demo purposes, we'll use sample models
|
||||||
val models = remember { ModelInfo.getSampleModels() }
|
val models = remember { ModelInfo.getSampleModels() }
|
||||||
|
|
||||||
AppScaffold(
|
PerformanceAppScaffold(
|
||||||
title = "Models",
|
title = "Models",
|
||||||
drawerState = drawerState,
|
onMenuOpen = onMenuClicked,
|
||||||
navigationActions = navigationActions,
|
showTemperature = false
|
||||||
onMenuPressed = onMenuClicked
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,14 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.CloudDownload
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Done
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material.icons.filled.FileOpen
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.DrawerState
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
|
@ -23,15 +26,17 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.llama.revamp.data.model.ModelInfo
|
import com.example.llama.revamp.data.model.ModelInfo
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.ui.components.StorageAppScaffold
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
@ -42,18 +47,22 @@ import java.util.Locale
|
||||||
@Composable
|
@Composable
|
||||||
fun ModelsManagementScreen(
|
fun ModelsManagementScreen(
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
drawerState: DrawerState,
|
|
||||||
navigationActions: NavigationActions,
|
|
||||||
onMenuClicked: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
// For demo purposes, we'll use sample models
|
// For demo purposes, we'll use sample models
|
||||||
val installedModels = remember { ModelInfo.getSampleModels() }
|
val installedModels = remember { ModelInfo.getSampleModels() }
|
||||||
|
|
||||||
AppScaffold(
|
// Edit mode for models' batch deletion
|
||||||
title = "Models",
|
var isEditMode by remember { mutableStateOf(false) }
|
||||||
navigationActions = navigationActions,
|
|
||||||
onBackPressed = onBackPressed,
|
// Calculate storage info
|
||||||
onMenuPressed = onMenuClicked
|
val storageUsed = 14.6f // This would be calculated from actual models
|
||||||
|
val storageTotal = 32.0f // This would be from device storage info
|
||||||
|
|
||||||
|
StorageAppScaffold(
|
||||||
|
title = "Models Management",
|
||||||
|
storageUsed = storageUsed,
|
||||||
|
storageTotal = storageTotal,
|
||||||
|
onNavigateBack = onBackPressed,
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.llama.revamp.data.preferences.UserPreferences
|
import com.example.llama.revamp.data.preferences.UserPreferences
|
||||||
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
import com.example.llama.revamp.ui.components.DefaultAppScaffold
|
||||||
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
||||||
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
||||||
|
|
||||||
|
|
@ -56,11 +56,10 @@ fun SettingsGeneralScreen(
|
||||||
val isMonitoringEnabled by performanceViewModel.isMonitoringEnabled.collectAsState()
|
val isMonitoringEnabled by performanceViewModel.isMonitoringEnabled.collectAsState()
|
||||||
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
||||||
|
|
||||||
AppScaffold(
|
DefaultAppScaffold(
|
||||||
title = "Settings",
|
title = "Settings",
|
||||||
navigationActions = navigationActions,
|
onNavigateBack = onBackPressed,
|
||||||
onBackPressed = onBackPressed,
|
onMenuOpen = onMenuClicked
|
||||||
onMenuPressed = onMenuClicked
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue