diff --git a/app/src/main/java/moe/apex/breadboard/preferences/Pref.kt b/app/src/main/java/moe/apex/breadboard/preferences/Pref.kt index c65ca444..3f0efb3d 100644 --- a/app/src/main/java/moe/apex/breadboard/preferences/Pref.kt +++ b/app/src/main/java/moe/apex/breadboard/preferences/Pref.kt @@ -97,6 +97,7 @@ data object PrefNames { const val INTERNAL_IGNORE_LIST = "internal_ignore_list" const val AUTOPLAY_VIDEOS = "autoplay_videos" const val UNIFIED_INFO_SHEET = "unified_info_sheet" + const val DARK_THEME = "dark_theme" } @@ -131,6 +132,7 @@ object PreferenceKeys { val INTERNAL_IGNORE_LIST = stringSetPreferencesKey(PrefNames.INTERNAL_IGNORE_LIST) val AUTOPLAY_VIDEOS = stringPreferencesKey(PrefNames.AUTOPLAY_VIDEOS) val UNIFIED_INFO_SHEET = booleanPreferencesKey(PrefNames.UNIFIED_INFO_SHEET) + var DARK_THEME = stringPreferencesKey(PrefNames.DARK_THEME) } @@ -228,7 +230,8 @@ data class Prefs( val internalIgnoreListTimestamp: Long, val internalIgnoreList: Set, val autoplayVideos: AutoplayVideosMode, - val unifiedInfoSheet: Boolean + val unifiedInfoSheet: Boolean, + val darkTheme: DarkTheme, ) { companion object { val DEFAULT = Prefs( @@ -262,6 +265,7 @@ data class Prefs( internalIgnoreList = emptySet(), autoplayVideos = AutoplayVideosMode.OFF, unifiedInfoSheet = false, // Unified is called 'Classic' in the UI + darkTheme = DarkTheme.AUTO ) } @@ -325,7 +329,8 @@ class UserPreferencesRepository(private val dataStore: DataStore) { PreferenceKeys.RECOMMENDATIONS_WEIGHTED_SELECTION to PrefMeta(PrefCategory.SETTING), PreferenceKeys.INTERNAL_IGNORE_LIST_TIMESTAMP to PrefMeta(PrefCategory.SETTING, exportable = false), PreferenceKeys.INTERNAL_IGNORE_LIST to PrefMeta(PrefCategory.SETTING, exportable = false), - PreferenceKeys.UNIFIED_INFO_SHEET to PrefMeta(PrefCategory.SETTING) + PreferenceKeys.UNIFIED_INFO_SHEET to PrefMeta(PrefCategory.SETTING), + PreferenceKeys.DARK_THEME to PrefMeta(PrefCategory.SETTING) ) } @@ -809,6 +814,8 @@ class UserPreferencesRepository(private val dataStore: DataStore) { val autoplayVideos = preferences[PreferenceKeys.AUTOPLAY_VIDEOS]?.let { AutoplayVideosMode.valueOf(it) } ?: Prefs.DEFAULT.autoplayVideos val unifiedInfoSheet = preferences[PreferenceKeys.UNIFIED_INFO_SHEET] ?: Prefs.DEFAULT.unifiedInfoSheet + val darkTheme = preferences[PreferenceKeys.DARK_THEME]?.let { DarkTheme.valueOf(it) } ?: Prefs.DEFAULT.darkTheme + return Prefs( dataSaver, storageLocation, @@ -839,7 +846,8 @@ class UserPreferencesRepository(private val dataStore: DataStore) { internalIgnoreListTimestamp, internalIgnoreList, autoplayVideos, - unifiedInfoSheet + unifiedInfoSheet, + darkTheme, ) } } @@ -854,3 +862,9 @@ enum class ImageSource(override val label: String, val imageBoard: ImageBoard) : YANDERE("Yande.re", Yandere), R34("Rule34", Rule34) } + +enum class DarkTheme(override val label: String) : PrefEnum { + ON("Always"), + OFF("Never"), + AUTO("Follow system") +} \ No newline at end of file diff --git a/app/src/main/java/moe/apex/breadboard/preferences/Preferences.kt b/app/src/main/java/moe/apex/breadboard/preferences/Preferences.kt index a2e54d8d..c4891fbe 100644 --- a/app/src/main/java/moe/apex/breadboard/preferences/Preferences.kt +++ b/app/src/main/java/moe/apex/breadboard/preferences/Preferences.kt @@ -365,6 +365,27 @@ fun PreferencesScreen(navController: NavHostController) { } } } + + item { + ExpressiveGroup(title = "Appearance") { + item { + EnumPref( + title = "Dark theme", + summary = currentSettings.darkTheme.label, + enumItems = DarkTheme.entries, + selectedItem = currentSettings.darkTheme, + onSelection = { + scope.launch { + preferencesRepository.updatePref( + PreferenceKeys.DARK_THEME, + it + ) + } + } + ) + } + } + } item { ExpressiveGroup(title = "Content") { diff --git a/app/src/main/java/moe/apex/breadboard/ui/theme/Theme.kt b/app/src/main/java/moe/apex/breadboard/ui/theme/Theme.kt index b63b8418..544f292e 100644 --- a/app/src/main/java/moe/apex/breadboard/ui/theme/Theme.kt +++ b/app/src/main/java/moe/apex/breadboard/ui/theme/Theme.kt @@ -14,6 +14,8 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import moe.apex.breadboard.preferences.LocalPreferences +import moe.apex.breadboard.preferences.DarkTheme private val DarkColorScheme = darkColorScheme( @@ -53,11 +55,20 @@ val LocalBreadboardColors = staticCompositionLocalOf { ) } +@Composable +fun shouldUseDarkTheme(): Boolean { + val preferences = LocalPreferences.current + + val userSelectedDarkMode = preferences.darkTheme == DarkTheme.ON + val followSystemDarkMode = preferences.darkTheme == DarkTheme.AUTO && isSystemInDarkTheme() + + return userSelectedDarkMode || followSystemDarkMode +} @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun BreadboardTheme( - darkTheme: Boolean = isSystemInDarkTheme(), + darkTheme: Boolean = shouldUseDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, content: @Composable () -> Unit