增加一些基本的界面自定义功能

This commit is contained in:
HapeLee
2025-09-22 01:18:21 +08:00
parent 43b7b39ec6
commit 66b78f53af
16 changed files with 286 additions and 297 deletions
@@ -9,7 +9,6 @@ import android.content.pm.ApplicationInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import com.github.liuyueyi.quick.transfer.constants.TransType import com.github.liuyueyi.quick.transfer.constants.TransType
import com.google.android.material.color.DynamicColors
import com.jeremyliao.liveeventbus.LiveEventBus import com.jeremyliao.liveeventbus.LiveEventBus
import com.jeremyliao.liveeventbus.logger.DefaultLogger import com.jeremyliao.liveeventbus.logger.DefaultLogger
import com.script.rhino.ReadOnlyJavaObject import com.script.rhino.ReadOnlyJavaObject
@@ -66,7 +65,6 @@ class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this)
FirebaseManager.init(this) FirebaseManager.init(this)
CrashHandler(this) CrashHandler(this)
if (isDebuggable) { if (isDebuggable) {
@@ -17,6 +17,7 @@ import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.color.DynamicColors import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import io.legato.kazusa.R import io.legato.kazusa.R
import io.legato.kazusa.constant.AppLog import io.legato.kazusa.constant.AppLog
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
@@ -31,6 +32,7 @@ import io.legato.kazusa.utils.hideSoftInput
import io.legato.kazusa.utils.observeEvent import io.legato.kazusa.utils.observeEvent
import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.windowSize import io.legato.kazusa.utils.windowSize
import io.legato.kazusa.lib.theme.primaryColor
abstract class BaseActivity<VB : ViewBinding>( abstract class BaseActivity<VB : ViewBinding>(
@@ -128,7 +130,9 @@ abstract class BaseActivity<VB : ViewBinding>(
open fun initTheme() { open fun initTheme() {
when (getPrefString("app_theme", "0")) { when (getPrefString("app_theme", "0")) {
"0" -> DynamicColors.applyToActivitiesIfAvailable(application) "0" -> {
DynamicColors.applyToActivitiesIfAvailable(application)
}
"1" -> setTheme(R.style.Theme_Base_GR) "1" -> setTheme(R.style.Theme_Base_GR)
"2" -> setTheme(R.style.Theme_Base_Lemon) "2" -> setTheme(R.style.Theme_Base_Lemon)
"3" -> setTheme(R.style.Theme_Base_WH) "3" -> setTheme(R.style.Theme_Base_WH)
@@ -139,8 +143,17 @@ abstract class BaseActivity<VB : ViewBinding>(
"8" -> setTheme(R.style.Theme_Base_Yuuka) "8" -> setTheme(R.style.Theme_Base_Yuuka)
"9" -> setTheme(R.style.Theme_Base_Phoebe) "9" -> setTheme(R.style.Theme_Base_Phoebe)
"10" -> setTheme(R.style.Theme_Base_Mujika) "10" -> setTheme(R.style.Theme_Base_Mujika)
"11" -> setTheme(R.style.AppTheme_Transparent) "11" -> {
if (AppConfig.customMode == "accent")
setTheme(R.style.ThemeOverlay_WhiteBackground)
DynamicColors.applyToActivitiesIfAvailable(application, DynamicColorsOptions.Builder()
.setContentBasedSource(application.primaryColor)
.build())
} }
"12" -> setTheme(R.style.AppTheme_Transparent)
}
if (AppConfig.pureBlack) if (AppConfig.pureBlack)
setTheme(R.style.ThemeOverlay_PureBlack) setTheme(R.style.ThemeOverlay_PureBlack)
} }
@@ -162,6 +162,7 @@ object PreferKey {
const val firebaseEnable = "firebaseEnable" const val firebaseEnable = "firebaseEnable"
const val cPrimary = "colorPrimary" const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent" const val cAccent = "colorAccent"
const val customMode = "customMode"
const val cBackground = "colorBackground" const val cBackground = "colorBackground"
const val cBBackground = "colorBottomBackground" const val cBBackground = "colorBottomBackground"
const val bgImage = "backgroundImage" const val bgImage = "backgroundImage"
@@ -27,6 +27,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
var useAntiAlias = appCtx.getPrefBoolean(PreferKey.antiAlias) var useAntiAlias = appCtx.getPrefBoolean(PreferKey.antiAlias)
var userAgent: String = getPrefUserAgent() var userAgent: String = getPrefUserAgent()
var isEInkMode = appCtx.getPrefString(PreferKey.themeMode) == "3" var isEInkMode = appCtx.getPrefString(PreferKey.themeMode) == "3"
var customMode = appCtx.getPrefString(PreferKey.customMode)
var clickActionTL = appCtx.getPrefInt(PreferKey.clickActionTL, 2) var clickActionTL = appCtx.getPrefInt(PreferKey.clickActionTL, 2)
var clickActionTC = appCtx.getPrefInt(PreferKey.clickActionTC, 2) var clickActionTC = appCtx.getPrefInt(PreferKey.clickActionTC, 2)
var clickActionTR = appCtx.getPrefInt(PreferKey.clickActionTR, 1) var clickActionTR = appCtx.getPrefInt(PreferKey.clickActionTR, 1)
@@ -14,9 +14,13 @@ import androidx.preference.PreferenceViewHolder
import com.jaredrummler.android.colorpicker.* import com.jaredrummler.android.colorpicker.*
import io.legato.kazusa.utils.ColorUtils import io.legato.kazusa.utils.ColorUtils
import io.legato.kazusa.utils.applyTint import io.legato.kazusa.utils.applyTint
import io.legato.kazusa.utils.themeColor
@Suppress("MemberVisibilityCanBePrivate", "unused") @Suppress("MemberVisibilityCanBePrivate", "unused")
class ColorPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs), class ColorPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : Preference(context, attrs),
ColorPickerDialogListener { ColorPickerDialogListener {
var onSaveColor: ((color: Int) -> Boolean)? = null var onSaveColor: ((color: Int) -> Boolean)? = null
@@ -123,6 +127,7 @@ class ColorPreference(context: Context, attrs: AttributeSet) : Preference(contex
) )
if (v is ColorPanelView) { if (v is ColorPanelView) {
v.color = mColor v.color = mColor
v.setBorderColor(context.themeColor(com.google.android.material.R.attr.colorPrimaryContainer))
} }
} }
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet import android.util.AttributeSet
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -17,6 +19,7 @@ import com.google.android.material.card.MaterialCardView
import io.legato.kazusa.R import io.legato.kazusa.R
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.utils.postEvent import io.legato.kazusa.utils.postEvent
import io.legato.kazusa.utils.restart
@SuppressLint("ResourceType") @SuppressLint("ResourceType")
class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) { class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
@@ -73,12 +76,20 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
holder.card.setOnClickListener { holder.card.setOnClickListener {
if (value != currentValue) { if (value != currentValue) {
val oldValue = currentValue
currentValue = value currentValue = value
persistString(value) persistString(value)
callChangeListener(value) callChangeListener(value)
notifyDataSetChanged() notifyDataSetChanged()
val isDynamicSwitch = (oldValue == "11" || value == "11")
Handler(Looper.getMainLooper()).postDelayed({
if (isDynamicSwitch) {
context.restart()
} else {
postEvent(EventBus.RECREATE, "") postEvent(EventBus.RECREATE, "")
} }
}, 300)
}
} }
} }
@@ -98,8 +109,8 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
"8" to R.style.Theme_Base_Yuuka, "8" to R.style.Theme_Base_Yuuka,
"9" to R.style.Theme_Base_Phoebe, "9" to R.style.Theme_Base_Phoebe,
"10" to R.style.Theme_Base_Mujika, "10" to R.style.Theme_Base_Mujika,
"11" to R.style.AppTheme_Transparent "11" to R.style.Theme_Base_WH,
) "12" to R.style.AppTheme_Transparent)
private fun getThemeColors(value: String): List<Int> { private fun getThemeColors(value: String): List<Int> {
val themeResId = themeResIdMap[value] ?: return listOf(Color.GRAY, Color.GRAY, Color.GRAY, Color.GRAY) val themeResId = themeResIdMap[value] ?: return listOf(Color.GRAY, Color.GRAY, Color.GRAY, Color.GRAY)
@@ -1,6 +1,8 @@
package io.legato.kazusa.lib.prefs package io.legato.kazusa.lib.prefs
import android.content.Context import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet import android.util.AttributeSet
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import com.google.android.material.button.MaterialButtonToggleGroup import com.google.android.material.button.MaterialButtonToggleGroup
@@ -56,7 +58,9 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co
currentValue = newValue currentValue = newValue
persistString(newValue) persistString(newValue)
callChangeListener(newValue) callChangeListener(newValue)
Handler(Looper.getMainLooper()).postDelayed({
ThemeConfig.applyDayNight(context) ThemeConfig.applyDayNight(context)
}, 300)
} }
} }
} }
@@ -2,6 +2,16 @@
package io.legato.kazusa.lib.theme package io.legato.kazusa.lib.theme
import android.content.Context
/** /**
* @author Karim Abou Zeid (kabouzeid) * @author Karim Abou Zeid (kabouzeid)
*/ */
val Context.primaryColor: Int
get() = ThemeStore.primaryColor(this)
val Context.secondaryColor: Int
get() = ThemeStore.secondaryColor(this)
val Context.primaryContainerColor: Int
get() = ThemeStore.primaryContainerColor(this)
@@ -11,20 +11,63 @@ import androidx.core.content.ContextCompat
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import io.legato.kazusa.utils.ColorUtils import io.legato.kazusa.utils.ColorUtils
import splitties.init.appCtx import splitties.init.appCtx
import androidx.core.content.edit
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import com.google.android.material.color.MaterialColors
/** /**
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) * @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid)
*/ */
@Suppress("unused") @Suppress("unused")
class ThemeStore @SuppressLint("CommitPrefEdits") class ThemeStore @SuppressLint("CommitPrefEdits")
private constructor(private val mContext: Context) : ThemeStoreInterface { private constructor(private val mContext: Context) : ThemeStoreInterface {
private val mEditor = prefs(mContext).edit() private val mEditor = prefs(mContext).edit()
override fun addColorScheme(@ColorInt color: Int): ThemeStore {
val options = DynamicColorsOptions.Builder()
.setContentBasedSource(color)
.build()
val wrapped = DynamicColors.wrapContextIfAvailable(
mContext,
options).apply {
resources.configuration.uiMode = mContext.resources.configuration.uiMode
}
val fallback = color
val secondary = MaterialColors.getColor(
wrapped,
com.google.android.material.R.attr.colorSecondary,
fallback
)
val primaryContainer = MaterialColors.getColor(
wrapped,
com.google.android.material.R.attr.colorSecondaryContainer,
fallback
)
val primary = MaterialColors.getColor(
wrapped,
androidx.appcompat.R.attr.colorPrimary,
fallback
)
mEditor.putInt(ThemeStorePrefKeys.KEY_SECONDARY_COLOR, secondary)
mEditor.putInt(ThemeStorePrefKeys.KEY_PRIMARY_CONTAINER_COLOR, primaryContainer)
mEditor.putInt(ThemeStorePrefKeys.KEY_PRIMARY_COLOR, primary)
return this
}
override fun primaryColor(@ColorInt color: Int): ThemeStore { override fun primaryColor(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_PRIMARY_COLOR, color)
if (autoGeneratePrimaryDark(mContext)) if (autoGeneratePrimaryDark(mContext))
primaryColorDark(ColorUtils.darkenColor(color)) primaryColorDark(ColorUtils.darkenColor(color))
addColorScheme(color)
return this return this
} }
@@ -49,97 +92,6 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
return primaryColorDark(ThemeUtils.resolveColor(mContext, colorAttr)) return primaryColorDark(ThemeUtils.resolveColor(mContext, colorAttr))
} }
override fun accentColor(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_ACCENT_COLOR, color)
return this
}
override fun accentColorRes(@ColorRes colorRes: Int): ThemeStore {
return accentColor(ContextCompat.getColor(mContext, colorRes))
}
override fun accentColorAttr(@AttrRes colorAttr: Int): ThemeStore {
return accentColor(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun statusBarColor(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_STATUS_BAR_COLOR, color)
return this
}
override fun statusBarColorRes(@ColorRes colorRes: Int): ThemeStore {
return statusBarColor(ContextCompat.getColor(mContext, colorRes))
}
override fun statusBarColorAttr(@AttrRes colorAttr: Int): ThemeStore {
return statusBarColor(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun navigationBarColor(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_NAVIGATION_BAR_COLOR, color)
return this
}
override fun navigationBarColorRes(@ColorRes colorRes: Int): ThemeStore {
return navigationBarColor(ContextCompat.getColor(mContext, colorRes))
}
override fun navigationBarColorAttr(@AttrRes colorAttr: Int): ThemeStore {
return navigationBarColor(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun textColorPrimary(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY, color)
return this
}
override fun textColorPrimaryRes(@ColorRes colorRes: Int): ThemeStore {
return textColorPrimary(ContextCompat.getColor(mContext, colorRes))
}
override fun textColorPrimaryAttr(@AttrRes colorAttr: Int): ThemeStore {
return textColorPrimary(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun textColorPrimaryInverse(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY_INVERSE, color)
return this
}
override fun textColorPrimaryInverseRes(@ColorRes colorRes: Int): ThemeStore {
return textColorPrimaryInverse(ContextCompat.getColor(mContext, colorRes))
}
override fun textColorPrimaryInverseAttr(@AttrRes colorAttr: Int): ThemeStore {
return textColorPrimaryInverse(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun textColorSecondary(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY, color)
return this
}
override fun textColorSecondaryRes(@ColorRes colorRes: Int): ThemeStore {
return textColorSecondary(ContextCompat.getColor(mContext, colorRes))
}
override fun textColorSecondaryAttr(@AttrRes colorAttr: Int): ThemeStore {
return textColorSecondary(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun textColorSecondaryInverse(@ColorInt color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY_INVERSE, color)
return this
}
override fun textColorSecondaryInverseRes(@ColorRes colorRes: Int): ThemeStore {
return textColorSecondaryInverse(ContextCompat.getColor(mContext, colorRes))
}
override fun textColorSecondaryInverseAttr(@AttrRes colorAttr: Int): ThemeStore {
return textColorSecondaryInverse(ThemeUtils.resolveColor(mContext, colorAttr))
}
override fun backgroundColor(color: Int): ThemeStore { override fun backgroundColor(color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_BACKGROUND_COLOR, color) mEditor.putInt(ThemeStorePrefKeys.KEY_BACKGROUND_COLOR, color)
return this return this
@@ -161,17 +113,17 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
mEditor.putLong(ThemeStorePrefKeys.VALUES_CHANGED, System.currentTimeMillis()) mEditor.putLong(ThemeStorePrefKeys.VALUES_CHANGED, System.currentTimeMillis())
.putBoolean(ThemeStorePrefKeys.IS_CONFIGURED_KEY, true) .putBoolean(ThemeStorePrefKeys.IS_CONFIGURED_KEY, true)
.apply() .apply()
accentColor = accentColor()
} }
companion object { companion object {
var accentColor = accentColor()
fun editTheme(context: Context): ThemeStore { fun editTheme(context: Context): ThemeStore {
return ThemeStore(context) return ThemeStore(context)
} }
fun isCustomThemeEnabled(context: Context): Boolean = true
// AppConfig.customTheme
// Static getters // Static getters
@CheckResult @CheckResult
@@ -189,7 +141,8 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
@CheckResult @CheckResult
@ColorInt @ColorInt
fun primaryColor(context: Context = appCtx): Int { fun primaryColor(context: Context = appCtx): Int {
return prefs(context).getInt( return if (isCustomThemeEnabled(context)) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_PRIMARY_COLOR, ThemeStorePrefKeys.KEY_PRIMARY_COLOR,
ThemeUtils.resolveColor( ThemeUtils.resolveColor(
context, context,
@@ -197,12 +150,38 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
"#455A64".toColorInt() "#455A64".toColorInt()
) )
) )
} else {
ThemeUtils.resolveColor(context, androidx.appcompat.R.attr.colorPrimary)
}
}
fun primaryContainerColor(context: Context = appCtx): Int {
return if (isCustomThemeEnabled(context)) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_PRIMARY_CONTAINER_COLOR,
"#FFFFFF".toColorInt()
)
} else {
ThemeUtils.resolveColor(context, com.google.android.material.R.attr.colorPrimaryContainer)
}
}
fun secondaryColor(context: Context = appCtx): Int {
return if (isCustomThemeEnabled(context)) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_SECONDARY_COLOR,
primaryColor(context)
)
} else {
primaryColor(context)
}
} }
@CheckResult @CheckResult
@ColorInt @ColorInt
fun primaryColorDark(context: Context): Int { fun primaryColorDark(context: Context): Int {
return prefs(context).getInt( return if (isCustomThemeEnabled(context)) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_PRIMARY_COLOR_DARK, ThemeStorePrefKeys.KEY_PRIMARY_COLOR_DARK,
ThemeUtils.resolveColor( ThemeUtils.resolveColor(
context, context,
@@ -210,89 +189,22 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
"#37474F".toColorInt() "#37474F".toColorInt()
) )
) )
}
@CheckResult
@ColorInt
fun accentColor(context: Context = appCtx): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_ACCENT_COLOR,
ThemeUtils.resolveColor(
context,
androidx.appcompat.R.attr.colorAccent,
"#263238".toColorInt()
)
)
}
@CheckResult
@ColorInt
fun statusBarColor(context: Context, transparent: Boolean): Int {
return if (transparent) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_STATUS_BAR_COLOR,
primaryColor(context)
)
} else { } else {
prefs(context).getInt( ThemeUtils.resolveColor(context, androidx.appcompat.R.attr.colorPrimaryDark)
ThemeStorePrefKeys.KEY_STATUS_BAR_COLOR,
primaryColorDark(context)
)
} }
} }
@CheckResult
@ColorInt
fun navigationBarColor(context: Context): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_NAVIGATION_BAR_COLOR,
bottomBackground(context)
)
}
@CheckResult
@ColorInt
fun textColorPrimary(context: Context): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY,
ThemeUtils.resolveColor(context, android.R.attr.textColorPrimary)
)
}
@CheckResult
@ColorInt
fun textColorPrimaryInverse(context: Context): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY_INVERSE,
ThemeUtils.resolveColor(context, android.R.attr.textColorPrimaryInverse)
)
}
@CheckResult
@ColorInt
fun textColorSecondary(context: Context): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY,
ThemeUtils.resolveColor(context, android.R.attr.textColorSecondary)
)
}
@CheckResult
@ColorInt
fun textColorSecondaryInverse(context: Context): Int {
return prefs(context).getInt(
ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY_INVERSE,
ThemeUtils.resolveColor(context, android.R.attr.textColorSecondaryInverse)
)
}
@CheckResult @CheckResult
@ColorInt @ColorInt
fun backgroundColor(context: Context = appCtx): Int { fun backgroundColor(context: Context = appCtx): Int {
return prefs(context).getInt( return if (isCustomThemeEnabled(context)) {
prefs(context).getInt(
ThemeStorePrefKeys.KEY_BACKGROUND_COLOR, ThemeStorePrefKeys.KEY_BACKGROUND_COLOR,
ThemeUtils.resolveColor(context, android.R.attr.colorBackground) ThemeUtils.resolveColor(context, android.R.attr.colorBackground)
) )
} else {
ThemeUtils.resolveColor(context, android.R.attr.colorBackground)
}
} }
@CheckResult @CheckResult
@@ -332,7 +244,7 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
val prefs = prefs(context) val prefs = prefs(context)
val lastVersion = prefs.getInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, -1) val lastVersion = prefs.getInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, -1)
if (version > lastVersion) { if (version > lastVersion) {
prefs.edit().putInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, version).apply() prefs.edit { putInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, version) }
return false return false
} }
return true return true
@@ -26,57 +26,7 @@ internal interface ThemeStoreInterface {
fun primaryColorDarkAttr(@AttrRes colorAttr: Int): ThemeStore fun primaryColorDarkAttr(@AttrRes colorAttr: Int): ThemeStore
// Accent colors fun addColorScheme(@ColorInt color: Int): ThemeStore
fun accentColor(@ColorInt color: Int): ThemeStore
fun accentColorRes(@ColorRes colorRes: Int): ThemeStore
fun accentColorAttr(@AttrRes colorAttr: Int): ThemeStore
// Status bar color
fun statusBarColor(@ColorInt color: Int): ThemeStore
fun statusBarColorRes(@ColorRes colorRes: Int): ThemeStore
fun statusBarColorAttr(@AttrRes colorAttr: Int): ThemeStore
// Navigation bar color
fun navigationBarColor(@ColorInt color: Int): ThemeStore
fun navigationBarColorRes(@ColorRes colorRes: Int): ThemeStore
fun navigationBarColorAttr(@AttrRes colorAttr: Int): ThemeStore
// Primary text color
fun textColorPrimary(@ColorInt color: Int): ThemeStore
fun textColorPrimaryRes(@ColorRes colorRes: Int): ThemeStore
fun textColorPrimaryAttr(@AttrRes colorAttr: Int): ThemeStore
fun textColorPrimaryInverse(@ColorInt color: Int): ThemeStore
fun textColorPrimaryInverseRes(@ColorRes colorRes: Int): ThemeStore
fun textColorPrimaryInverseAttr(@AttrRes colorAttr: Int): ThemeStore
// Secondary text color
fun textColorSecondary(@ColorInt color: Int): ThemeStore
fun textColorSecondaryRes(@ColorRes colorRes: Int): ThemeStore
fun textColorSecondaryAttr(@AttrRes colorAttr: Int): ThemeStore
fun textColorSecondaryInverse(@ColorInt color: Int): ThemeStore
fun textColorSecondaryInverseRes(@ColorRes colorRes: Int): ThemeStore
fun textColorSecondaryInverseAttr(@AttrRes colorAttr: Int): ThemeStore
// Background // Background
@@ -9,21 +9,12 @@ object ThemeStorePrefKeys {
const val IS_CONFIGURED_KEY = "is_configured" const val IS_CONFIGURED_KEY = "is_configured"
const val IS_CONFIGURED_VERSION_KEY = "is_configured_version" const val IS_CONFIGURED_VERSION_KEY = "is_configured_version"
const val VALUES_CHANGED = "values_changed" const val VALUES_CHANGED = "values_changed"
const val KEY_PRIMARY_COLOR = "primary_color" const val KEY_PRIMARY_COLOR = "primary_color"
const val KEY_PRIMARY_CONTAINER_COLOR = "KEY_PRIMARY_CONTAINER_COLOR"
const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark" const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark"
const val KEY_ACCENT_COLOR = "accent_color" const val KEY_SECONDARY_COLOR = "KEY_SECONDARY_COLOR"
const val KEY_STATUS_BAR_COLOR = "status_bar_color"
const val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color"
const val KEY_TEXT_COLOR_PRIMARY = "text_color_primary"
const val KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse"
const val KEY_TEXT_COLOR_SECONDARY = "text_color_secondary"
const val KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse"
const val KEY_BACKGROUND_COLOR = "backgroundColor" const val KEY_BACKGROUND_COLOR = "backgroundColor"
const val KEY_BOTTOM_BACKGROUND = "bottomBackground" const val KEY_BOTTOM_BACKGROUND = "bottomBackground"
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar" const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar" const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
@@ -2,13 +2,18 @@ package io.legato.kazusa.ui.config
//import io.legado.app.lib.theme.primaryColor //import io.legado.app.lib.theme.primaryColor
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View import android.view.View
import android.widget.SeekBar import android.widget.SeekBar
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import io.legato.kazusa.R import io.legato.kazusa.R
import io.legato.kazusa.base.AppContextWrapper import io.legato.kazusa.base.AppContextWrapper
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
@@ -21,8 +26,11 @@ import io.legato.kazusa.help.config.ThemeConfig
import io.legato.kazusa.lib.dialogs.alert import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.dialogs.selector import io.legato.kazusa.lib.dialogs.selector
import io.legato.kazusa.lib.prefs.ColorPreference import io.legato.kazusa.lib.prefs.ColorPreference
import io.legato.kazusa.lib.prefs.NameListPreference
import io.legato.kazusa.lib.prefs.ThemeCardPreference import io.legato.kazusa.lib.prefs.ThemeCardPreference
import io.legato.kazusa.lib.prefs.ThemeModePreference import io.legato.kazusa.lib.prefs.ThemeModePreference
import io.legato.kazusa.lib.theme.ThemeStore
import io.legato.kazusa.lib.theme.primaryColor
import io.legato.kazusa.ui.widget.number.NumberPickerDialog import io.legato.kazusa.ui.widget.number.NumberPickerDialog
import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener
import io.legato.kazusa.utils.ColorUtils import io.legato.kazusa.utils.ColorUtils
@@ -38,6 +46,7 @@ import io.legato.kazusa.utils.putPrefInt
import io.legato.kazusa.utils.putPrefString import io.legato.kazusa.utils.putPrefString
import io.legato.kazusa.utils.readUri import io.legato.kazusa.utils.readUri
import io.legato.kazusa.utils.removePref import io.legato.kazusa.utils.removePref
import io.legato.kazusa.utils.restart
import io.legato.kazusa.utils.startActivity import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.toastOnUi
import splitties.init.appCtx import splitties.init.appCtx
@@ -101,11 +110,25 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
} }
} }
findPreference<ThemeCardPreference>(PreferKey.themePref)?.let { val themePref = findPreference<ThemeCardPreference>(PreferKey.themePref)
val colorPrimary = findPreference<ColorPreference>("colorPrimary")
val currentTheme = getPrefString("app_theme")
colorPrimary?.isVisible = currentTheme == "11"
val customMode = findPreference<NameListPreference>("customMode")
customMode?.isVisible = currentTheme == "11"
themePref?.let {
it.setOnPreferenceChangeListener { _, _ -> it.setOnPreferenceChangeListener { _, _ ->
true true
} }
} }
themePref?.setOnPreferenceChangeListener { _, newValue ->
colorPrimary?.isVisible = newValue == "11"
customMode?.isVisible = newValue == "11"
true
}
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -136,19 +159,38 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
//recreateActivities() //recreateActivities()
} }
PreferKey.customMode -> {
Handler(Looper.getMainLooper()).postDelayed({
requireContext().restart()
}, 300)
}
PreferKey.pureBlack -> { PreferKey.pureBlack -> {
Handler(Looper.getMainLooper()).postDelayed({
recreateActivities() recreateActivities()
}, 300)
}
PreferKey.cPrimary -> {
val color = getPrefInt(key, ThemeStore.primaryColor(requireContext()))
ThemeStore.editTheme(requireContext())
.primaryColor(color)
.apply()
DynamicColors.applyToActivitiesIfAvailable(requireContext().applicationContext as Application, DynamicColorsOptions.Builder()
.setContentBasedSource(requireContext().primaryColor)
.build())
Handler(Looper.getMainLooper()).postDelayed({
recreateActivities()
}, 300)
} }
PreferKey.cPrimary,
PreferKey.cAccent,
PreferKey.cBackground, PreferKey.cBackground,
PreferKey.cBBackground -> { PreferKey.cBBackground -> {
upTheme(false) upTheme(false)
} }
PreferKey.cNPrimary, //PreferKey.cNPrimary,
PreferKey.cNAccent,
PreferKey.cNBackground, PreferKey.cNBackground,
PreferKey.cNBBackground -> { PreferKey.cNBBackground -> {
upTheme(true) upTheme(true)
+29
View File
@@ -12,6 +12,35 @@
<item name="alertDialogTheme">@style/AppTheme.AlertDialog</item> <item name="alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style> </style>
<style name="ThemeOverlay.WhiteBackground" parent="">
<item name="colorOnPrimary">@color/wh_theme_onPrimary</item>
<item name="colorOnSecondary">@color/wh_theme_onSecondary</item>
<item name="colorOnTertiary">@color/wh_theme_onTertiary</item>
<item name="colorOnTertiaryContainer">@color/wh_theme_onTertiaryContainer</item>
<item name="colorError">@color/wh_theme_error</item>
<item name="colorOnError">@color/wh_theme_onError</item>
<item name="colorErrorContainer">@color/wh_theme_errorContainer</item>
<item name="colorOnErrorContainer">@color/wh_theme_onErrorContainer</item>
<item name="android:colorBackground">@color/wh_theme_background</item>
<item name="colorOnBackground">@color/wh_theme_onBackground</item>
<item name="colorSurface">@color/wh_theme_surface</item>
<item name="colorOnSurface">@color/wh_theme_onSurface</item>
<item name="colorSurfaceVariant">@color/wh_theme_surfaceVariant</item>
<item name="colorOutlineVariant">@color/wh_theme_outlineVariant</item>
<item name="colorOnSurfaceInverse">@color/wh_theme_inverseOnSurface</item>
<item name="colorTertiaryFixed">@color/wh_theme_tertiaryFixed</item>
<item name="colorOnTertiaryFixed">@color/wh_theme_onTertiaryFixed</item>
<item name="colorTertiaryFixedDim">@color/wh_theme_tertiaryFixedDim</item>
<item name="colorOnTertiaryFixedVariant">@color/wh_theme_onTertiaryFixedVariant</item>
<item name="colorSurfaceDim">@color/wh_theme_surfaceDim</item>
<item name="colorSurfaceBright">@color/wh_theme_surfaceBright</item>
<item name="colorSurfaceContainerLowest">@color/wh_theme_surfaceContainerLowest</item>
<item name="colorSurfaceContainerLow">@color/wh_theme_surfaceContainerLow</item>
<item name="colorSurfaceContainer">@color/wh_theme_surfaceContainer</item>
<item name="colorSurfaceContainerHigh">@color/wh_theme_surfaceContainerHigh</item>
<item name="colorSurfaceContainerHighest">@color/wh_theme_surfaceContainerHighest</item>
</style>
<style name="ThemeOverlay.PureBlack" parent=""> <style name="ThemeOverlay.PureBlack" parent="">
<item name="android:colorBackground">@color/black</item> <item name="android:colorBackground">@color/black</item>
<item name="colorSurface">@color/black</item> <item name="colorSurface">@color/black</item>
+3 -3
View File
@@ -66,9 +66,9 @@
<color name="wh_theme_onError">#FFFFFF</color> <color name="wh_theme_onError">#FFFFFF</color>
<color name="wh_theme_errorContainer">#FFDAD6</color> <color name="wh_theme_errorContainer">#FFDAD6</color>
<color name="wh_theme_onErrorContainer">#93000A</color> <color name="wh_theme_onErrorContainer">#93000A</color>
<color name="wh_theme_background">#FCF8F8</color> <color name="wh_theme_background">#FAFAFA</color>
<color name="wh_theme_onBackground">#1C1B1B</color> <color name="wh_theme_onBackground">#1C1B1B</color>
<color name="wh_theme_surface">#FCF8F8</color> <color name="wh_theme_surface">#F8F8F8</color>
<color name="wh_theme_onSurface">#1C1B1B</color> <color name="wh_theme_onSurface">#1C1B1B</color>
<color name="wh_theme_surfaceVariant">#E0E3E3</color> <color name="wh_theme_surfaceVariant">#E0E3E3</color>
<color name="wh_theme_onSurfaceVariant">#444748</color> <color name="wh_theme_onSurfaceVariant">#444748</color>
@@ -91,7 +91,7 @@
<color name="wh_theme_tertiaryFixedDim">#CBC5C7</color> <color name="wh_theme_tertiaryFixedDim">#CBC5C7</color>
<color name="wh_theme_onTertiaryFixedVariant">#494648</color> <color name="wh_theme_onTertiaryFixedVariant">#494648</color>
<color name="wh_theme_surfaceDim">#DDD9D8</color> <color name="wh_theme_surfaceDim">#DDD9D8</color>
<color name="wh_theme_surfaceBright">#FCF8F8</color> <color name="wh_theme_surfaceBright">#F8F8F8</color>
<color name="wh_theme_surfaceContainerLowest">#FFFFFF</color> <color name="wh_theme_surfaceContainerLowest">#FFFFFF</color>
<color name="wh_theme_surfaceContainerLow">#F7F3F2</color> <color name="wh_theme_surfaceContainerLow">#F7F3F2</color>
<color name="wh_theme_surfaceContainer">#F1EDEC</color> <color name="wh_theme_surfaceContainer">#F1EDEC</color>
+29
View File
@@ -11,6 +11,35 @@
<item name="alertDialogTheme">@style/AppTheme.AlertDialog</item> <item name="alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style> </style>
<style name="ThemeOverlay.WhiteBackground" parent="">
<item name="colorOnPrimary">@color/wh_theme_onPrimary</item>
<item name="colorOnSecondary">@color/wh_theme_onSecondary</item>
<item name="colorOnTertiary">@color/wh_theme_onTertiary</item>
<item name="colorOnTertiaryContainer">@color/wh_theme_onTertiaryContainer</item>
<item name="colorError">@color/wh_theme_error</item>
<item name="colorOnError">@color/wh_theme_onError</item>
<item name="colorErrorContainer">@color/wh_theme_errorContainer</item>
<item name="colorOnErrorContainer">@color/wh_theme_onErrorContainer</item>
<item name="android:colorBackground">@color/wh_theme_background</item>
<item name="colorOnBackground">@color/wh_theme_onBackground</item>
<item name="colorSurface">@color/wh_theme_surface</item>
<item name="colorOnSurface">@color/wh_theme_onSurface</item>
<item name="colorSurfaceVariant">@color/wh_theme_surfaceVariant</item>
<item name="colorOutlineVariant">@color/wh_theme_outlineVariant</item>
<item name="colorOnSurfaceInverse">@color/wh_theme_inverseOnSurface</item>
<item name="colorTertiaryFixed">@color/wh_theme_tertiaryFixed</item>
<item name="colorOnTertiaryFixed">@color/wh_theme_onTertiaryFixed</item>
<item name="colorTertiaryFixedDim">@color/wh_theme_tertiaryFixedDim</item>
<item name="colorOnTertiaryFixedVariant">@color/wh_theme_onTertiaryFixedVariant</item>
<item name="colorSurfaceDim">@color/wh_theme_surfaceDim</item>
<item name="colorSurfaceBright">@color/wh_theme_surfaceBright</item>
<item name="colorSurfaceContainerLowest">@color/wh_theme_surfaceContainerLowest</item>
<item name="colorSurfaceContainerLow">@color/wh_theme_surfaceContainerLow</item>
<item name="colorSurfaceContainer">@color/wh_theme_surfaceContainer</item>
<item name="colorSurfaceContainerHigh">@color/wh_theme_surfaceContainerHigh</item>
<item name="colorSurfaceContainerHighest">@color/wh_theme_surfaceContainerHighest</item>
</style>
<style name="ThemeOverlay.PureBlack" parent=""> <style name="ThemeOverlay.PureBlack" parent="">
</style> </style>
+25 -32
View File
@@ -33,7 +33,22 @@
<io.legato.kazusa.lib.prefs.SwitchPreference <io.legato.kazusa.lib.prefs.SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="pure_black" android:key="pure_black"
android:title="纯黑色模式" /> android:title="纯黑色模式" />
<io.legato.kazusa.lib.prefs.ColorPreference
android:defaultValue="@color/md_green_500"
android:key="colorPrimary"
android:summary="使用种子颜色创建主题"
android:title="种子色"
app:cpv_dialogType="preset"
app:iconSpaceReserved="false" />
<io.legato.kazusa.lib.prefs.NameListPreference
android:defaultValue="global"
android:key="customMode"
android:title="自定义模式"
app:entries="@array/customMode"
app:entryValues="@array/customMode_value" />
<io.legato.kazusa.lib.prefs.IconListPreference <io.legato.kazusa.lib.prefs.IconListPreference
android:defaultValue="ic_launcher" android:defaultValue="ic_launcher"
@@ -67,26 +82,26 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legato.kazusa.lib.prefs.Preference <io.legato.kazusa.lib.prefs.Preference
android:key="themeList" android:key="backgroundImage"
android:summary="@string/theme_list_summary" android:title="@string/background_image" />
android:title="@string/theme_list"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
</io.legato.kazusa.lib.prefs.PreferenceCategory> </io.legato.kazusa.lib.prefs.PreferenceCategory>
<io.legato.kazusa.lib.prefs.PreferenceCategory <io.legato.kazusa.lib.prefs.PreferenceCategory
android:key="dayThemeCategory" android:key="dayThemeCategory"
android:title="@string/day" android:title="@string/share"
app:allowDividerAbove="true" app:allowDividerAbove="true"
app:allowDividerBelow="false" app:allowDividerBelow="false"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:layout="@layout/view_preference_category"> app:layout="@layout/view_preference_category">
<io.legato.kazusa.lib.prefs.Preference <io.legato.kazusa.lib.prefs.Preference
android:key="backgroundImage" android:key="themeList"
android:title="@string/background_image" /> android:summary="@string/theme_list_summary"
android:title="@string/theme_list"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
<io.legato.kazusa.lib.prefs.Preference <io.legato.kazusa.lib.prefs.Preference
android:key="saveDayTheme" android:key="saveDayTheme"
@@ -98,26 +113,4 @@
</io.legato.kazusa.lib.prefs.PreferenceCategory> </io.legato.kazusa.lib.prefs.PreferenceCategory>
<io.legato.kazusa.lib.prefs.PreferenceCategory
android:key="nightThemeCategory"
android:title="@string/night"
app:allowDividerAbove="true"
app:allowDividerBelow="false"
app:iconSpaceReserved="false"
app:layout="@layout/view_preference_category">
<io.legato.kazusa.lib.prefs.Preference
android:key="backgroundImageNight"
android:title="@string/background_image" />
<io.legato.kazusa.lib.prefs.Preference
android:key="saveNightTheme"
android:summary="@string/save_night_theme_summary"
android:title="@string/save_theme_config"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
</io.legato.kazusa.lib.prefs.PreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>