UI: fix UI issues in the generic settings screen and navigation drawer

This commit is contained in:
Han Yin 2025-09-02 14:14:21 -07:00
parent 36c3768f52
commit eba09a3d40
6 changed files with 82 additions and 98 deletions

View File

@ -48,6 +48,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"

View File

@ -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<Int> =
fun getColorThemeMode(): Flow<ColorThemeMode> =
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<Int> =
fun getDarkThemeMode(): Flow<DarkThemeMode> =
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 }
}
}

View File

@ -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)

View File

@ -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,24 +98,24 @@ 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)
modifier = Modifier.weight(weight),
selected = colorThemeMode == mode,
onClick = { viewModel.setColorThemeMode(mode) },
shape = SegmentedButtonDefaults.itemShape(
index = index,
count = ColorThemeMode.entries.size
)
) {
Text("Material Design")
Text(mode.label)
}
}
}
HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp))
// Dark theme mode
Text(
@ -135,28 +134,14 @@ fun SettingsGeneralScreen(
SingleChoiceSegmentedButtonRow(
modifier = Modifier.fillMaxWidth()
) {
DarkThemeMode.entries.forEachIndexed { index, mode ->
SegmentedButton(
selected = darkThemeMode == UserPreferences.DARK_THEME_MODE_AUTO,
onClick = { viewModel.setDarkThemeMode(UserPreferences.DARK_THEME_MODE_AUTO) },
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3)
selected = darkThemeMode == mode,
onClick = { viewModel.setDarkThemeMode(mode) },
shape = SegmentedButtonDefaults.itemShape(index = index, count = DarkThemeMode.entries.size)
) {
Text("Auto")
Text(mode.label)
}
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")
}
}
}
@ -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))

View File

@ -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

View File

@ -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<Long> = _monitoringInterval.asStateFlow()
// User preferences: themes
private val _colorThemeMode = MutableStateFlow(UserPreferences.COLOR_THEME_MODE_ARM)
val colorThemeMode: StateFlow<Int> = _colorThemeMode.asStateFlow()
private val _colorThemeMode = MutableStateFlow(ColorThemeMode.ARM)
val colorThemeMode: StateFlow<ColorThemeMode> = _colorThemeMode.asStateFlow()
private val _darkThemeMode = MutableStateFlow(UserPreferences.DARK_THEME_MODE_AUTO)
val darkThemeMode: StateFlow<Int> = _darkThemeMode.asStateFlow()
private val _darkThemeMode = MutableStateFlow(DarkThemeMode.AUTO)
val darkThemeMode: StateFlow<DarkThemeMode> = _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