From d02e99ea699cc97f6431cfe268d9f6de4fead3ac Mon Sep 17 00:00:00 2001 From: kerdx <69465056+kerdx@users.noreply.github.com> Date: Thu, 17 Sep 2026 09:17:12 +0200 Subject: [PATCH] feat: add Material You dynamic color toggle in Appearance settings --- app/src/main/java/pm/antani/resentin/MainActivity.kt | 2 ++ .../pm/antani/resentin/data/prefs/AppPreferences.kt | 10 ++++++++++ .../resentin/ui/appsettings/AppSettingsScreen.kt | 12 ++++++++++++ .../resentin/ui/appsettings/AppSettingsViewModel.kt | 7 +++++++ .../java/pm/antani/resentin/ui/home/HomeScreen.kt | 2 +- .../java/pm/antani/resentin/ui/login/LoginScreen.kt | 2 +- .../main/java/pm/antani/resentin/ui/theme/Theme.kt | 10 ++++++++++ app/src/main/res/values-en/strings.xml | 2 ++ app/src/main/res/values/strings.xml | 2 ++ 9 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pm/antani/resentin/MainActivity.kt b/app/src/main/java/pm/antani/resentin/MainActivity.kt index 756ad93..4c47a0d 100644 --- a/app/src/main/java/pm/antani/resentin/MainActivity.kt +++ b/app/src/main/java/pm/antani/resentin/MainActivity.kt @@ -45,6 +45,7 @@ class MainActivity : ComponentActivity() { val lineHeightScale by container.appPreferences.lineHeightScale.collectAsState(initial = 1f) val messageDensity by container.appPreferences.messageDensity.collectAsState(initial = MessageDensity.NORMAL) val themeMode by container.appPreferences.themeMode.collectAsState(initial = ThemeMode.SYSTEM) + val dynamicColor by container.appPreferences.dynamicColor.collectAsState(initial = false) val useDarkTheme = when (themeMode) { ThemeMode.LIGHT -> false ThemeMode.DARK -> true @@ -52,6 +53,7 @@ class MainActivity : ComponentActivity() { } ResentinTheme( darkTheme = useDarkTheme, + dynamicColor = dynamicColor, fontScale = fontScale, lineHeightScale = lineHeightScale, fontFamilyChoice = fontFamily, diff --git a/app/src/main/java/pm/antani/resentin/data/prefs/AppPreferences.kt b/app/src/main/java/pm/antani/resentin/data/prefs/AppPreferences.kt index 1203828..7973363 100644 --- a/app/src/main/java/pm/antani/resentin/data/prefs/AppPreferences.kt +++ b/app/src/main/java/pm/antani/resentin/data/prefs/AppPreferences.kt @@ -92,6 +92,7 @@ class AppPreferences(private val context: Context) { private val keyLineSpacing = stringPreferencesKey("line_spacing") private val keyLineHeightScale = floatPreferencesKey("line_height_scale") private val keyDismissedUpdateVersion = stringPreferencesKey("dismissed_update_version") + private val keyDynamicColor = booleanPreferencesKey("dynamic_color") val pinnedChannels: Flow> = context.dataStore.data.map { it[keyPinnedChannels] ?: emptySet() } @@ -349,4 +350,13 @@ class AppPreferences(private val context: Context) { if (epochMillis != null) it[keyPushDecryptionFailureAt] = epochMillis else it.remove(keyPushDecryptionFailureAt) } } + + /** Material You dynamic color (Android 12+): system palette derived from + * the wallpaper instead of the hand-tuned Resentin palette. Off by + * default to preserve the app's visual identity. */ + val dynamicColor: Flow = context.dataStore.data.map { it[keyDynamicColor] ?: false } + + suspend fun setDynamicColor(value: Boolean) { + context.dataStore.edit { it[keyDynamicColor] = value } + } } diff --git a/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsScreen.kt b/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsScreen.kt index 43dab14..3c360ae 100644 --- a/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsScreen.kt +++ b/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsScreen.kt @@ -190,6 +190,7 @@ fun AppSettingsScreen(viewModel: AppSettingsViewModel, onBack: () -> Unit, onAdm val unreadFirst by viewModel.unreadFirst.collectAsState() val fontScale by viewModel.fontScale.collectAsState() val themeMode by viewModel.themeMode.collectAsState() + val dynamicColor by viewModel.dynamicColor.collectAsState() val fontFamily by viewModel.fontFamily.collectAsState() val chatFontFamily by viewModel.chatFontFamily.collectAsState() val fontFamilyOptions = appFontFamilyOptions() @@ -398,6 +399,17 @@ fun AppSettingsScreen(viewModel: AppSettingsViewModel, onBack: () -> Unit, onAdm ), onSelected = viewModel::setThemeMode, ) + // Material You esiste solo da Android 12 (API 31): sotto, + // la voce non viene mostrata proprio. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + SettingsRowDivider() + SettingsSwitchRow( + title = stringResource(R.string.settings_dynamic_color), + description = stringResource(R.string.settings_dynamic_color_desc), + checked = dynamicColor, + onCheckedChange = viewModel::setDynamicColor, + ) + } SettingsRowDivider() SettingsBlockLabel( text = stringResource(R.string.settings_language), diff --git a/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsViewModel.kt b/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsViewModel.kt index 4d8b80c..f92385f 100644 --- a/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsViewModel.kt +++ b/app/src/main/java/pm/antani/resentin/ui/appsettings/AppSettingsViewModel.kt @@ -188,6 +188,13 @@ class AppSettingsViewModel( viewModelScope.launch { appPreferences.setReplyStyle(style) } } + val dynamicColor: StateFlow = appPreferences.dynamicColor + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), false) + + fun setDynamicColor(enabled: Boolean) { + viewModelScope.launch { appPreferences.setDynamicColor(enabled) } + } + fun onReplyCustomTemplateChange(value: String) = _uiState.update { it.copy(replyCustomTemplate = value, replyCustomTemplateSaved = false) } diff --git a/app/src/main/java/pm/antani/resentin/ui/home/HomeScreen.kt b/app/src/main/java/pm/antani/resentin/ui/home/HomeScreen.kt index e19cfc8..006e1fc 100644 --- a/app/src/main/java/pm/antani/resentin/ui/home/HomeScreen.kt +++ b/app/src/main/java/pm/antani/resentin/ui/home/HomeScreen.kt @@ -187,7 +187,7 @@ fun HomeScreen( Surface( modifier = Modifier.size(40.dp), shape = MaterialTheme.shapes.extraSmall, - color = Color(0xFF4E342E), + color = MaterialTheme.colorScheme.primaryContainer, ) { androidx.compose.foundation.Image( painter = androidx.compose.ui.res.painterResource( diff --git a/app/src/main/java/pm/antani/resentin/ui/login/LoginScreen.kt b/app/src/main/java/pm/antani/resentin/ui/login/LoginScreen.kt index 267c1f8..19b7355 100644 --- a/app/src/main/java/pm/antani/resentin/ui/login/LoginScreen.kt +++ b/app/src/main/java/pm/antani/resentin/ui/login/LoginScreen.kt @@ -115,7 +115,7 @@ fun LoginScreen(viewModel: LoginViewModel) { Surface( modifier = Modifier.size(72.dp), shape = MaterialTheme.shapes.large, - color = androidx.compose.ui.graphics.Color(0xFF4E342E), + color = MaterialTheme.colorScheme.primaryContainer, ) { androidx.compose.foundation.Image( painter = androidx.compose.ui.res.painterResource( diff --git a/app/src/main/java/pm/antani/resentin/ui/theme/Theme.kt b/app/src/main/java/pm/antani/resentin/ui/theme/Theme.kt index 35ff49d..2c4c603 100644 --- a/app/src/main/java/pm/antani/resentin/ui/theme/Theme.kt +++ b/app/src/main/java/pm/antani/resentin/ui/theme/Theme.kt @@ -5,9 +5,12 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Shapes import androidx.compose.material3.Typography import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import pm.antani.resentin.data.prefs.AppFontFamily @@ -108,7 +111,14 @@ fun ResentinTheme( chatFontFamilyChoice: AppFontFamily = AppFontFamily.SYSTEM, content: @Composable () -> Unit, ) { + // Material You: palette generata dal sistema dai colori dello sfondo + // (Android 12+). Sotto API 31, o a toggle spento, resta la palette + // Resentin curata a mano. Forme, tipografia e scale non cambiano mai. val colorScheme = when { + dynamicColor && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } darkTheme -> DarkColorScheme else -> LightColorScheme } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 06bb5f0..7b9ee16 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -378,6 +378,8 @@ System Light Dark + Dynamic colors + Match your wallpaper colors (Material You, Android 12+) App font Applies across the app interface. Chat font diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 162f45b..88ea1fe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -384,6 +384,8 @@ Sistema Chiaro Scuro + Colori dinamici + Usa i colori dello sfondo del telefono (Material You, Android 12+) Font dell’app Si applica a tutta l’interfaccia. Font della chat