Skip to content

Commit

Permalink
Separates theme choosing from night mode
Browse files Browse the repository at this point in the history
Enables choosing the night mode (light/drak/system) with dynamic colors enabled.
  • Loading branch information
meikpiep committed Jan 26, 2025
1 parent bf39e7e commit 97af7cf
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ class MainApplication : Application() {
logger.info { "Starting application Gauguin..." }

val applicationPreferences = ApplicationPreferencesImpl(this)
applicationPreferences.migrateThemeToNightModeIfNecessary()

val options =
DynamicColorsOptions.Builder()
DynamicColorsOptions
.Builder()
.setThemeOverlay(R.style.AppTheme_Overlay)
.setPrecondition(DynamicColorsPrecondition())
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import org.koin.core.component.KoinComponent
import org.piepmeyer.gauguin.NightMode
import org.piepmeyer.gauguin.R
import org.piepmeyer.gauguin.Theme
import org.piepmeyer.gauguin.options.DifficultySetting
Expand All @@ -23,23 +24,74 @@ class ApplicationPreferencesImpl(
preferences.edit { clear() }
}

override fun migrateThemeToNightModeIfNecessary() {
if (!preferences.getString("nightMode", null).isNullOrEmpty()) {
return
}

val oldThemeValue = preferences.getString("theme", null)
/*
* Possible values:
* LIGHT
* DARK
* SYSTEM_DEFAULT
* DYNAMIC_COLORS
*/

val (newThemeValue, newNightModeValue) = migrateToNewThemeNightModesValues(oldThemeValue)

theme = newThemeValue
nightMode = newNightModeValue
}

fun migrateToNewThemeNightModesValues(oldThemeValue: String?): Pair<Theme, NightMode> {
val newThemeValue = if (oldThemeValue == "DYNAMIC_COLORS") Theme.DYNAMIC_COLORS else Theme.GAUGUIN

val newNightModeValue =
when (oldThemeValue) {
"LIGHT", "DYNAMIC_COLORS" -> NightMode.LIGHT
"DARK" -> NightMode.DARK
"SYSTEM_DEFAULT" -> NightMode.SYSTEM_DEFAULT
else -> NightMode.DARK
}

return Pair(newThemeValue, newNightModeValue)
}

override var theme: Theme
get() {
val themePref = preferences.getString("theme", null)
return themePref?.let {
try {
enumValueOf<Theme>(it)
} catch (_: IllegalArgumentException) {
return Theme.DARK
return Theme.GAUGUIN
}
} ?: Theme.DARK
} ?: Theme.GAUGUIN
}
set(value) {
preferences.edit {
putString("theme", value.name)
}
}

override var nightMode: NightMode
get() {
val nightModePref = preferences.getString("nightMode", null)
return nightModePref?.let {
try {
enumValueOf<NightMode>(it)
} catch (_: IllegalArgumentException) {
return NightMode.DARK
}
} ?: NightMode.DARK
}
set(value) {
preferences.edit {
putString("nightMode", value.name)
}
}

override fun maximumCellSizeInDP(): Int = preferences.getInt("maximumCellSize", 72)

override var gridTakesRemainingSpaceIfNecessary: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDelegate
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.piepmeyer.gauguin.NightMode
import org.piepmeyer.gauguin.R
import org.piepmeyer.gauguin.Theme
import org.piepmeyer.gauguin.preferences.ApplicationPreferences
Expand All @@ -31,17 +32,30 @@ class ActivityUtils : KoinComponent {

fun configureTheme(activity: Activity) {
when (applicationPreferences.theme) {
Theme.LIGHT -> {
Theme.GAUGUIN -> {
activity.setTheme(R.style.AppTheme)
}
Theme.DYNAMIC_COLORS -> {
activity.setTheme(com.google.android.material.R.style.Theme_Material3_DynamicColors_DayNight_NoActionBar)
}
}

when (applicationPreferences.nightMode) {
NightMode.LIGHT -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
Theme.DARK -> {
activity.setTheme(R.style.AppTheme)
NightMode.DARK -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
Theme.SYSTEM_DEFAULT, Theme.DYNAMIC_COLORS -> {
NightMode.SYSTEM_DEFAULT -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}

fun reconfigureTheme(activity: Activity) {
configureTheme(activity)

activity.recreate()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ class FerrisWheelConfigurer(
)
ferrisWheel.cabinColors =
when (applicationPreferences.theme) {
Theme.DARK -> cabinColorsDark()
Theme.LIGHT -> cabinColorsLight()
Theme.DYNAMIC_COLORS -> cabinColorsDynamic()
Theme.SYSTEM_DEFAULT -> {
else -> {
when (isNightMode()) {
true -> cabinColorsDark()
false -> cabinColorsLight()
true -> cabinColorsGauguinDark()
false -> cabinColorsGauguinLight()
}
}
}
Expand All @@ -55,14 +53,14 @@ class FerrisWheelConfigurer(
return (mode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
}

private fun cabinColorsDark(): List<CabinStyle> =
private fun cabinColorsGauguinDark(): List<CabinStyle> =
listOf(
cabin(com.google.android.material.R.attr.colorPrimaryVariant),
cabin(com.google.android.material.R.attr.colorSecondaryVariant),
cabin(R.attr.colorGridSelected),
)

private fun cabinColorsLight(): List<CabinStyle> =
private fun cabinColorsGauguinLight(): List<CabinStyle> =
listOf(
cabin(com.google.android.material.R.attr.colorSecondaryVariant),
cabin(R.attr.colorMainTopPanelBackground),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ThemeChooserBalloon(
setWidth(BalloonSizeSpec.WRAP)
setHeight(BalloonSizeSpec.WRAP)
setBackgroundColor(
MaterialColors.getColor(baseView, com.google.android.material.R.attr.colorSurface),
MaterialColors.getColor(baseView, com.google.android.material.R.attr.colorSurfaceVariant),
)
setArrowPositionRules(ArrowPositionRules.ALIGN_ANCHOR)
setArrowSize(10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.piepmeyer.gauguin.NightMode
import org.piepmeyer.gauguin.R
import org.piepmeyer.gauguin.Theme
import org.piepmeyer.gauguin.databinding.FragmentThemeChooserBinding
Expand All @@ -35,50 +36,71 @@ class ThemeChooserFragment(
): View {
binding = FragmentThemeChooserBinding.inflate(inflater, parent, false)

binding.navigationDrawerThemeLight.isChecked = preferences.theme == Theme.LIGHT
binding.navigationDrawerThemeLight.setOnClickListener {
themeHasBeenAltered = true
preferences.theme = Theme.LIGHT
activityUtils.configureTheme(mainActivity)
binding.nightModeLight.isChecked = preferences.nightMode == NightMode.LIGHT
binding.nightModeLight.setOnClickListener {
configureNightMode(NightMode.LIGHT)
}

binding.navigationDrawerThemeDark.isChecked = preferences.theme == Theme.DARK
binding.navigationDrawerThemeDark.setOnClickListener {
themeHasBeenAltered = true
preferences.theme = Theme.DARK
activityUtils.configureTheme(mainActivity)
binding.nightModeDark.isChecked = preferences.nightMode == NightMode.DARK
binding.nightModeDark.setOnClickListener {
configureNightMode(NightMode.DARK)
}

binding.navigationDrawerThemeAuto.isChecked = preferences.theme == Theme.SYSTEM_DEFAULT
binding.navigationDrawerThemeAuto.setOnClickListener {
themeHasBeenAltered = true
preferences.theme = Theme.SYSTEM_DEFAULT
activityUtils.configureTheme(mainActivity)
binding.nightModeSystemDefault.isChecked = preferences.nightMode == NightMode.SYSTEM_DEFAULT
binding.nightModeSystemDefault.setOnClickListener {
configureNightMode(NightMode.SYSTEM_DEFAULT)
}

binding.themeGauguin.isChecked = preferences.theme == Theme.GAUGUIN
binding.themeGauguin.setOnClickListener {
configureTheme(Theme.GAUGUIN)
}

if (DynamicColors.isDynamicColorAvailable()) {
binding.navigationDrawerThemeDynamicColors.isChecked =
preferences.theme == Theme.DYNAMIC_COLORS
binding.navigationDrawerThemeDynamicColors.setOnClickListener {
themeHasBeenAltered = true
preferences.theme = Theme.DYNAMIC_COLORS
activityUtils.configureTheme(mainActivity)

val options =
DynamicColorsOptions
.Builder()
.setThemeOverlay(R.style.AppTheme_Overlay)
.setPrecondition(DynamicColorsPrecondition())
.build()

DynamicColors.applyToActivitiesIfAvailable(this.mainActivity.application, options)
binding.themeDynamicColors.isChecked = preferences.theme == Theme.DYNAMIC_COLORS
binding.themeDynamicColors.setOnClickListener {
configureTheme(Theme.DYNAMIC_COLORS)
}
} else {
binding.navigationDrawerThemeDynamicColors.visibility = View.GONE
binding.themeDynamicColors.visibility = View.GONE
}

return binding.root
}

private fun configureNightMode(nightMode: NightMode) {
if (preferences.nightMode == nightMode) {
return
}

preferences.nightMode = nightMode

applyThemeAndNightModeChanges()
}

private fun configureTheme(theme: Theme) {
if (preferences.theme == theme) {
return
}

preferences.theme = theme

applyThemeAndNightModeChanges()
}

private fun applyThemeAndNightModeChanges() {
themeHasBeenAltered = true
activityUtils.reconfigureTheme(mainActivity)

val options =
DynamicColorsOptions
.Builder()
.setThemeOverlay(R.style.AppTheme_Overlay)
.setPrecondition(DynamicColorsPrecondition())
.build()

DynamicColors.applyToActivitiesIfAvailable(this.mainActivity.application, options)
}

fun themeHasBeenAltered(): Boolean = themeHasBeenAltered
}
54 changes: 47 additions & 7 deletions gauguin-app/src/main/res/layout/fragment_theme_chooser.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,79 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">

<TextView
android:id="@+id/labelNightMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center_vertical"
style="@style/TextAppearance.Material3.LabelLarge"
android:text="@string/setting_night_mode_title"/>

<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggleButton"
android:id="@+id/toggleButtonNightMode"
android:layout_width="300dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/labelNightMode"
android:layout_margin="8dp"
app:singleSelection="true"
app:selectionRequired="true"
android:orientation="vertical"
>
<com.google.android.material.button.MaterialButton
android:id="@+id/navigation_drawer_theme_light"
android:id="@+id/nightModeLight"
style="@style/VerticalButtonGroupButton"
app:icon="@drawable/light_mode_24px"
android:text="@string/setting_theme_entry_light"
/>
<com.google.android.material.button.MaterialButton
android:id="@+id/navigation_drawer_theme_dark"
android:id="@+id/nightModeDark"
style="@style/VerticalButtonGroupButton"
app:icon="@drawable/dark_mode_24px"
android:text="@string/setting_theme_entry_dark"
/>
<com.google.android.material.button.MaterialButton
android:id="@+id/navigation_drawer_theme_auto"
android:id="@+id/nightModeSystemDefault"
style="@style/VerticalButtonGroupButton"
app:icon="@drawable/night_sight_auto_24px"
android:text="@string/setting_theme_entry_system"
/>
</com.google.android.material.button.MaterialButtonToggleGroup>

<TextView
android:id="@+id/labelTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toggleButtonNightMode"
android:layout_marginTop="16dp"
android:gravity="center_vertical"
style="@style/TextAppearance.Material3.LabelLarge"
android:text="@string/setting_theme_title"/>

<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggleButtonTheme"
android:layout_width="300dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/labelTheme"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="8dp"
app:singleSelection="true"
app:selectionRequired="true"
android:orientation="vertical"
>
<com.google.android.material.button.MaterialButton
android:id="@+id/themeGauguin"
style="@style/VerticalButtonGroupButton"
android:text="@string/setting_theme_entry_gauguin_own_theme"
/>
<com.google.android.material.button.MaterialButton
android:id="@+id/navigation_drawer_theme_dynamic_colors"
android:id="@+id/themeDynamicColors"
style="@style/VerticalButtonGroupButton"
android:text="@string/setting_theme_entry_dynamic_colors"
/>
Expand Down
2 changes: 2 additions & 0 deletions gauguin-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,12 @@
<string name="setting_remove_pencils_title">Auto-remove pencil marks</string>
<string name="setting_remove_pencils_summary">In the same row or column as a penned number</string>
<string name="setting_group_display_title">Display</string>
<string name="setting_night_mode_title">Night Mode</string>
<string name="setting_theme_title">Theme</string>
<string name="setting_theme_entry_light">Light</string>
<string name="setting_theme_entry_dark">Dark</string>
<string name="setting_theme_entry_system">System Default</string>
<string name="setting_theme_entry_gauguin_own_theme">Gauguin Theme</string>
<string name="setting_theme_entry_dynamic_colors">Dynamic Colors</string>
<string name="setting_pencil_at_start_title">Pencil marks at game start</string>
<string name="setting_pencil_at_start_summary_on">Begin with filled pencil marks</string>
Expand Down
Loading

0 comments on commit 97af7cf

Please sign in to comment.