Option to set Light/Dark Theme individually

Works "the exact same" as upstream, except ui and code is completely different

With this there's less theme items in the general settings

Also moved auto hide bottom nav to the first preference
This commit is contained in:
Jays2Kings 2021-04-10 14:33:24 -04:00
parent e0c77abe1c
commit 4ef4dc2677
14 changed files with 173 additions and 254 deletions

View File

@ -7,7 +7,9 @@ object PreferenceKeys {
const val theme = "pref_theme_key" const val theme = "pref_theme_key"
const val themeStyle = "theme_style" const val nightMode = "night_mode"
const val lightTheme = "light_theme"
const val darkTheme = "dark_theme"
const val startingTab = "starting_tab" const val startingTab = "starting_tab"

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Environment import android.os.Environment
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.f2prateek.rx.preferences.Preference import com.f2prateek.rx.preferences.Preference
import com.f2prateek.rx.preferences.RxSharedPreferences import com.f2prateek.rx.preferences.RxSharedPreferences
@ -88,7 +89,10 @@ class PreferencesHelper(val context: Context) {
fun oldTheme() = prefs.getInt(Keys.theme, 5) fun oldTheme() = prefs.getInt(Keys.theme, 5)
fun theme() = flowPrefs.getEnum(Keys.themeStyle, ThemeUtil.Themes.DEFAULT) fun nightMode() = flowPrefs.getInt(Keys.nightMode, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
fun lightTheme() = flowPrefs.getEnum(Keys.lightTheme, ThemeUtil.Themes.PURE_WHITE)
fun darkTheme() = flowPrefs.getEnum(Keys.darkTheme, ThemeUtil.Themes.DARK)
fun rotation() = flowPrefs.getInt(Keys.rotation, 1) fun rotation() = flowPrefs.getInt(Keys.rotation, 1)

View File

@ -2,14 +2,13 @@ package eu.kanade.tachiyomi.ui.base.activity
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.main.SearchActivity import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.security.BiometricActivity import eu.kanade.tachiyomi.ui.security.BiometricActivity
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.setThemeAndNight
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() { abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@ -23,18 +22,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
if (preferences.theme().isNotSet()) { setThemeAndNight(preferences)
ThemeUtil.convertTheme(preferences, preferences.oldTheme())
}
// Using a try catch in case I start to remove themes
val theme = try {
preferences.theme().get()
} catch (e: Exception) {
preferences.theme().set(ThemeUtil.Themes.DEFAULT)
ThemeUtil.Themes.DEFAULT
}
AppCompatDelegate.setDefaultNightMode(theme.nightMode)
setTheme(theme.styleRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
SecureActivityDelegate.setSecure(this) SecureActivityDelegate.setSecure(this)
} }

View File

@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.base.activity
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.setThemeAndNight
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
abstract class BaseThemedActivity : AppCompatActivity() { abstract class BaseThemedActivity : AppCompatActivity() {
@ -12,13 +11,7 @@ abstract class BaseThemedActivity : AppCompatActivity() {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
if (preferences.theme().isNotSet()) { setThemeAndNight(preferences)
ThemeUtil.convertTheme(preferences, preferences.oldTheme())
}
val theme = preferences.theme().get()
AppCompatDelegate.setDefaultNightMode(theme.nightMode)
setTheme(theme.styleRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
} }

View File

@ -87,6 +87,7 @@ import eu.kanade.tachiyomi.util.moveCategories
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.ThemeUtil
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getPrefTheme
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.isInNightMode import eu.kanade.tachiyomi.util.system.isInNightMode
import eu.kanade.tachiyomi.util.system.isOnline import eu.kanade.tachiyomi.util.system.isOnline
@ -361,7 +362,7 @@ class MangaDetailsController :
val activity = activity as? MainActivity ?: return val activity = activity as? MainActivity ?: return
val activityBinding = activityBinding ?: return val activityBinding = activityBinding ?: return
// if the theme is using inverted toolbar color // if the theme is using inverted toolbar color
if (ThemeUtil.hasDarkActionBarInLight(activity, presenter.preferences.theme().get())) { if (ThemeUtil.hasDarkActionBarInLight(activity, activity.getPrefTheme(presenter.preferences))) {
if (forThis) activityBinding.appBar.context.setTheme( if (forThis) activityBinding.appBar.context.setTheme(
R.style.ThemeOverlay_AppCompat_DayNight_ActionBar R.style.ThemeOverlay_AppCompat_DayNight_ActionBar
) )
@ -1414,7 +1415,7 @@ class MangaDetailsController :
if (!activity.isInNightMode()) { if (!activity.isInNightMode()) {
activityBinding?.appBar?.context?.setTheme( activityBinding?.appBar?.context?.setTheme(
presenter.preferences.theme().get().styleRes activity.getPrefTheme(presenter.preferences).styleRes
) )
val iconPrimary = currColor ?: Color.WHITE val iconPrimary = currColor ?: Color.WHITE

View File

@ -21,7 +21,6 @@ import android.view.WindowManager
import android.view.animation.Animation import android.view.animation.Animation
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.SeekBar import android.widget.SeekBar
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -59,6 +58,7 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.GLUtil import eu.kanade.tachiyomi.util.system.GLUtil
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.ThemeUtil
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getPrefTheme
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.hasSideNavBar import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.isBottomTappable import eu.kanade.tachiyomi.util.system.isBottomTappable
@ -67,6 +67,7 @@ import eu.kanade.tachiyomi.util.system.isTablet
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.setThemeAndNight
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.collapse import eu.kanade.tachiyomi.util.view.collapse
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
@ -198,9 +199,7 @@ class ReaderActivity :
* Called when the activity is created. Initializes the presenter and configuration. * Called when the activity is created. Initializes the presenter and configuration.
*/ */
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val theme = preferences.theme().get() setThemeAndNight(preferences)
AppCompatDelegate.setDefaultNightMode(theme.nightMode)
setTheme(theme.styleRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ReaderActivityBinding.inflate(layoutInflater) binding = ReaderActivityBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@ -244,7 +243,7 @@ class ReaderActivity :
} }
binding.chaptersSheet.chaptersBottomSheet.setup(this) binding.chaptersSheet.chaptersBottomSheet.setup(this)
if (ThemeUtil.isColoredTheme(preferences.theme().get())) { if (ThemeUtil.isColoredTheme(getPrefTheme(preferences))) {
binding.chaptersSheet.chapterRecycler.setBackgroundColor(getResourceColor(android.R.attr.colorBackground)) binding.chaptersSheet.chapterRecycler.setBackgroundColor(getResourceColor(android.R.attr.colorBackground))
} }
config = ReaderConfig() config = ReaderConfig()

View File

@ -2,15 +2,20 @@ package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.updater.UpdaterJob import eu.kanade.tachiyomi.data.updater.UpdaterJob
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.appDelegateNightMode
import eu.kanade.tachiyomi.util.system.getPrefTheme
import eu.kanade.tachiyomi.widget.preference.IntListMatPreference import eu.kanade.tachiyomi.widget.preference.IntListMatPreference
import kotlinx.coroutines.flow.launchIn
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
class SettingsGeneralController : SettingsController() { class SettingsGeneralController : SettingsController() {
@ -67,6 +72,13 @@ class SettingsGeneralController : SettingsController() {
defaultValue = true defaultValue = true
} }
switchPreference {
key = Keys.hideBottomNavOnScroll
titleRes = R.string.hide_bottom_nav
summaryRes = R.string.hides_on_scroll
defaultValue = true
}
switchPreference { switchPreference {
key = Keys.automaticUpdates key = Keys.automaticUpdates
titleRes = R.string.check_for_updates titleRes = R.string.check_for_updates
@ -92,18 +104,33 @@ class SettingsGeneralController : SettingsController() {
titleRes = R.string.display titleRes = R.string.display
themePreference = themePreference { themePreference = themePreference {
key = Keys.themeStyle key = "theme_preference"
titleRes = R.string.app_theme titleRes = R.string.app_theme
lastScrollPostion = lastThemeX lastScrollPostion = lastThemeX
summaryRes = preferences.theme().get().nameRes summaryRes = context.getPrefTheme(preferences).nameRes
activity = this@SettingsGeneralController.activity activity = this@SettingsGeneralController.activity
} }
switchPreference { switchPreference {
key = Keys.hideBottomNavOnScroll key = "night_mode_switch"
titleRes = R.string.hide_bottom_nav isPersistent = false
summaryRes = R.string.hides_on_scroll titleRes = R.string.follow_system_theme
defaultValue = true isChecked =
preferences.nightMode().get() == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
onChange {
if (it == true) {
preferences.nightMode().set(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
activity?.recreate()
} else {
preferences.nightMode().set(context.appDelegateNightMode())
themePreference?.fastAdapter?.notifyDataSetChanged()
}
true
}
preferences.nightMode().asImmediateFlow { mode ->
isChecked = mode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}.launchIn(viewScope)
} }
} }

View File

@ -22,16 +22,18 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.ThemeItemBinding import eu.kanade.tachiyomi.databinding.ThemeItemBinding
import eu.kanade.tachiyomi.databinding.ThemesPreferenceBinding import eu.kanade.tachiyomi.databinding.ThemesPreferenceBinding
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.ThemeUtil
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.view.visInvisIf import eu.kanade.tachiyomi.util.view.visInvisIf
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class ThemePreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : class ThemePreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Preference(context, attrs) { Preference(context, attrs) {
private lateinit var fastAdapter: FastAdapter<ThemeItem> var fastAdapter: FastAdapter<ThemeItem>
private val itemAdapter = ItemAdapter<ThemeItem>() private val itemAdapter = ItemAdapter<ThemeItem>()
private lateinit var selectExtension: SelectExtension<ThemeItem> private var selectExtension: 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 lastScrollPostion: Int? = null
@ -42,22 +44,41 @@ class ThemePreference @JvmOverloads constructor(context: Context, attrs: Attribu
fastAdapter = FastAdapter.with(itemAdapter) fastAdapter = FastAdapter.with(itemAdapter)
fastAdapter.setHasStableIds(true) fastAdapter.setHasStableIds(true)
val enumConstants = ThemeUtil.Themes::class.java.enumConstants val enumConstants = ThemeUtil.Themes::class.java.enumConstants
val currentTheme = preferences.theme().get() val currentLightTheme = preferences.lightTheme().get()
val currentDarkTheme = preferences.darkTheme().get()
val nightMode = preferences.nightMode().get()
selectExtension = fastAdapter.getSelectExtension().apply { selectExtension = fastAdapter.getSelectExtension().apply {
isSelectable = true isSelectable = true
multiSelect = false multiSelect = true
selectionListener = object : ISelectionListener<ThemeItem> { selectionListener = object : ISelectionListener<ThemeItem> {
override fun onSelectionChanged(item: ThemeItem, selected: Boolean) { override fun onSelectionChanged(item: ThemeItem, selected: Boolean) {
preferences.theme().set(item.theme) if (item.theme.nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
preferences.darkTheme().set(item.theme)
} else {
preferences.lightTheme().set(item.theme)
}
if (!selected) {
preferences.nightMode().set(item.theme.nightMode)
} else if (preferences.nightMode()
.get() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
) {
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())
) {
fastAdapter.notifyDataSetChanged()
} else {
activity?.recreate() activity?.recreate()
} }
} }
} }
}
itemAdapter.set(enumConstants?.map(::ThemeItem).orEmpty()) itemAdapter.set(enumConstants?.map(::ThemeItem).orEmpty())
itemAdapter.adapterItems.forEach { item ->
item.isSelected = currentTheme == item.theme
}
isSelectable = false isSelectable = false
} }
@ -75,24 +96,22 @@ class ThemePreference @JvmOverloads constructor(context: Context, attrs: Attribu
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 = lastScrollPostion =
recyclerView.computeHorizontalScrollOffset() // (lastScrollPostion ?: 0) + dx recyclerView.computeHorizontalScrollOffset()
} }
}) })
val enumConstants = ThemeUtil.Themes::class.java.enumConstants
val currentTheme = preferences.theme().get()
if (lastScrollPostion != null) { if (lastScrollPostion != null) {
val lX = lastScrollPostion!! val lX = lastScrollPostion!!
(binding.themeRecycler.layoutManager as LinearLayoutManager).apply { (binding.themeRecycler.layoutManager as LinearLayoutManager).apply {
scrollToPositionWithOffset( scrollToPositionWithOffset(
lX / 110.dpToPx, lX / 110.dpToPx,
-lX % 110.dpToPx + binding.themeRecycler.paddingStart -lX % 110.dpToPx
) )
} }
lastScrollPostion = binding.themeRecycler.computeHorizontalScrollOffset() lastScrollPostion = binding.themeRecycler.computeHorizontalScrollOffset()
} else { } else {
binding.themeRecycler.scrollToPosition( binding.themeRecycler.scrollToPosition(
enumConstants?.indexOf(currentTheme) ?: 0 selectExtension.selections.firstOrNull() ?: 0
) )
} }
} }
@ -112,11 +131,15 @@ class ThemePreference @JvmOverloads constructor(context: Context, attrs: Attribu
} }
val colors = theme.getColors() val colors = theme.getColors()
val darkColors = if (theme.nightMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
theme.getColors(AppCompatDelegate.MODE_NIGHT_YES) override var isSelected: Boolean
} else { get() = when (preferences.nightMode().get()) {
null AppCompatDelegate.MODE_NIGHT_YES -> preferences.darkTheme().get() == theme
AppCompatDelegate.MODE_NIGHT_NO -> preferences.lightTheme().get() == theme
else -> preferences.darkTheme().get() == theme ||
preferences.lightTheme().get() == theme
} }
set(value) {}
inner class ViewHolder(view: View) : FastAdapter.ViewHolder<ThemeItem>(view) { inner class ViewHolder(view: View) : FastAdapter.ViewHolder<ThemeItem>(view) {
@ -126,6 +149,16 @@ class ThemePreference @JvmOverloads constructor(context: Context, attrs: Attribu
binding.checkbox.isVisible = item.isSelected binding.checkbox.isVisible = item.isSelected
binding.themeSelected.visInvisIf(item.isSelected) binding.themeSelected.visInvisIf(item.isSelected)
if (binding.checkbox.isVisible) {
val themeMatchesApp = if (context.isInNightMode()) {
item.theme.nightMode == AppCompatDelegate.MODE_NIGHT_YES
} else {
item.theme.nightMode == AppCompatDelegate.MODE_NIGHT_NO
}
binding.themeSelected.alpha = if (themeMatchesApp) 1f else 0.5f
binding.checkbox.alpha = if (themeMatchesApp) 1f else 0.5f
}
binding.themeToolbar.setBackgroundColor(item.colors.appBar) binding.themeToolbar.setBackgroundColor(item.colors.appBar)
binding.themeAppBarText.imageTintList = ColorStateList.valueOf(item.colors.appBarText) binding.themeAppBarText.imageTintList = ColorStateList.valueOf(item.colors.appBarText)
binding.themeHeroImage.imageTintList = ColorStateList.valueOf(item.colors.primaryText) binding.themeHeroImage.imageTintList = ColorStateList.valueOf(item.colors.primaryText)
@ -138,23 +171,7 @@ class ThemePreference @JvmOverloads constructor(context: Context, attrs: Attribu
binding.themeItem1.imageTintList = ColorStateList.valueOf(item.colors.inactiveTab) binding.themeItem1.imageTintList = ColorStateList.valueOf(item.colors.inactiveTab)
binding.themeItem2.imageTintList = ColorStateList.valueOf(item.colors.activeTab) binding.themeItem2.imageTintList = ColorStateList.valueOf(item.colors.activeTab)
binding.themeItem3.imageTintList = ColorStateList.valueOf(item.colors.inactiveTab) binding.themeItem3.imageTintList = ColorStateList.valueOf(item.colors.inactiveTab)
binding.themeLayout.setBackgroundColor(item.colors.colorBackground) binding.themeLayout.setBackgroundColor(item.colors.colorBackground)
binding.darkThemeLayout.isVisible = item.darkColors != null
if (binding.darkThemeLayout.isVisible && item.darkColors != null) {
binding.darkThemeToolbar.setBackgroundColor(item.darkColors.appBar)
binding.darkThemeAppBarText.imageTintList = ColorStateList.valueOf(item.darkColors.appBarText)
binding.darkThemeLayout.setBackgroundColor(item.darkColors.colorBackground)
binding.darkThemePrimaryText.imageTintList = ColorStateList.valueOf(item.darkColors.primaryText)
binding.darkThemeHeroImage.imageTintList = ColorStateList.valueOf(item.darkColors.primaryText)
binding.darkThemeAccentedButton.imageTintList = ColorStateList.valueOf(item.darkColors.colorAccent)
binding.darkThemeSecondaryText.imageTintList = ColorStateList.valueOf(item.darkColors.secondaryText)
binding.darkThemeBottomBar.setBackgroundColor(item.darkColors.bottomBar)
binding.darkThemeItem2.imageTintList = ColorStateList.valueOf(item.darkColors.activeTab)
binding.darkThemeItem3.imageTintList = ColorStateList.valueOf(item.darkColors.inactiveTab)
}
} }
override fun unbindView(item: ThemeItem) { override fun unbindView(item: ThemeItem) {

View File

@ -32,7 +32,7 @@ open class BaseWebViewActivity : BaseActivity<WebviewActivityBinding>() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = WebviewActivityBinding.inflate(layoutInflater) binding = WebviewActivityBinding.inflate(layoutInflater)
delegate.localNightMode = preferences.theme().get().nightMode delegate.localNightMode = preferences.nightMode().get()
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)

View File

@ -24,6 +24,7 @@ import androidx.annotation.ColorInt
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatDelegate
import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION import androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION
@ -324,6 +325,11 @@ fun Context.isInNightMode(): Boolean {
return currentNightMode == Configuration.UI_MODE_NIGHT_YES return currentNightMode == Configuration.UI_MODE_NIGHT_YES
} }
fun Context.appDelegateNightMode(): Int {
return if (isInNightMode()) AppCompatDelegate.MODE_NIGHT_YES
else AppCompatDelegate.MODE_NIGHT_NO
}
fun Context.isOnline(): Boolean { fun Context.isOnline(): Boolean {
val connectivityManager = this val connectivityManager = this
.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager .getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.util.system package eu.kanade.tachiyomi.util.system
import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
@ -15,17 +16,24 @@ object ThemeUtil {
/** Migration method */ /** Migration method */
fun convertTheme(preferences: PreferencesHelper, theme: Int) { fun convertTheme(preferences: PreferencesHelper, theme: Int) {
preferences.theme().set( preferences.nightMode().set(
when (theme) {
0, 1 -> AppCompatDelegate.MODE_NIGHT_NO
2, 3, 4 -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
)
preferences.lightTheme().set(
when (theme) { when (theme) {
0 -> Themes.PURE_WHITE
1 -> Themes.LIGHT_BLUE 1 -> Themes.LIGHT_BLUE
2 -> Themes.DARK else -> Themes.PURE_WHITE
}
)
preferences.darkTheme().set(
when (theme) {
3 -> Themes.AMOLED 3 -> Themes.AMOLED
4 -> Themes.DARK_BLUE 4 -> Themes.DARK_BLUE
5 -> Themes.DEFAULT else -> Themes.DARK
6 -> Themes.DEFAULT_AMOLED
7 -> Themes.ALL_BLUE
else -> Themes.DEFAULT
} }
) )
} }
@ -51,36 +59,21 @@ object ThemeUtil {
enum class Themes(@StyleRes val styleRes: Int, val nightMode: Int, @StringRes val nameRes: Int) { enum class Themes(@StyleRes val styleRes: Int, val nightMode: Int, @StringRes val nameRes: Int) {
PURE_WHITE(R.style.Theme_Tachiyomi, AppCompatDelegate.MODE_NIGHT_NO, R.string.white_theme), PURE_WHITE(R.style.Theme_Tachiyomi, AppCompatDelegate.MODE_NIGHT_NO, R.string.white_theme),
LIGHT_BLUE(
R.style.Theme_Tachiyomi_AllBlue,
AppCompatDelegate.MODE_NIGHT_NO,
R.string.light_blue
),
DARK(R.style.Theme_Tachiyomi, AppCompatDelegate.MODE_NIGHT_YES, R.string.dark), DARK(R.style.Theme_Tachiyomi, AppCompatDelegate.MODE_NIGHT_YES, R.string.dark),
AMOLED( AMOLED(
R.style.Theme_Tachiyomi_Amoled, R.style.Theme_Tachiyomi_Amoled,
AppCompatDelegate.MODE_NIGHT_YES, AppCompatDelegate.MODE_NIGHT_YES,
R.string.amoled_black R.string.amoled_black
), ),
LIGHT_BLUE(
R.style.Theme_Tachiyomi_AllBlue,
AppCompatDelegate.MODE_NIGHT_NO,
R.string.light_blue
),
DARK_BLUE( DARK_BLUE(
R.style.Theme_Tachiyomi_AllBlue, R.style.Theme_Tachiyomi_AllBlue,
AppCompatDelegate.MODE_NIGHT_YES, AppCompatDelegate.MODE_NIGHT_YES,
R.string.dark_blue R.string.dark_blue
),
DEFAULT(
R.style.Theme_Tachiyomi,
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,
R.string.system_default
),
DEFAULT_AMOLED(
R.style.Theme_Tachiyomi_Amoled,
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,
R.string.system_default_amoled
),
ALL_BLUE(
R.style.Theme_Tachiyomi_AllBlue,
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,
R.string.system_default_all_blue
); );
fun getColors(mode: Int = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM): Colors { fun getColors(mode: Int = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM): Colors {
@ -177,16 +170,21 @@ object ThemeUtil {
} }
@ColorInt @ColorInt
val lightBottomBar: Int = when (styleRes) { val lightBottomBar: Int = Color.parseColor(
R.style.Theme_Tachiyomi_AllBlue -> Color.parseColor("#54759E") when (styleRes) {
else -> Color.parseColor("#FFFFFF") R.style.Theme_Tachiyomi_AllBlue -> "#54759E"
else -> "#FFFFFF"
} }
)
@ColorInt @ColorInt
val darkBottomBar: Int = when (styleRes) { val darkBottomBar: Int = Color.parseColor(
R.style.Theme_Tachiyomi_AllBlue -> Color.parseColor("#54759E") when (styleRes) {
else -> Color.parseColor("#212121") R.style.Theme_Tachiyomi_AllBlue -> "#54759E"
R.style.Theme_Tachiyomi_Amoled -> "#000000"
else -> "#212121"
} }
)
@ColorInt @ColorInt
val lightInactiveTab: Int = when (styleRes) { val lightInactiveTab: Int = when (styleRes) {
@ -225,3 +223,23 @@ object ThemeUtil {
@ColorInt val activeTab: Int, @ColorInt val activeTab: Int,
) )
} }
fun Activity.setThemeAndNight(preferences: PreferencesHelper) {
if (preferences.nightMode().isNotSet()) {
ThemeUtil.convertTheme(preferences, preferences.oldTheme())
}
AppCompatDelegate.setDefaultNightMode(preferences.nightMode().get())
val theme = getPrefTheme(preferences)
setTheme(theme.styleRes)
}
fun Context.getPrefTheme(preferences: PreferencesHelper): ThemeUtil.Themes {
// Using a try catch in case I start to remove themes
return try {
(if (isInNightMode() || preferences.nightMode().get() == AppCompatDelegate.MODE_NIGHT_YES) preferences.darkTheme() else preferences.lightTheme()).get()
} catch (e: Exception) {
preferences.lightTheme().set(ThemeUtil.Themes.PURE_WHITE)
preferences.darkTheme().set(ThemeUtil.Themes.DARK)
ThemeUtil.Themes.PURE_WHITE
}
}

View File

@ -32,9 +32,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.ThemeUtil
import eu.kanade.tachiyomi.util.system.contextCompatColor import eu.kanade.tachiyomi.util.system.contextCompatColor
import eu.kanade.tachiyomi.util.system.getPrefTheme
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -63,7 +63,7 @@ fun View.snack(
if (f != null) { if (f != null) {
snack.f() snack.f()
} }
val theme = Injekt.get<PreferencesHelper>().theme().get() val theme = context.getPrefTheme(Injekt.get())
if (ThemeUtil.isPitchBlack(context, theme)) { if (ThemeUtil.isPitchBlack(context, theme)) {
val textView: TextView = val textView: TextView =
snack.view.findViewById(com.google.android.material.R.id.snackbar_text) snack.view.findViewById(com.google.android.material.R.id.snackbar_text)

View File

@ -184,143 +184,6 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/dark_theme_layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.50">
<FrameLayout
android:id="@+id/dark_theme_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/theme_app_bar_preview"
android:background="?attr/colorSecondary"
android:elevation="2dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/dark_theme_app_bar_text"
android:layout_width="match_parent"
android:layout_height="@dimen/theme_text_preview"
android:layout_gravity="start|center"
android:layout_marginEnd="@dimen/theme_app_bar_margin_end"
android:src="@drawable/right_half_oval"
app:tint="?actionBarTintColor"
tools:ignore="ContentDescription" />
</FrameLayout>
<ImageView
android:id="@+id/dark_theme_hero_image"
android:layout_width="match_parent"
android:layout_height="@dimen/theme_hero_preview"
android:layout_marginTop="@dimen/theme_padding_preview"
android:layout_marginEnd="@dimen/theme_padding_preview"
android:alpha="0.70"
android:src="@drawable/right_half_oval"
app:layout_constraintBottom_toTopOf="@id/dark_theme_hero_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dark_theme_toolbar"
app:tint="?android:attr/textColorPrimary"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/dark_theme_primary_text"
android:layout_width="match_parent"
android:layout_height="@dimen/theme_text_preview"
android:layout_marginTop="@dimen/theme_text_padding_preview"
android:layout_marginEnd="@dimen/theme_primary_margin_end"
android:src="@drawable/right_half_oval"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dark_theme_hero_image"
app:tint="?android:attr/textColorPrimary"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/dark_theme_accented_button"
android:layout_width="@dimen/theme_accent_width_preview"
android:layout_height="@dimen/theme_text_preview"
android:layout_marginStart="3dp"
android:src="@drawable/oval"
app:layout_constraintBottom_toBottomOf="@id/dark_theme_primary_text"
app:layout_constraintStart_toEndOf="@id/dark_theme_primary_text"
app:layout_constraintTop_toTopOf="@id/dark_theme_primary_text"
app:tint="?colorAccent"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/dark_theme_secondary_text"
android:layout_width="20dp"
android:layout_height="@dimen/theme_text_preview"
android:layout_marginTop="@dimen/theme_text_padding_preview"
android:src="@drawable/right_half_oval"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dark_theme_primary_text"
app:tint="?android:attr/textColorSecondary"
tools:ignore="ContentDescription" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/dark_theme_bottom_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/theme_bottom_bar_preview"
android:background="?colorPrimaryVariant"
android:elevation="2dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:id="@+id/dark_theme_item_2"
android:layout_width="@dimen/theme_bottom_item_half_preview"
android:layout_height="@dimen/theme_bottom_item_preview"
android:src="@drawable/right_half_oval"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/dark_theme_item_3"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/tabBarIconColor"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/dark_theme_item_3"
android:layout_width="@dimen/theme_bottom_item_preview"
android:layout_height="@dimen/theme_bottom_item_preview"
android:src="@drawable/oval"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/dark_theme_item_gap"
app:layout_constraintStart_toEndOf="@id/dark_theme_item_2"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/tabBarIconInactive"
tools:ignore="ContentDescription" />
<Space
android:id="@+id/dark_theme_item_gap"
android:layout_width="0dp"
app:layout_constraintWidth_percent="0.0"
android:layout_height="30dp"
android:src="@drawable/right_half_oval"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/dark_theme_item_3"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/tabBarIconColor"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView <ImageView
android:id="@+id/checkbox" android:id="@+id/checkbox"
android:background="@drawable/oval" android:background="@drawable/oval"
@ -340,7 +203,7 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/theme_name_text" android:id="@+id/theme_name_text"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="50sp" android:layout_height="32sp"
android:maxLines="3" android:maxLines="3"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:textAlignment="center" android:textAlignment="center"

View File

@ -579,6 +579,7 @@
<string name="auto_check_for_app_versions">Automatically check for new app versions</string> <string name="auto_check_for_app_versions">Automatically check for new app versions</string>
<string name="secure_screen">Secure screen</string> <string name="secure_screen">Secure screen</string>
<string name="hide_bottom_nav">Auto-hide bottom navigation</string> <string name="hide_bottom_nav">Auto-hide bottom navigation</string>
<string name="follow_system_theme">Follow system theme</string>
<string name="hides_on_scroll">Hides when scrolling</string> <string name="hides_on_scroll">Hides when scrolling</string>
<string name="hide_tachi_from_recents">Hide Tachiyomi from the recents screen</string> <string name="hide_tachi_from_recents">Hide Tachiyomi from the recents screen</string>
<string name="security">Security</string> <string name="security">Security</string>