diff --git a/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt b/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt index 6960e23b56..be6da82e35 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/MainActivity.kt @@ -504,13 +504,6 @@ fun AppContent( ) } - // Settings General Screen - composable(AppDestinations.SETTINGS_GENERAL_ROUTE) { - SettingsGeneralScreen( - viewModel = settingsViewModel - ) - } - // Models Management Screen composable(AppDestinations.MODELS_MANAGEMENT_ROUTE) { ModelsManagementScreen( @@ -518,6 +511,13 @@ fun AppContent( viewModel = modelsManagementViewModel ) } + + // General Settings Screen + composable(AppDestinations.SETTINGS_GENERAL_ROUTE) { + SettingsGeneralScreen( + viewModel = settingsViewModel + ) + } } } } diff --git a/examples/llama.android/app/src/main/java/com/example/llama/data/preferences/UserPreferences.kt b/examples/llama.android/app/src/main/java/com/example/llama/data/preferences/UserPreferences.kt index cf87c04a00..ec15c94c29 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/data/preferences/UserPreferences.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/data/preferences/UserPreferences.kt @@ -23,16 +23,18 @@ class UserPreferences @Inject constructor ( ) { companion object { - private val Context.dataStore: DataStore by preferencesDataStore(name = "settings") - // Performance monitoring preferences - val PERFORMANCE_MONITORING_ENABLED = booleanPreferencesKey("performance_monitoring_enabled") - val USE_FAHRENHEIT_TEMPERATURE = booleanPreferencesKey("use_fahrenheit_temperature") - val MONITORING_INTERVAL_MS = longPreferencesKey("monitoring_interval_ms") - val THEME_MODE = intPreferencesKey("theme_mode") + private const val DATASTORE_SETTINGS = "settings" + private val Context.settingsDataStore: DataStore + by preferencesDataStore(name = DATASTORE_SETTINGS) - // Default values - const val DEFAULT_MONITORING_INTERVAL_MS = 5000L + private val PERFORMANCE_MONITORING_ENABLED = booleanPreferencesKey("performance_monitoring_enabled") + private val USE_FAHRENHEIT_TEMPERATURE = booleanPreferencesKey("use_fahrenheit_temperature") + private val MONITORING_INTERVAL_MS = longPreferencesKey("monitoring_interval_ms") + private val THEME_MODE = intPreferencesKey("theme_mode") + + // Constants + private const val DEFAULT_MONITORING_INTERVAL_MS = 5000L // Theme mode values const val THEME_MODE_AUTO = 0 @@ -44,7 +46,7 @@ class UserPreferences @Inject constructor ( * Gets whether performance monitoring is enabled. */ fun isPerformanceMonitoringEnabled(): Flow { - return context.dataStore.data.map { preferences -> + return context.settingsDataStore.data.map { preferences -> preferences[PERFORMANCE_MONITORING_ENABLED] != false } } @@ -53,7 +55,7 @@ class UserPreferences @Inject constructor ( * Sets whether performance monitoring is enabled. */ suspend fun setPerformanceMonitoringEnabled(enabled: Boolean) { - context.dataStore.edit { preferences -> + context.settingsDataStore.edit { preferences -> preferences[PERFORMANCE_MONITORING_ENABLED] = enabled } } @@ -62,7 +64,7 @@ class UserPreferences @Inject constructor ( * Gets whether temperature should be displayed in Fahrenheit. */ fun usesFahrenheitTemperature(): Flow { - return context.dataStore.data.map { preferences -> + return context.settingsDataStore.data.map { preferences -> preferences[USE_FAHRENHEIT_TEMPERATURE] == true } } @@ -71,7 +73,7 @@ class UserPreferences @Inject constructor ( * Sets whether temperature should be displayed in Fahrenheit. */ suspend fun setUseFahrenheitTemperature(useFahrenheit: Boolean) { - context.dataStore.edit { preferences -> + context.settingsDataStore.edit { preferences -> preferences[USE_FAHRENHEIT_TEMPERATURE] = useFahrenheit } } @@ -82,7 +84,7 @@ class UserPreferences @Inject constructor ( * TODO-han.yin: replace with Enum value instead of millisecond value */ fun getMonitoringInterval(): Flow { - return context.dataStore.data.map { preferences -> + return context.settingsDataStore.data.map { preferences -> preferences[MONITORING_INTERVAL_MS] ?: DEFAULT_MONITORING_INTERVAL_MS } } @@ -91,7 +93,7 @@ class UserPreferences @Inject constructor ( * Sets the monitoring interval in milliseconds. */ suspend fun setMonitoringInterval(intervalMs: Long) { - context.dataStore.edit { preferences -> + context.settingsDataStore.edit { preferences -> preferences[MONITORING_INTERVAL_MS] = intervalMs } } @@ -100,7 +102,7 @@ class UserPreferences @Inject constructor ( * Gets the current theme mode. */ fun getThemeMode(): Flow { - return context.dataStore.data.map { preferences -> + return context.settingsDataStore.data.map { preferences -> preferences[THEME_MODE] ?: THEME_MODE_AUTO } } @@ -109,7 +111,7 @@ class UserPreferences @Inject constructor ( * Sets the theme mode. */ suspend fun setThemeMode(mode: Int) { - context.dataStore.edit { preferences -> + context.settingsDataStore.edit { preferences -> preferences[THEME_MODE] = mode } } 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 d905362aa6..7307838527 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 @@ -147,19 +147,19 @@ private fun DrawerContent( modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) ) - DrawerNavigationItem( - icon = Icons.Default.Settings, - label = "General Settings", - isSelected = currentRoute == AppDestinations.SETTINGS_GENERAL_ROUTE, - onClick = { onNavigate { navigationActions.navigateToSettingsGeneral() } } - ) - DrawerNavigationItem( icon = Icons.Default.Folder, label = "Models", isSelected = currentRoute == AppDestinations.MODELS_MANAGEMENT_ROUTE, onClick = { onNavigate { navigationActions.navigateToModelsManagement() } } ) + + DrawerNavigationItem( + icon = Icons.Default.Settings, + label = "General Settings", + isSelected = currentRoute == AppDestinations.SETTINGS_GENERAL_ROUTE, + onClick = { onNavigate { navigationActions.navigateToSettingsGeneral() } } + ) } } 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 de416fbe95..531685b10a 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 @@ -55,6 +55,12 @@ fun SettingsGeneralScreen( onCheckedChange = { viewModel.setMonitoringEnabled(it) } ) + Spacer(modifier = Modifier.height(8.dp)) + + HorizontalDivider() + + Spacer(modifier = Modifier.height(8.dp)) + SettingsSwitch( title = "Use Fahrenheit", description = "Display temperature in Fahrenheit instead of Celsius", @@ -64,115 +70,101 @@ fun SettingsGeneralScreen( } SettingsCategory(title = "Theme") { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + Text( + text = "Theme Mode", + style = MaterialTheme.typography.titleMedium + ) + + Text( + text = "Follow system setting or override with your choice", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(16.dp)) + + SingleChoiceSegmentedButtonRow( + modifier = Modifier.fillMaxWidth() ) { - Text( - text = "Theme Mode", - style = MaterialTheme.typography.titleMedium - ) - - Text( - text = "Follow system setting or override with your choice", - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - - Spacer(modifier = Modifier.height(16.dp)) - - SingleChoiceSegmentedButtonRow( - modifier = Modifier.fillMaxWidth() + SegmentedButton( + selected = themeMode == UserPreferences.THEME_MODE_AUTO, + onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_AUTO) }, + shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3) ) { - SegmentedButton( - selected = themeMode == UserPreferences.THEME_MODE_AUTO, - onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_AUTO) }, - shape = SegmentedButtonDefaults.itemShape(index = 0, count = 3) - ) { - Text("Auto") - } + Text("Auto") + } - SegmentedButton( - selected = themeMode == UserPreferences.THEME_MODE_LIGHT, - onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_LIGHT) }, - shape = SegmentedButtonDefaults.itemShape(index = 1, count = 3) - ) { - Text("Light") - } + SegmentedButton( + selected = themeMode == UserPreferences.THEME_MODE_LIGHT, + onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_LIGHT) }, + shape = SegmentedButtonDefaults.itemShape(index = 1, count = 3) + ) { + Text("Light") + } - SegmentedButton( - selected = themeMode == UserPreferences.THEME_MODE_DARK, - onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_DARK) }, - shape = SegmentedButtonDefaults.itemShape(index = 2, count = 3) - ) { - Text("Dark") - } + SegmentedButton( + selected = themeMode == UserPreferences.THEME_MODE_DARK, + onClick = { viewModel.setThemeMode(UserPreferences.THEME_MODE_DARK) }, + shape = SegmentedButtonDefaults.itemShape(index = 2, count = 3) + ) { + Text("Dark") } } } // ARM Features Visualizer with Tier Information description SettingsCategory(title = "About your device") { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text( - text = "ARM Capabilities", - style = MaterialTheme.typography.titleLarge - ) + Text( + text = "ARM Capabilities", + style = MaterialTheme.typography.titleMedium + ) - Text( - text = "Hardware-accelerated AI features", - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) + Text( + text = "Hardware-accelerated AI features", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) - detectedTier?.let { tier -> - Spacer(modifier = Modifier.height(8.dp)) + detectedTier?.let { tier -> + Spacer(modifier = Modifier.height(8.dp)) - ArmFeaturesVisualizerClickable(detectedTier = detectedTier) - - Spacer(modifier = Modifier.height(8.dp)) - - Text( - text = "Optimization Tier: ${tier.name}", - style = MaterialTheme.typography.bodyLarge - ) - - Text( - text = tier.description, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(top = 4.dp) - ) - } - } - } - - SettingsCategory(title = "About this app") { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text( - text = APP_NAME, - style = MaterialTheme.typography.titleLarge - ) - - Text( - text = "Version 1.0.0", - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) + ArmFeaturesVisualizerClickable(detectedTier = detectedTier) Spacer(modifier = Modifier.height(8.dp)) Text( - text = "Local inference for LLM models on your device powered by ArmĀ® technologies.", - style = MaterialTheme.typography.bodyLarge + text = "Optimization Tier: ${tier.name}", + style = MaterialTheme.typography.titleMedium + ) + + Text( + text = tier.description, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 4.dp) ) } } + + SettingsCategory(title = "About this app") { + Text( + text = APP_NAME, + style = MaterialTheme.typography.titleMedium + ) + + Text( + text = "Version 1.0.0", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Local inference for LLM models on your device powered by ArmĀ® technologies.", + style = MaterialTheme.typography.bodyMedium + ) + } } } @@ -182,20 +174,16 @@ fun SettingsCategory( content: @Composable () -> Unit ) { Column( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp) + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) ) { Text( text = title, - style = MaterialTheme.typography.titleMedium, + style = MaterialTheme.typography.labelLarge, modifier = Modifier.padding(bottom = 8.dp) ) - Card( - modifier = Modifier.fillMaxWidth() - ) { - Column { + Card(modifier = Modifier.fillMaxWidth()) { + Column( modifier = Modifier.fillMaxWidth().padding(16.dp)) { content() } } @@ -211,36 +199,28 @@ fun SettingsSwitch( checked: Boolean, onCheckedChange: (Boolean) -> Unit ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() + Column( + modifier = Modifier.weight(1f) ) { - Column( - modifier = Modifier.weight(1f) - ) { - Text( - text = title, - style = MaterialTheme.typography.titleMedium - ) + Text( + text = title, + style = MaterialTheme.typography.titleMedium + ) - Text( - text = description, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - - Switch( - checked = checked, - onCheckedChange = onCheckedChange + Text( + text = description, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant ) } - } - HorizontalDivider() + Switch( + checked = checked, + onCheckedChange = onCheckedChange + ) + } }