UI: code polish

This commit is contained in:
Han Yin 2025-04-12 20:44:20 -07:00
parent fddf060d92
commit e8b84c6ebf
12 changed files with 113 additions and 70 deletions

View File

@ -278,6 +278,7 @@ fun AppContent() {
} }
// Model unload confirmation dialog // Model unload confirmation dialog
// TODO-han.yin: show a progress indicator until the model success unloads?
if (showUnloadDialog) { if (showUnloadDialog) {
UnloadModelConfirmationDialog( UnloadModelConfirmationDialog(
onConfirm = { onConfirm = {

View File

@ -46,6 +46,11 @@ sealed class SystemPrompt {
* Creates a list of sample presets. * Creates a list of sample presets.
*/ */
val STUB_PRESETS = listOf( val STUB_PRESETS = listOf(
Preset(
id = "haiku",
name = "Matsuo Bashō",
content = "You are a wise and contemplative Japanese poet in the spirit of Matsuo Bashō. You speak only through haiku—short poems that capture fleeting moments, natures beauty, or quiet reflections of life. Each of your responses must follow the traditional haiku format: 3 lines; 5 syllables in the first line; 7 syllables in the second line; 5 syllables in the third line. Your words are serene, subtle, and full of meaning. You draw on imagery from nature, emotion, and the impermanence of all things. You do not explain or elaborate. You let the silence between the words speak for itself. Never break character. Never explain your form. Only respond in haiku."
),
Preset( Preset(
id = "assistant", id = "assistant",
name = "Helpful Assistant", name = "Helpful Assistant",

View File

@ -21,7 +21,7 @@ class PerformanceMonitor(private val context: Context) {
/** /**
* Provides a flow of memory usage information that updates at the specified interval. * Provides a flow of memory usage information that updates at the specified interval.
*/ */
fun monitorMemoryUsage(intervalMs: Long = 5000): Flow<MemoryMetrics> = flow { fun monitorMemoryUsage(intervalMs: Long = MEMORY_POLLING_INTERVAL): Flow<MemoryMetrics> = flow {
while(true) { while(true) {
emit(getMemoryInfo()) emit(getMemoryInfo())
delay(intervalMs) delay(intervalMs)
@ -31,7 +31,7 @@ class PerformanceMonitor(private val context: Context) {
/** /**
* Provides a flow of battery information that updates at the specified interval. * Provides a flow of battery information that updates at the specified interval.
*/ */
fun monitorBattery(intervalMs: Long = 10000): Flow<BatteryMetrics> = flow { fun monitorBattery(intervalMs: Long = BATTERY_POLLING_INTERVAL): Flow<BatteryMetrics> = flow {
while(true) { while(true) {
emit(getBatteryInfo()) emit(getBatteryInfo())
delay(intervalMs) delay(intervalMs)
@ -41,7 +41,7 @@ class PerformanceMonitor(private val context: Context) {
/** /**
* Provides a flow of temperature information that updates at the specified interval. * Provides a flow of temperature information that updates at the specified interval.
*/ */
fun monitorTemperature(intervalMs: Long = 10000): Flow<TemperatureMetrics> = flow { fun monitorTemperature(intervalMs: Long = TEMP_POLLING_INTERVAL): Flow<TemperatureMetrics> = flow {
while(true) { while(true) {
emit(getTemperatureInfo()) emit(getTemperatureInfo())
delay(intervalMs) delay(intervalMs)
@ -122,6 +122,12 @@ class PerformanceMonitor(private val context: Context) {
repeat(decimals) { multiplier *= 10 } repeat(decimals) { multiplier *= 10 }
return (this * multiplier).roundToInt() / multiplier return (this * multiplier).roundToInt() / multiplier
} }
companion object {
private const val MEMORY_POLLING_INTERVAL = 5000L
private const val BATTERY_POLLING_INTERVAL = 10000L
private const val TEMP_POLLING_INTERVAL = 10000L
}
} }
/** /**

View File

@ -54,14 +54,11 @@ fun AppScaffold(
val temperatureInfo by performanceViewModel.temperatureInfo.collectAsState() val temperatureInfo by performanceViewModel.temperatureInfo.collectAsState()
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState() val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
// Formatted memory usage
val memoryText = String.format("%.1f / %.1f GB", memoryUsage.availableGb, memoryUsage.totalGb)
Scaffold( Scaffold(
topBar = { topBar = {
SystemStatusTopBar( SystemStatusTopBar(
title = title, title = title,
memoryUsage = memoryText, memoryUsage = memoryUsage,
batteryLevel = batteryInfo.level, batteryLevel = batteryInfo.level,
temperature = temperatureInfo.temperature, temperature = temperatureInfo.temperature,
useFahrenheit = useFahrenheit, useFahrenheit = useFahrenheit,

View File

@ -154,7 +154,7 @@ private fun DrawerContent(
DrawerNavigationItem( DrawerNavigationItem(
icon = Icons.Default.Folder, icon = Icons.Default.Folder,
label = "Models Management", label = "Models",
isSelected = currentRoute == com.example.llama.revamp.navigation.AppDestinations.MODELS_MANAGEMENT_ROUTE, isSelected = currentRoute == com.example.llama.revamp.navigation.AppDestinations.MODELS_MANAGEMENT_ROUTE,
onClick = { onNavigate { navigationActions.navigateToModelsManagement() } } onClick = { onNavigate { navigationActions.navigateToModelsManagement() } }
) )

View File

@ -5,25 +5,28 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.BatteryAlert import androidx.compose.material.icons.filled.BatteryAlert
import androidx.compose.material.icons.filled.BatteryFull import androidx.compose.material.icons.filled.BatteryFull
import androidx.compose.material.icons.filled.BatteryStd 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.Menu
import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material.icons.filled.Thermostat
import androidx.compose.material.icons.filled.WarningAmber
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
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
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults 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.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.example.llama.revamp.monitoring.MemoryMetrics
/** /**
* Top app bar that displays system status information and navigation controls. * Top app bar that displays system status information and navigation controls.
@ -32,7 +35,7 @@ import androidx.compose.ui.unit.dp
@Composable @Composable
fun SystemStatusTopBar( fun SystemStatusTopBar(
title: String, title: String,
memoryUsage: String, memoryUsage: MemoryMetrics,
batteryLevel: Int, batteryLevel: Int,
temperature: Float, temperature: Float,
useFahrenheit: Boolean = false, useFahrenheit: Boolean = false,
@ -41,14 +44,14 @@ fun SystemStatusTopBar(
onRerunPressed: (() -> Unit)? = null, onRerunPressed: (() -> Unit)? = null,
onSharePressed: (() -> Unit)? = null onSharePressed: (() -> Unit)? = null
) { ) {
CenterAlignedTopAppBar( TopAppBar(
title = { Text(title) }, title = { Text(title) },
navigationIcon = { navigationIcon = {
when { when {
onBackPressed != null -> { onBackPressed != null -> {
IconButton(onClick = onBackPressed) { IconButton(onClick = onBackPressed) {
Icon( Icon(
imageVector = Icons.Default.ArrowBack, imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back" contentDescription = "Back"
) )
} }
@ -64,15 +67,28 @@ fun SystemStatusTopBar(
} }
}, },
actions = { actions = {
// Memory usage
Text(
text = memoryUsage,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(end = 8.dp)
)
// Battery and temperature
Row(verticalAlignment = Alignment.CenterVertically) { 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 // Battery icon and percentage
Icon( Icon(
imageVector = when { imageVector = when {
@ -92,9 +108,21 @@ fun SystemStatusTopBar(
style = MaterialTheme.typography.bodySmall style = MaterialTheme.typography.bodySmall
) )
Spacer(modifier = Modifier.width(8.dp)) 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
}
)
// Temperature display
val tempDisplay = if (useFahrenheit) { val tempDisplay = if (useFahrenheit) {
"${(temperature * 9/5 + 32).toInt()}°F" "${(temperature * 9/5 + 32).toInt()}°F"
} else { } else {
@ -103,7 +131,7 @@ fun SystemStatusTopBar(
val tempTint = when { val tempTint = when {
temperature >= 45 -> MaterialTheme.colorScheme.error temperature >= 45 -> MaterialTheme.colorScheme.error
temperature >= 40 -> Color(0xFFFFA500) // Orange warning color temperature >= 35 -> MaterialTheme.colorScheme.tertiary
else -> MaterialTheme.colorScheme.onSurface else -> MaterialTheme.colorScheme.onSurface
} }

View File

@ -57,11 +57,9 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.repeatOnLifecycle
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.AppScaffold
@ -123,7 +121,7 @@ fun ConversationScreen(
} }
AppScaffold( AppScaffold(
title = selectedModel?.name ?: "Conversation", title = "Chat",
drawerState = drawerState, drawerState = drawerState,
navigationActions = navigationActions, navigationActions = navigationActions,
onBackPressed = onBackPressed onBackPressed = onBackPressed
@ -134,7 +132,7 @@ fun ConversationScreen(
.padding(paddingValues) .padding(paddingValues)
) { ) {
// System prompt display (collapsible) // System prompt display (collapsible)
AnimatedSystemPrompt(systemPrompt) AnimatedSystemPrompt(selectedModel?.name, systemPrompt)
// Messages list // Messages list
Box( Box(
@ -165,15 +163,19 @@ fun ConversationScreen(
} }
@Composable @Composable
fun AnimatedSystemPrompt(systemPrompt: String?) { fun AnimatedSystemPrompt(modelName: String?, systemPrompt: String?) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
// TODO-han.yin: add model name into this card, on top of system prompt!
if (!systemPrompt.isNullOrBlank()) { if (!systemPrompt.isNullOrBlank()) {
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
onClick = { expanded = !expanded } onClick = {
expanded = !expanded
}
) { ) {
Column( Column(
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
@ -369,7 +371,7 @@ fun AssistantMessageBubble(
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = if (isThinking) "Thinking..." else "", text = if (isThinking) "Thinking" else "",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )

View File

@ -120,14 +120,17 @@ fun ModelLoadingScreen(
.padding(paddingValues) .padding(paddingValues)
.padding(16.dp) .padding(16.dp)
) { ) {
// Mode selection cards // Benchmark card
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 8.dp) .padding(bottom = 8.dp)
.selectable( .selectable(
selected = selectedMode == Mode.BENCHMARK, selected = selectedMode == Mode.BENCHMARK,
onClick = { selectedMode = Mode.BENCHMARK }, onClick = {
selectedMode = Mode.BENCHMARK
useSystemPrompt = false
},
enabled = !isLoading, enabled = !isLoading,
role = Role.RadioButton role = Role.RadioButton
) )
@ -142,23 +145,24 @@ fun ModelLoadingScreen(
) )
Text( Text(
text = "Benchmark", text = "Benchmark",
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(start = 8.dp) modifier = Modifier.padding(start = 8.dp)
) )
} }
} }
// Conversation card with integrated system prompt // Conversation card with integrated system prompt picker & editor
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 8.dp) .padding(bottom = 4.dp)
// Only use weight if system prompt is active, otherwise wrap content // Only use weight if system prompt is active, otherwise wrap content
.then(if (useSystemPrompt) Modifier.weight(1f) else Modifier) .then(if (useSystemPrompt) Modifier.weight(1f) else Modifier)
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 12.dp)
// Only fill height if system prompt is active // Only fill height if system prompt is active
.then(if (useSystemPrompt) Modifier.fillMaxSize() else Modifier) .then(if (useSystemPrompt) Modifier.fillMaxSize() else Modifier)
) { ) {
@ -172,7 +176,7 @@ fun ModelLoadingScreen(
enabled = !isLoading, enabled = !isLoading,
role = Role.RadioButton role = Role.RadioButton
) )
.padding(16.dp), .padding(top = 16.dp, start = 16.dp, end = 16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
RadioButton( RadioButton(
@ -181,7 +185,7 @@ fun ModelLoadingScreen(
) )
Text( Text(
text = "Conversation", text = "Conversation",
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(start = 8.dp) modifier = Modifier.padding(start = 8.dp)
) )
} }
@ -190,11 +194,11 @@ fun ModelLoadingScreen(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
text = "System prompt", text = "Use system prompt",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier modifier = Modifier
.padding(start = 32.dp) // Align with radio text .padding(start = 32.dp) // Align with radio text
@ -222,10 +226,13 @@ fun ModelLoadingScreen(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxSize() // Fill remaining card space .fillMaxSize()
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(start = 48.dp, end = 16.dp)
) { ) {
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) HorizontalDivider(
modifier = Modifier
.padding(top = 4.dp, bottom = 8.dp)
)
// Tab selector using SegmentedButton // Tab selector using SegmentedButton
SingleChoiceSegmentedButtonRow( SingleChoiceSegmentedButtonRow(
@ -277,7 +284,7 @@ fun ModelLoadingScreen(
) )
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(8.dp))
// Content based on selected tab // Content based on selected tab
when (selectedTab) { when (selectedTab) {
@ -353,6 +360,8 @@ fun ModelLoadingScreen(
// Flexible spacer when system prompt is not active // Flexible spacer when system prompt is not active
if (!useSystemPrompt) { if (!useSystemPrompt) {
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
} else {
Spacer(modifier = Modifier.height(8.dp))
} }
// Start button // Start button
@ -369,16 +378,20 @@ fun ModelLoadingScreen(
viewModel.savePromptToRecents(prompt) viewModel.savePromptToRecents(prompt)
prompt.content prompt.content
} }
SystemPromptTab.CUSTOM -> SystemPromptTab.CUSTOM ->
customPromptText.takeIf { it.isNotBlank() }?.also { promptText -> customPromptText.takeIf { it.isNotBlank() }
// Save custom prompt to database ?.also { promptText ->
viewModel.saveCustomPromptToRecents(promptText) // Save custom prompt to database
} viewModel.saveCustomPromptToRecents(promptText)
}
} }
} else null } else null
onConversationSelected(systemPrompt) onConversationSelected(systemPrompt)
} }
null -> { /* No mode selected */ }
null -> { /* No mode selected */
}
} }
}, },
modifier = Modifier modifier = Modifier
@ -395,15 +408,16 @@ fun ModelLoadingScreen(
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = when(engineState) { text = when (engineState) {
is InferenceEngine.State.LoadingModel -> "Loading model..." is InferenceEngine.State.LoadingModel -> "Loading model..."
is InferenceEngine.State.ProcessingSystemPrompt -> "Processing system prompt..." is InferenceEngine.State.ProcessingSystemPrompt -> "Processing system prompt..."
is InferenceEngine.State.ModelLoaded -> "Preparing conversation..." is InferenceEngine.State.ModelLoaded -> "Preparing conversation..."
else -> "Processing..." else -> "Processing..."
} },
style = MaterialTheme.typography.titleMedium
) )
} else { } else {
Text("Start") Text(text = "Start", style = MaterialTheme.typography.titleMedium)
} }
} }
} }
@ -423,7 +437,7 @@ fun PromptList(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxSize(), // Fill available space .fillMaxSize(), // Fill available space
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
items( items(
items = prompts, items = prompts,
@ -480,7 +494,7 @@ fun PromptList(
if (prompt.id != prompts.last().id) { if (prompt.id != prompts.last().id) {
HorizontalDivider( HorizontalDivider(
modifier = Modifier.padding(top = 8.dp, start = 40.dp) modifier = Modifier.padding(top = 8.dp, start = 32.dp)
) )
} }
} }

View File

@ -66,12 +66,6 @@ fun ModelSelectionScreen(
Text("Manage Models") Text("Manage Models")
} }
Text(
text = "Downloaded Models",
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(vertical = 8.dp)
)
LazyColumn { LazyColumn {
items(models) { model -> items(models) { model ->
ModelCard( ModelCard(

View File

@ -1,6 +1,5 @@
package com.example.llama.revamp.ui.screens package com.example.llama.revamp.ui.screens
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -8,18 +7,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
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.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.Button
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.DrawerState 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
@ -27,7 +21,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -57,7 +50,7 @@ fun ModelsManagementScreen(
val installedModels = remember { ModelInfo.getSampleModels() } val installedModels = remember { ModelInfo.getSampleModels() }
AppScaffold( AppScaffold(
title = "Models Management", title = "Models",
navigationActions = navigationActions, navigationActions = navigationActions,
onBackPressed = onBackPressed, onBackPressed = onBackPressed,
onMenuPressed = onMenuClicked onMenuPressed = onMenuClicked

View File

@ -90,7 +90,9 @@ fun SettingsGeneralScreen(
title = "Dark Theme", title = "Dark Theme",
description = "Use dark theme throughout the app", description = "Use dark theme throughout the app",
checked = true, // This would be connected to theme state in a real app checked = true, // This would be connected to theme state in a real app
onCheckedChange = { /* TODO: Implement theme switching */ } onCheckedChange = {
/* TODO-hyin: Implement theme switching between Auto, Light and Dark */
}
) )
} }

View File

@ -66,5 +66,6 @@ val md_theme_dark_outlineVariant = Color(0xFF49454E)
val md_theme_dark_scrim = Color(0xFF000000) val md_theme_dark_scrim = Color(0xFF000000)
// Additional app-specific colors // Additional app-specific colors
val CriticalColor = Color(0xFFFF0000)
val WarningColor = Color(0xFFFFA000) val WarningColor = Color(0xFFFFA000)
val SuccessColor = Color(0xFF388E3C) val SuccessColor = Color(0xFF388E3C)