Splitting Light and Dark Theme setting

Soi you can stop complaining now
This commit is contained in:
Jays2Kings 2021-07-03 03:28:24 -04:00
parent 49e0d561b2
commit bed52c7b86
5 changed files with 139 additions and 59 deletions

View File

@ -19,7 +19,8 @@ class SettingsGeneralController : SettingsController() {
private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER
var lastThemeX: Int? = null var lastThemeXLight: Int? = null
var lastThemeXDark: Int? = null
var themePreference: ThemePreference? = null var themePreference: ThemePreference? = null
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
titleRes = R.string.general titleRes = R.string.general
@ -90,12 +91,13 @@ class SettingsGeneralController : SettingsController() {
} }
preferenceCategory { preferenceCategory {
titleRes = R.string.display titleRes = R.string.app_theme
themePreference = themePreference { themePreference = themePreference {
key = "theme_preference" key = "theme_preference"
titleRes = R.string.app_theme titleRes = R.string.app_theme
lastScrollPostion = lastThemeX lastScrollPostionLight = lastThemeXLight
lastScrollPostionDark = lastThemeXDark
summary = if (preferences.nightMode() summary = if (preferences.nightMode()
.get() == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM .get() == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
) { ) {
@ -124,7 +126,8 @@ class SettingsGeneralController : SettingsController() {
activity?.recreate() activity?.recreate()
} else { } else {
preferences.nightMode().set(context.appDelegateNightMode()) preferences.nightMode().set(context.appDelegateNightMode())
themePreference?.fastAdapter?.notifyDataSetChanged() themePreference?.fastAdapterLight?.notifyDataSetChanged()
themePreference?.fastAdapterDark?.notifyDataSetChanged()
} }
true true
} }
@ -270,13 +273,16 @@ class SettingsGeneralController : SettingsController() {
} }
override fun onSaveViewState(view: View, outState: Bundle) { override fun onSaveViewState(view: View, outState: Bundle) {
outState.putInt(::lastThemeX.name, themePreference?.lastScrollPostion ?: 0) outState.putInt(::lastThemeXLight.name, themePreference?.lastScrollPostionLight ?: 0)
outState.putInt(::lastThemeXDark.name, themePreference?.lastScrollPostionDark ?: 0)
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
} }
override fun onRestoreViewState(view: View, savedViewState: Bundle) { override fun onRestoreViewState(view: View, savedViewState: Bundle) {
super.onRestoreViewState(view, savedViewState) super.onRestoreViewState(view, savedViewState)
lastThemeX = savedViewState.getInt(::lastThemeX.name) lastThemeXLight = savedViewState.getInt(::lastThemeXLight.name)
themePreference?.lastScrollPostion = lastThemeX lastThemeXDark = savedViewState.getInt(::lastThemeXDark.name)
themePreference?.lastScrollPostionLight = lastThemeXLight
themePreference?.lastScrollPostionDark = lastThemeXDark
} }
} }

View File

@ -27,88 +27,128 @@ import eu.kanade.tachiyomi.util.system.appDelegateNightMode
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.isInNightMode import eu.kanade.tachiyomi.util.system.isInNightMode
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.math.max
class ThemePreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : class ThemePreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Preference(context, attrs) { Preference(context, attrs) {
var fastAdapter: FastAdapter<ThemeItem> var fastAdapterLight: FastAdapter<ThemeItem>
private val itemAdapter = ItemAdapter<ThemeItem>() var fastAdapterDark: FastAdapter<ThemeItem>
private var selectExtension: SelectExtension<ThemeItem> private val itemAdapterLight = ItemAdapter<ThemeItem>()
private val itemAdapterDark = ItemAdapter<ThemeItem>()
private var selectExtensionLight: SelectExtension<ThemeItem>
private var selectExtensionDark: SelectExtension<ThemeItem>
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
var activity: Activity? = null var activity: Activity? = null
var lastScrollPostion: Int? = null var lastScrollPostionLight: Int? = null
var lastScrollPostionDark: Int? = null
lateinit var binding: ThemesPreferenceBinding lateinit var binding: ThemesPreferenceBinding
val manager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) private val managerLight = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
private val managerDark = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
init { init {
layoutResource = R.layout.themes_preference layoutResource = R.layout.themes_preference
fastAdapter = FastAdapter.with(itemAdapter) fastAdapterLight = FastAdapter.with(itemAdapterLight)
fastAdapter.setHasStableIds(true) fastAdapterDark = FastAdapter.with(itemAdapterDark)
selectExtension = fastAdapter.getSelectExtension().apply { fastAdapterLight.setHasStableIds(true)
isSelectable = true fastAdapterDark.setHasStableIds(true)
multiSelect = true selectExtensionLight = fastAdapterLight.getSelectExtension().setThemeListener()
selectionListener = object : ISelectionListener<ThemeItem> { selectExtensionDark = fastAdapterDark.getSelectExtension().setThemeListener()
override fun onSelectionChanged(item: ThemeItem, selected: Boolean) { val enumConstants = Themes.values()
if (item.theme.nightMode == AppCompatDelegate.MODE_NIGHT_YES) { itemAdapterLight.set(enumConstants.filter { it.nightMode == AppCompatDelegate.MODE_NIGHT_NO }.map(::ThemeItem))
preferences.darkTheme().set(item.theme) itemAdapterDark.set(enumConstants.filter { it.nightMode == AppCompatDelegate.MODE_NIGHT_YES }.map(::ThemeItem))
} else { isSelectable = false
preferences.lightTheme().set(item.theme) }
}
if (!selected) { private fun SelectExtension<ThemeItem>.setThemeListener(): SelectExtension<ThemeItem> {
preferences.nightMode().set(item.theme.nightMode) isSelectable = true
} else if (preferences.nightMode() multiSelect = true
.get() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM selectionListener = object : ISelectionListener<ThemeItem> {
) { override fun onSelectionChanged(item: ThemeItem, selected: Boolean) {
preferences.nightMode().set(item.theme.nightMode) if (item.theme.nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
} preferences.darkTheme().set(item.theme)
if (( } else {
preferences.nightMode().get() == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && preferences.lightTheme().set(item.theme)
item.theme.nightMode != context.appDelegateNightMode() }
) || if (!selected) {
(!selected && item.theme.nightMode == context.appDelegateNightMode()) preferences.nightMode().set(item.theme.nightMode)
) { } else if (preferences.nightMode()
fastAdapter.notifyDataSetChanged() .get() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
} else { ) {
activity?.recreate() preferences.nightMode().set(item.theme.nightMode)
} }
if ((
preferences.nightMode().get() == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM &&
item.theme.nightMode != context.appDelegateNightMode()
) ||
(!selected && item.theme.nightMode == context.appDelegateNightMode())
) {
fastAdapterLight.notifyDataSetChanged()
fastAdapterDark.notifyDataSetChanged()
} else {
activity?.recreate()
} }
} }
} }
return this
val enumConstants = Themes.values()
itemAdapter.set(enumConstants.map(::ThemeItem))
isSelectable = false
} }
override fun onBindViewHolder(holder: PreferenceViewHolder) { override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
binding = ThemesPreferenceBinding.bind(holder.itemView) binding = ThemesPreferenceBinding.bind(holder.itemView)
binding.themePrefTitle.text = title
binding.themeRecycler.setHasFixedSize(true) binding.themeRecycler.setHasFixedSize(true)
binding.themeRecycler.layoutManager = manager binding.themeRecycler.layoutManager = managerLight
binding.themeRecycler.adapter = fastAdapter binding.themeRecycler.adapter = fastAdapterLight
binding.themeRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.themeRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
lastScrollPostion = lastScrollPostionLight =
recyclerView.computeHorizontalScrollOffset() recyclerView.computeHorizontalScrollOffset()
} }
}) })
if (lastScrollPostion != null) { binding.themeRecyclerDark.setHasFixedSize(true)
val lX = lastScrollPostion!! binding.themeRecyclerDark.layoutManager = managerDark
binding.themeRecyclerDark.adapter = fastAdapterDark
binding.themeRecyclerDark.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
lastScrollPostionDark =
recyclerView.computeHorizontalScrollOffset()
}
})
if (lastScrollPostionLight != null) {
val lX = lastScrollPostionLight!!
(binding.themeRecycler.layoutManager as LinearLayoutManager).apply { (binding.themeRecycler.layoutManager as LinearLayoutManager).apply {
scrollToPositionWithOffset( scrollToPositionWithOffset(
lX / 110.dpToPx, lX / 110.dpToPx,
-lX % 110.dpToPx -lX % 110.dpToPx
) )
} }
lastScrollPostion = binding.themeRecycler.computeHorizontalScrollOffset() lastScrollPostionLight = binding.themeRecycler.computeHorizontalScrollOffset()
} else { } else {
binding.themeRecycler.scrollToPosition( binding.themeRecycler.scrollToPosition(
selectExtension.selections.firstOrNull() ?: 0 max((selectExtensionLight.selections.firstOrNull() ?: 0) - 1, 0)
)
}
if (lastScrollPostionDark != null) {
val lX = lastScrollPostionDark!!
(binding.themeRecyclerDark.layoutManager as LinearLayoutManager).apply {
scrollToPositionWithOffset(
lX / 110.dpToPx,
-lX % 110.dpToPx
)
}
lastScrollPostionDark = binding.themeRecyclerDark.computeHorizontalScrollOffset()
} else {
binding.themeRecyclerDark.scrollToPosition(
max((selectExtensionDark.selections.firstOrNull() ?: 0) - 1, 0)
) )
} }
} }

View File

@ -49,7 +49,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/theme_app_bar_preview" android:layout_height="@dimen/theme_app_bar_preview"
android:background="?attr/colorSecondary" android:background="?attr/colorSecondary"
android:elevation="2dp" android:elevation="1dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">

View File

@ -5,18 +5,18 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/theme_pref_title" android:id="@+id/light_theme"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/theme_recycler" app:layout_constraintBottom_toTopOf="@id/theme_recycler"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
android:textAppearance="@style/TextAppearance.AppCompat.Menu" android:textAppearance="@style/TextAppearance.AppCompat.Menu"
android:text="@string/app_theme"/> android:text="@string/light_theme"/>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/theme_recycler" android:id="@+id/theme_recycler"
@ -26,10 +26,42 @@
android:paddingStart="4dp" android:paddingStart="4dp"
android:paddingEnd="0dp" android:paddingEnd="0dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/theme_pref_title" app:layout_constraintTop_toBottomOf="@id/light_theme"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/dark_theme"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
tools:itemCount="2" tools:itemCount="2"
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:orientation="horizontal"
android:clipToPadding="false"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/dark_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/theme_recycler"
app:layout_constraintBottom_toTopOf="@id/theme_recycler_dark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textAppearance="@style/TextAppearance.AppCompat.Menu"
android:text="@string/dark_theme"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/theme_recycler_dark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/theme_item"
android:paddingStart="4dp"
android:paddingEnd="0dp"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/dark_theme"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:orientation="horizontal"
tools:itemCount="2"
android:clipToPadding="false"/> android:clipToPadding="false"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -602,6 +602,8 @@
<!-- General settings --> <!-- General settings -->
<string name="app_theme">App theme</string> <string name="app_theme">App theme</string>
<string name="light_theme">Light theme</string>
<string name="dark_theme">Dark theme</string>
<string name="light_blue">Light Blue</string> <string name="light_blue">Light Blue</string>
<string name="dark">Dark</string> <string name="dark">Dark</string>
<string name="amoled_black">AMOLED Black</string> <string name="amoled_black">AMOLED Black</string>