From eba09a3d404d18a4659a91d3d8adc429faef30f5 Mon Sep 17 00:00:00 2001 From: Han Yin Date: Tue, 2 Sep 2025 14:14:21 -0700 Subject: [PATCH] UI: fix UI issues in the generic settings screen and navigation drawer --- examples/llama.android/app/build.gradle.kts | 1 + .../data/source/prefs/UserPreferences.kt | 42 ++++++---- .../llama/ui/scaffold/NavigationDrawer.kt | 3 +- .../llama/ui/screens/SettingsGeneralScreen.kt | 82 ++++++++----------- .../java/com/example/llama/ui/theme/Theme.kt | 25 +++--- .../llama/viewmodel/SettingsViewModel.kt | 27 ++---- 6 files changed, 82 insertions(+), 98 deletions(-) diff --git a/examples/llama.android/app/build.gradle.kts b/examples/llama.android/app/build.gradle.kts index 1ea0b5a469..e272fd15de 100644 --- a/examples/llama.android/app/build.gradle.kts +++ b/examples/llama.android/app/build.gradle.kts @@ -48,6 +48,7 @@ android { } buildFeatures { compose = true + buildConfig = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.1" diff --git a/examples/llama.android/app/src/main/java/com/example/llama/data/source/prefs/UserPreferences.kt b/examples/llama.android/app/src/main/java/com/example/llama/data/source/prefs/UserPreferences.kt index 5f73f3088c..40dec5f13c 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/data/source/prefs/UserPreferences.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/data/source/prefs/UserPreferences.kt @@ -38,13 +38,6 @@ class UserPreferences @Inject constructor ( // Constants private const val DEFAULT_MONITORING_INTERVAL_MS = 5000L - - const val COLOR_THEME_MODE_ARM = 0 - const val COLOR_THEME_MODE_MATERIAL = 1 - - const val DARK_THEME_MODE_AUTO = 0 - const val DARK_THEME_MODE_LIGHT = 1 - const val DARK_THEME_MODE_DARK = 2 } /** @@ -103,34 +96,53 @@ class UserPreferences @Inject constructor ( /** * Gets the current color theme mode. */ - fun getColorThemeMode(): Flow = + fun getColorThemeMode(): Flow = context.settingsDataStore.data.map { preferences -> - preferences[COLOR_THEME_MODE] ?: COLOR_THEME_MODE_ARM + ColorThemeMode.fromInt(preferences[COLOR_THEME_MODE]) ?: ColorThemeMode.ARM } /** * Sets the color theme mode. */ - suspend fun setColorThemeMode(mode: Int) = withContext(Dispatchers.IO) { + suspend fun setColorThemeMode(mode: ColorThemeMode) = withContext(Dispatchers.IO) { context.settingsDataStore.edit { preferences -> - preferences[COLOR_THEME_MODE] = mode + preferences[COLOR_THEME_MODE] = mode.value } } /** * Gets the current dark theme mode. */ - fun getDarkThemeMode(): Flow = + fun getDarkThemeMode(): Flow = context.settingsDataStore.data.map { preferences -> - preferences[DARK_THEME_MODE] ?: DARK_THEME_MODE_AUTO + DarkThemeMode.fromInt(preferences[DARK_THEME_MODE]) ?: DarkThemeMode.AUTO } /** * Sets the dark theme mode. */ - suspend fun setDarkThemeMode(mode: Int) = withContext(Dispatchers.IO) { + suspend fun setDarkThemeMode(mode: DarkThemeMode) = withContext(Dispatchers.IO) { context.settingsDataStore.edit { preferences -> - preferences[DARK_THEME_MODE] = mode + preferences[DARK_THEME_MODE] = mode.value } } } + +enum class ColorThemeMode(val value: Int, val label: String) { + ARM(0, "ArmĀ®"), + MATERIAL(1, "Material Design"); + + companion object { + fun fromInt(value: Int?) = entries.find { it.value == value } + } +} + +enum class DarkThemeMode(val value: Int, val label: String) { + AUTO(0, "Auto"), + LIGHT(1, "Light"), + DARK(2, "Dark"); + + companion object { + fun fromInt(value: Int?) = entries.find { it.value == value } + } +} diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/NavigationDrawer.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/NavigationDrawer.kt index de23b065c3..b72bb219c8 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/NavigationDrawer.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/scaffold/NavigationDrawer.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.example.llama.APP_NAME +import com.example.llama.BuildConfig import com.example.llama.navigation.AppDestinations import com.example.llama.navigation.NavigationActions import kotlinx.coroutines.launch @@ -111,7 +112,7 @@ private fun DrawerContent( ) Text( - text = "v1.0.0", + text = BuildConfig.VERSION_NAME, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 4.dp) diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/screens/SettingsGeneralScreen.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/screens/SettingsGeneralScreen.kt index 47d4bcd599..9ab75e942f 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/screens/SettingsGeneralScreen.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/screens/SettingsGeneralScreen.kt @@ -31,9 +31,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.core.net.toUri import com.example.llama.APP_NAME -import com.example.llama.data.source.prefs.UserPreferences +import com.example.llama.BuildConfig +import com.example.llama.data.source.prefs.ColorThemeMode +import com.example.llama.data.source.prefs.DarkThemeMode import com.example.llama.ui.components.ArmFeaturesVisualizer import com.example.llama.viewmodel.SettingsViewModel +import kotlin.math.sqrt /** * Screen for general app settings @@ -67,11 +70,7 @@ fun SettingsGeneralScreen( onCheckedChange = { viewModel.setMonitoringEnabled(it) } ) - Spacer(modifier = Modifier.height(8.dp)) - - HorizontalDivider() - - Spacer(modifier = Modifier.height(8.dp)) + HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) SettingsSwitch( title = "Use Fahrenheit", @@ -99,25 +98,25 @@ fun SettingsGeneralScreen( SingleChoiceSegmentedButtonRow( modifier = Modifier.fillMaxWidth() ) { - SegmentedButton( - modifier = Modifier.weight(3f), - selected = colorThemeMode == UserPreferences.COLOR_THEME_MODE_ARM, - onClick = { viewModel.setColorThemeMode(UserPreferences.COLOR_THEME_MODE_ARM) }, - shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2) - ) { - Text("Arm") - } + ColorThemeMode.entries.forEachIndexed { index, mode -> + val weight = sqrt(sqrt(mode.label.length.toFloat())) - SegmentedButton( - modifier = Modifier.weight(4f), - selected = colorThemeMode == UserPreferences.COLOR_THEME_MODE_MATERIAL, - onClick = { viewModel.setColorThemeMode(UserPreferences.COLOR_THEME_MODE_MATERIAL) }, - shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2) - ) { - Text("Material Design") + SegmentedButton( + modifier = Modifier.weight(weight), + selected = colorThemeMode == mode, + onClick = { viewModel.setColorThemeMode(mode) }, + shape = SegmentedButtonDefaults.itemShape( + index = index, + count = ColorThemeMode.entries.size + ) + ) { + Text(mode.label) + } } } + HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp)) + // Dark theme mode Text( text = "Dark Mode", @@ -135,28 +134,14 @@ fun SettingsGeneralScreen( SingleChoiceSegmentedButtonRow( modifier = Modifier.fillMaxWidth() ) { - SegmentedButton( - selected = darkThemeMode == UserPreferences.DARK_THEME_MODE_AUTO, - onClick = { viewModel.setDarkThemeMode(UserPreferences.DARK_THEME_MODE_AUTO) }, - shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3) - ) { - Text("Auto") - } - - SegmentedButton( - selected = darkThemeMode == UserPreferences.DARK_THEME_MODE_LIGHT, - onClick = { viewModel.setDarkThemeMode(UserPreferences.DARK_THEME_MODE_LIGHT) }, - shape = SegmentedButtonDefaults.itemShape(index = 1, count = 3) - ) { - Text("Light") - } - - SegmentedButton( - selected = darkThemeMode == UserPreferences.DARK_THEME_MODE_DARK, - onClick = { viewModel.setDarkThemeMode(UserPreferences.DARK_THEME_MODE_DARK) }, - shape = SegmentedButtonDefaults.itemShape(index = 2, count = 3) - ) { - Text("Dark") + DarkThemeMode.entries.forEachIndexed { index, mode -> + SegmentedButton( + selected = darkThemeMode == mode, + onClick = { viewModel.setDarkThemeMode(mode) }, + shape = SegmentedButtonDefaults.itemShape(index = index, count = DarkThemeMode.entries.size) + ) { + Text(mode.label) + } } } } @@ -169,13 +154,11 @@ fun SettingsGeneralScreen( style = MaterialTheme.typography.titleMedium ) - Spacer(modifier = Modifier.height(4.dp)) - Text( text = "Available hardware capabilities on your device are highlighted below:", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(top = 4.dp, bottom = 8.dp) + modifier = Modifier.padding(vertical = 8.dp) ) supportedFeatures?.let { @@ -186,7 +169,7 @@ fun SettingsGeneralScreen( text = "Tap a feature above to learn more about how it accelerates Generative AI!", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(top = 8.dp, bottom = 4.dp) + modifier = Modifier.padding(vertical = 8.dp) ) } } @@ -198,9 +181,10 @@ fun SettingsGeneralScreen( ) Text( - text = "Version 1.0.0", + text = "Version ${BuildConfig.VERSION_NAME}", style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(vertical = 4.dp) ) Spacer(modifier = Modifier.height(8.dp)) diff --git a/examples/llama.android/app/src/main/java/com/example/llama/ui/theme/Theme.kt b/examples/llama.android/app/src/main/java/com/example/llama/ui/theme/Theme.kt index 680ec405ba..adc0e25baf 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/ui/theme/Theme.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/ui/theme/Theme.kt @@ -14,9 +14,8 @@ import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat -import com.example.llama.data.source.prefs.UserPreferences -import com.example.llama.data.source.prefs.UserPreferences.Companion.COLOR_THEME_MODE_ARM -import com.example.llama.data.source.prefs.UserPreferences.Companion.COLOR_THEME_MODE_MATERIAL +import com.example.llama.data.source.prefs.ColorThemeMode +import com.example.llama.data.source.prefs.DarkThemeMode import com.google.accompanist.systemuicontroller.rememberSystemUiController // -------------------- ColorScheme -------------------- @@ -143,23 +142,21 @@ internal val armDarkColorScheme: ColorScheme = darkColorScheme( @Composable fun LlamaTheme( - colorThemeMode: Int, - darkThemeMode: Int, + colorThemeMode: ColorThemeMode, + darkThemeMode: DarkThemeMode, content: @Composable () -> Unit ) { - val darkTheme = when (darkThemeMode) { - UserPreferences.DARK_THEME_MODE_LIGHT -> false - UserPreferences.DARK_THEME_MODE_DARK -> true - else -> isSystemInDarkTheme() - } - val context = LocalContext.current + val darkTheme = when (darkThemeMode) { + DarkThemeMode.AUTO -> isSystemInDarkTheme() + DarkThemeMode.LIGHT -> false + DarkThemeMode.DARK -> true + } val colorScheme = when(colorThemeMode) { - COLOR_THEME_MODE_ARM -> if (darkTheme) armDarkColorScheme else armLightColorScheme - COLOR_THEME_MODE_MATERIAL -> + ColorThemeMode.ARM -> if (darkTheme) armDarkColorScheme else armLightColorScheme + ColorThemeMode.MATERIAL -> if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - else -> error("Unexpected color theme $colorThemeMode") } val view = LocalView.current diff --git a/examples/llama.android/app/src/main/java/com/example/llama/viewmodel/SettingsViewModel.kt b/examples/llama.android/app/src/main/java/com/example/llama/viewmodel/SettingsViewModel.kt index 91fdf29a80..f715fd25dd 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/viewmodel/SettingsViewModel.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/viewmodel/SettingsViewModel.kt @@ -5,6 +5,8 @@ import android.llama.cpp.TierDetection import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.llama.data.repo.ModelRepository +import com.example.llama.data.source.prefs.ColorThemeMode +import com.example.llama.data.source.prefs.DarkThemeMode import com.example.llama.data.source.prefs.UserPreferences import com.example.llama.monitoring.BatteryMetrics import com.example.llama.monitoring.MemoryMetrics @@ -58,11 +60,11 @@ class SettingsViewModel @Inject constructor( val monitoringInterval: StateFlow = _monitoringInterval.asStateFlow() // User preferences: themes - private val _colorThemeMode = MutableStateFlow(UserPreferences.COLOR_THEME_MODE_ARM) - val colorThemeMode: StateFlow = _colorThemeMode.asStateFlow() + private val _colorThemeMode = MutableStateFlow(ColorThemeMode.ARM) + val colorThemeMode: StateFlow = _colorThemeMode.asStateFlow() - private val _darkThemeMode = MutableStateFlow(UserPreferences.DARK_THEME_MODE_AUTO) - val darkThemeMode: StateFlow = _darkThemeMode.asStateFlow() + private val _darkThemeMode = MutableStateFlow(DarkThemeMode.AUTO) + val darkThemeMode: StateFlow = _darkThemeMode.asStateFlow() val detectedTier: LLamaTier? get() = tierDetection.detectedTier @@ -80,19 +82,6 @@ class SettingsViewModel @Inject constructor( if (_isMonitoringEnabled.value) { startMonitoring() } - -// viewModelScope.launch { -// launch { -// userPreferences.getColorThemeMode().collect { mode -> -// _colorThemeMode.value = mode -// } -// } -// launch { -// userPreferences.getDarkThemeMode().collect { mode -> -// _darkThemeMode.value = mode -// } -// } -// } } } @@ -171,7 +160,7 @@ class SettingsViewModel @Inject constructor( /** * Sets the color theme mode. */ - fun setColorThemeMode(mode: Int) { + fun setColorThemeMode(mode: ColorThemeMode) { viewModelScope.launch { userPreferences.setColorThemeMode(mode) _colorThemeMode.value = mode @@ -181,7 +170,7 @@ class SettingsViewModel @Inject constructor( /** * Sets the dark theme mode. */ - fun setDarkThemeMode(mode: Int) { + fun setDarkThemeMode(mode: DarkThemeMode) { viewModelScope.launch { userPreferences.setDarkThemeMode(mode) _darkThemeMode.value = mode