UI: fix UI issues in the generic settings screen and navigation drawer
This commit is contained in:
parent
36c3768f52
commit
eba09a3d40
|
|
@ -48,6 +48,7 @@ android {
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose = true
|
compose = true
|
||||||
|
buildConfig = true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion = "1.5.1"
|
kotlinCompilerExtensionVersion = "1.5.1"
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,6 @@ class UserPreferences @Inject constructor (
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
private const val DEFAULT_MONITORING_INTERVAL_MS = 5000L
|
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.
|
* Gets the current color theme mode.
|
||||||
*/
|
*/
|
||||||
fun getColorThemeMode(): Flow<Int> =
|
fun getColorThemeMode(): Flow<ColorThemeMode> =
|
||||||
context.settingsDataStore.data.map { preferences ->
|
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.
|
* 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 ->
|
context.settingsDataStore.edit { preferences ->
|
||||||
preferences[COLOR_THEME_MODE] = mode
|
preferences[COLOR_THEME_MODE] = mode.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current dark theme mode.
|
* Gets the current dark theme mode.
|
||||||
*/
|
*/
|
||||||
fun getDarkThemeMode(): Flow<Int> =
|
fun getDarkThemeMode(): Flow<DarkThemeMode> =
|
||||||
context.settingsDataStore.data.map { preferences ->
|
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.
|
* 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 ->
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.llama.APP_NAME
|
import com.example.llama.APP_NAME
|
||||||
|
import com.example.llama.BuildConfig
|
||||||
import com.example.llama.navigation.AppDestinations
|
import com.example.llama.navigation.AppDestinations
|
||||||
import com.example.llama.navigation.NavigationActions
|
import com.example.llama.navigation.NavigationActions
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -111,7 +112,7 @@ private fun DrawerContent(
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "v1.0.0",
|
text = BuildConfig.VERSION_NAME,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(top = 4.dp)
|
modifier = Modifier.padding(top = 4.dp)
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,12 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.example.llama.APP_NAME
|
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.ui.components.ArmFeaturesVisualizer
|
||||||
import com.example.llama.viewmodel.SettingsViewModel
|
import com.example.llama.viewmodel.SettingsViewModel
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen for general app settings
|
* Screen for general app settings
|
||||||
|
|
@ -67,11 +70,7 @@ fun SettingsGeneralScreen(
|
||||||
onCheckedChange = { viewModel.setMonitoringEnabled(it) }
|
onCheckedChange = { viewModel.setMonitoringEnabled(it) }
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
|
||||||
|
|
||||||
HorizontalDivider()
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
|
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
title = "Use Fahrenheit",
|
title = "Use Fahrenheit",
|
||||||
|
|
@ -99,24 +98,24 @@ fun SettingsGeneralScreen(
|
||||||
SingleChoiceSegmentedButtonRow(
|
SingleChoiceSegmentedButtonRow(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
SegmentedButton(
|
ColorThemeMode.entries.forEachIndexed { index, mode ->
|
||||||
modifier = Modifier.weight(3f),
|
val weight = sqrt(sqrt(mode.label.length.toFloat()))
|
||||||
selected = colorThemeMode == UserPreferences.COLOR_THEME_MODE_ARM,
|
|
||||||
onClick = { viewModel.setColorThemeMode(UserPreferences.COLOR_THEME_MODE_ARM) },
|
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2)
|
|
||||||
) {
|
|
||||||
Text("Arm")
|
|
||||||
}
|
|
||||||
|
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
modifier = Modifier.weight(4f),
|
modifier = Modifier.weight(weight),
|
||||||
selected = colorThemeMode == UserPreferences.COLOR_THEME_MODE_MATERIAL,
|
selected = colorThemeMode == mode,
|
||||||
onClick = { viewModel.setColorThemeMode(UserPreferences.COLOR_THEME_MODE_MATERIAL) },
|
onClick = { viewModel.setColorThemeMode(mode) },
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2)
|
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
|
// Dark theme mode
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -135,28 +134,14 @@ fun SettingsGeneralScreen(
|
||||||
SingleChoiceSegmentedButtonRow(
|
SingleChoiceSegmentedButtonRow(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
|
DarkThemeMode.entries.forEachIndexed { index, mode ->
|
||||||
SegmentedButton(
|
SegmentedButton(
|
||||||
selected = darkThemeMode == UserPreferences.DARK_THEME_MODE_AUTO,
|
selected = darkThemeMode == mode,
|
||||||
onClick = { viewModel.setDarkThemeMode(UserPreferences.DARK_THEME_MODE_AUTO) },
|
onClick = { viewModel.setDarkThemeMode(mode) },
|
||||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3)
|
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
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Available hardware capabilities on your device are highlighted below:",
|
text = "Available hardware capabilities on your device are highlighted below:",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(top = 4.dp, bottom = 8.dp)
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
supportedFeatures?.let {
|
supportedFeatures?.let {
|
||||||
|
|
@ -186,7 +169,7 @@ fun SettingsGeneralScreen(
|
||||||
text = "Tap a feature above to learn more about how it accelerates Generative AI!",
|
text = "Tap a feature above to learn more about how it accelerates Generative AI!",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
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(
|
||||||
text = "Version 1.0.0",
|
text = "Version ${BuildConfig.VERSION_NAME}",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(vertical = 4.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,8 @@ import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import com.example.llama.data.source.prefs.UserPreferences
|
import com.example.llama.data.source.prefs.ColorThemeMode
|
||||||
import com.example.llama.data.source.prefs.UserPreferences.Companion.COLOR_THEME_MODE_ARM
|
import com.example.llama.data.source.prefs.DarkThemeMode
|
||||||
import com.example.llama.data.source.prefs.UserPreferences.Companion.COLOR_THEME_MODE_MATERIAL
|
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
|
||||||
// -------------------- ColorScheme --------------------
|
// -------------------- ColorScheme --------------------
|
||||||
|
|
@ -143,23 +142,21 @@ internal val armDarkColorScheme: ColorScheme = darkColorScheme(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LlamaTheme(
|
fun LlamaTheme(
|
||||||
colorThemeMode: Int,
|
colorThemeMode: ColorThemeMode,
|
||||||
darkThemeMode: Int,
|
darkThemeMode: DarkThemeMode,
|
||||||
content: @Composable () -> Unit
|
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 context = LocalContext.current
|
||||||
|
|
||||||
|
val darkTheme = when (darkThemeMode) {
|
||||||
|
DarkThemeMode.AUTO -> isSystemInDarkTheme()
|
||||||
|
DarkThemeMode.LIGHT -> false
|
||||||
|
DarkThemeMode.DARK -> true
|
||||||
|
}
|
||||||
val colorScheme = when(colorThemeMode) {
|
val colorScheme = when(colorThemeMode) {
|
||||||
COLOR_THEME_MODE_ARM -> if (darkTheme) armDarkColorScheme else armLightColorScheme
|
ColorThemeMode.ARM -> if (darkTheme) armDarkColorScheme else armLightColorScheme
|
||||||
COLOR_THEME_MODE_MATERIAL ->
|
ColorThemeMode.MATERIAL ->
|
||||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
else -> error("Unexpected color theme $colorThemeMode")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import android.llama.cpp.TierDetection
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.llama.data.repo.ModelRepository
|
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.data.source.prefs.UserPreferences
|
||||||
import com.example.llama.monitoring.BatteryMetrics
|
import com.example.llama.monitoring.BatteryMetrics
|
||||||
import com.example.llama.monitoring.MemoryMetrics
|
import com.example.llama.monitoring.MemoryMetrics
|
||||||
|
|
@ -58,11 +60,11 @@ class SettingsViewModel @Inject constructor(
|
||||||
val monitoringInterval: StateFlow<Long> = _monitoringInterval.asStateFlow()
|
val monitoringInterval: StateFlow<Long> = _monitoringInterval.asStateFlow()
|
||||||
|
|
||||||
// User preferences: themes
|
// User preferences: themes
|
||||||
private val _colorThemeMode = MutableStateFlow(UserPreferences.COLOR_THEME_MODE_ARM)
|
private val _colorThemeMode = MutableStateFlow(ColorThemeMode.ARM)
|
||||||
val colorThemeMode: StateFlow<Int> = _colorThemeMode.asStateFlow()
|
val colorThemeMode: StateFlow<ColorThemeMode> = _colorThemeMode.asStateFlow()
|
||||||
|
|
||||||
private val _darkThemeMode = MutableStateFlow(UserPreferences.DARK_THEME_MODE_AUTO)
|
private val _darkThemeMode = MutableStateFlow(DarkThemeMode.AUTO)
|
||||||
val darkThemeMode: StateFlow<Int> = _darkThemeMode.asStateFlow()
|
val darkThemeMode: StateFlow<DarkThemeMode> = _darkThemeMode.asStateFlow()
|
||||||
|
|
||||||
val detectedTier: LLamaTier?
|
val detectedTier: LLamaTier?
|
||||||
get() = tierDetection.detectedTier
|
get() = tierDetection.detectedTier
|
||||||
|
|
@ -80,19 +82,6 @@ class SettingsViewModel @Inject constructor(
|
||||||
if (_isMonitoringEnabled.value) {
|
if (_isMonitoringEnabled.value) {
|
||||||
startMonitoring()
|
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.
|
* Sets the color theme mode.
|
||||||
*/
|
*/
|
||||||
fun setColorThemeMode(mode: Int) {
|
fun setColorThemeMode(mode: ColorThemeMode) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
userPreferences.setColorThemeMode(mode)
|
userPreferences.setColorThemeMode(mode)
|
||||||
_colorThemeMode.value = mode
|
_colorThemeMode.value = mode
|
||||||
|
|
@ -181,7 +170,7 @@ class SettingsViewModel @Inject constructor(
|
||||||
/**
|
/**
|
||||||
* Sets the dark theme mode.
|
* Sets the dark theme mode.
|
||||||
*/
|
*/
|
||||||
fun setDarkThemeMode(mode: Int) {
|
fun setDarkThemeMode(mode: DarkThemeMode) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
userPreferences.setDarkThemeMode(mode)
|
userPreferences.setDarkThemeMode(mode)
|
||||||
_darkThemeMode.value = mode
|
_darkThemeMode.value = mode
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue