@@ -5,13 +5,18 @@ import androidx.compose.foundation.layout.Column
55import androidx.compose.runtime.Composable
66import androidx.compose.runtime.ReadOnlyComposable
77import androidx.compose.runtime.getValue
8+ import androidx.compose.runtime.mutableIntStateOf
9+ import androidx.compose.runtime.mutableStateOf
810import androidx.compose.runtime.remember
11+ import androidx.compose.runtime.saveable.rememberSaveable
12+ import androidx.compose.runtime.setValue
913import androidx.compose.ui.platform.LocalContext
1014import androidx.core.app.ActivityCompat
1115import androidx.lifecycle.compose.collectAsStateWithLifecycle
1216import cafe.adriel.voyager.navigator.LocalNavigator
1317import cafe.adriel.voyager.navigator.currentOrThrow
1418import eu.kanade.domain.ui.UiPreferences
19+ import eu.kanade.domain.ui.model.AppTheme
1520import eu.kanade.domain.ui.model.NavStyle
1621import eu.kanade.domain.ui.model.StartScreen
1722import eu.kanade.domain.ui.model.TabletUiMode
@@ -21,6 +26,9 @@ import eu.kanade.presentation.more.settings.Preference
2126import eu.kanade.presentation.more.settings.screen.appearance.AppLanguageScreen
2227import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
2328import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
29+ import eu.kanade.presentation.more.settings.widget.CustomThemeAccentPreferenceWidget
30+ import eu.kanade.presentation.more.settings.widget.CustomThemeColorPickerDialog
31+ import eu.kanade.presentation.more.settings.widget.normalizeAccentSeed
2432import eu.kanade.tachiyomi.util.system.toast
2533import kotlinx.collections.immutable.persistentListOf
2634import kotlinx.collections.immutable.toImmutableMap
@@ -35,6 +43,8 @@ import java.time.LocalDate
3543
3644object SettingsAppearanceScreen : SearchableSettings {
3745
46+ internal const val DEFAULT_CUSTOM_ACCENT_PICKER_SEED = 0xFF1E88E5 .toInt()
47+
3848 @ReadOnlyComposable
3949 @Composable
4050 override fun getTitleRes () = MR .strings.pref_category_appearance
@@ -61,9 +71,20 @@ object SettingsAppearanceScreen : SearchableSettings {
6171 val appThemePref = uiPreferences.appTheme()
6272 val appTheme by appThemePref.collectAsStateWithLifecycle()
6373
74+ val customThemeAccentSeedPref = uiPreferences.customThemeAccentSeed()
75+ val customThemeAccentSeed by customThemeAccentSeedPref.collectAsStateWithLifecycle()
76+
6477 val amoledPref = uiPreferences.themeDarkAmoled()
6578 val amoled by amoledPref.collectAsStateWithLifecycle()
6679
80+ var showCustomAccentPicker by rememberSaveable { mutableStateOf(false ) }
81+ var customAccentPickerSeed by rememberSaveable { mutableIntStateOf(DEFAULT_CUSTOM_ACCENT_PICKER_SEED ) }
82+ var customAccentPickerSession by rememberSaveable { mutableIntStateOf(0 ) }
83+
84+ fun recreateForThemeChange () {
85+ (context as ? Activity )?.let { ActivityCompat .recreate(it) }
86+ }
87+
6788 return Preference .PreferenceGroup (
6889 title = stringResource(MR .strings.pref_category_theme),
6990 preferenceItems = persistentListOf(
@@ -84,6 +105,37 @@ object SettingsAppearanceScreen : SearchableSettings {
84105 amoled = amoled,
85106 onItemClick = { appThemePref.set(it) },
86107 )
108+
109+ if (appTheme == AppTheme .CUSTOM ) {
110+ CustomThemeAccentPreferenceWidget (
111+ selectedAccentSeed = customThemeAccentSeed,
112+ onSwatchClick = { selectedSeed ->
113+ customThemeAccentSeedPref.set(normalizeAccentSeed(selectedSeed))
114+ recreateForThemeChange()
115+ },
116+ onOpenPicker = {
117+ customAccentPickerSeed = resolveInitialCustomAccentPickerSeed(customThemeAccentSeed)
118+ customAccentPickerSession = nextCustomAccentPickerSession(customAccentPickerSession)
119+ showCustomAccentPicker = true
120+ },
121+ onReset = {
122+ customThemeAccentSeedPref.set(UiPreferences .CUSTOM_THEME_ACCENT_SEED_UNSET )
123+ recreateForThemeChange()
124+ },
125+ )
126+ }
127+
128+ if (showCustomAccentPicker) {
129+ CustomThemeColorPickerDialog (
130+ sessionKey = customAccentPickerSession,
131+ initialSeed = customAccentPickerSeed,
132+ onDismiss = { showCustomAccentPicker = false },
133+ onApply = { pickedSeed ->
134+ customThemeAccentSeedPref.set(normalizeAccentSeed(pickedSeed))
135+ recreateForThemeChange()
136+ },
137+ )
138+ }
87139 }
88140 },
89141 Preference .PreferenceItem .SwitchPreference (
@@ -179,6 +231,16 @@ object SettingsAppearanceScreen : SearchableSettings {
179231 }
180232}
181233
234+ internal fun resolveInitialCustomAccentPickerSeed (currentAccentSeed : Int ): Int {
235+ return if (currentAccentSeed == UiPreferences .CUSTOM_THEME_ACCENT_SEED_UNSET ) {
236+ SettingsAppearanceScreen .DEFAULT_CUSTOM_ACCENT_PICKER_SEED
237+ } else {
238+ normalizeAccentSeed(currentAccentSeed)
239+ }
240+ }
241+
242+ internal fun nextCustomAccentPickerSession (currentSession : Int ): Int = currentSession + 1
243+
182244private val DateFormats = listOf (
183245 " " , // Default
184246 " MM/dd/yy" ,
0 commit comments