重写主题系统
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package io.legato.kazusa.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||
import io.legato.kazusa.R
|
||||
import androidx.core.content.withStyledAttributes
|
||||
|
||||
|
||||
class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
|
||||
|
||||
private var currentValue: String? = null
|
||||
private var isBottomBackground: Boolean = false
|
||||
|
||||
init {
|
||||
layoutResource = R.layout.view_pref
|
||||
widgetLayoutResource = R.layout.view_theme_mode
|
||||
context.withStyledAttributes(attrs, R.styleable.Preference) {
|
||||
isBottomBackground = getBoolean(R.styleable.Preference_isBottomBackground, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
|
||||
val toggleGroup = holder.itemView.findViewById<View>(R.id.theme_toggle_group)
|
||||
if (toggleGroup == null) {
|
||||
val rootView = holder.itemView as ViewGroup
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val themeToggleView = inflater.inflate(R.layout.view_theme_mode, rootView, false)
|
||||
rootView.addView(themeToggleView)
|
||||
|
||||
setupToggleGroup(themeToggleView.findViewById(R.id.theme_toggle_group))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupToggleGroup(toggleGroup: MaterialButtonToggleGroup) {
|
||||
|
||||
when (currentValue) {
|
||||
"0" -> toggleGroup.check(R.id.btn_system)
|
||||
"1" -> toggleGroup.check(R.id.btn_light)
|
||||
"2" -> toggleGroup.check(R.id.btn_dark)
|
||||
}
|
||||
|
||||
// 监听选择变化
|
||||
toggleGroup.addOnButtonCheckedListener { group, checkedId, isChecked ->
|
||||
if (isChecked) {
|
||||
val newValue = when (checkedId) {
|
||||
R.id.btn_system -> "0"
|
||||
R.id.btn_light -> "1"
|
||||
R.id.btn_dark -> "2"
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (newValue != null && callChangeListener(newValue)) {
|
||||
currentValue = newValue
|
||||
persistString(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSetInitialValue(defaultValue: Any?) {
|
||||
super.onSetInitialValue(defaultValue)
|
||||
currentValue = getPersistedString(defaultValue as? String ?: "0")
|
||||
}
|
||||
|
||||
fun getDefaultValue(): Any {
|
||||
return "0"
|
||||
}
|
||||
|
||||
override fun shouldDisableDependents(): Boolean {
|
||||
return currentValue == null || super.shouldDisableDependents()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.legato.kazusa.utils
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.floatPreferencesKey
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
object DataStoreUtil {
|
||||
|
||||
suspend fun <T> save(context: Context, key: String, value: T) {
|
||||
context.dataStore.edit { preferences ->
|
||||
when (value) {
|
||||
is String -> preferences[stringPreferencesKey(key)] = value
|
||||
is Int -> preferences[intPreferencesKey(key)] = value
|
||||
is Boolean -> preferences[booleanPreferencesKey(key)] = value
|
||||
is Float -> preferences[floatPreferencesKey(key)] = value
|
||||
is Long -> preferences[longPreferencesKey(key)] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> read(context: Context, key: String, defaultValue: T): T {
|
||||
return context.dataStore.data.map { preferences ->
|
||||
when (defaultValue) {
|
||||
is String -> preferences[stringPreferencesKey(key)] ?: defaultValue
|
||||
is Int -> preferences[intPreferencesKey(key)] ?: defaultValue
|
||||
is Boolean -> preferences[booleanPreferencesKey(key)] ?: defaultValue
|
||||
is Float -> preferences[floatPreferencesKey(key)] ?: defaultValue
|
||||
is Long -> preferences[longPreferencesKey(key)] ?: defaultValue
|
||||
else -> defaultValue
|
||||
} as T
|
||||
}.first()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?attr/colorSurfaceContainerLow" />
|
||||
<corners android:radius="12dp" />
|
||||
<padding
|
||||
android:bottom="8dp"
|
||||
android:top="8dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/theme_toggle_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
app:singleSelection="true"
|
||||
app:selectionRequired="true">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_system"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="跟随系统" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_light"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="浅色" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_dark"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="深色" />
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Base.AppTheme" parent="Theme.Material3.DynamicColors.DayNight.NoActionBar">
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="tabStyle">@style/Widget.App.TabLayout</item>
|
||||
<item name="popupMenuBackground">@drawable/popup_background</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.AlertDialog</item>
|
||||
</style>
|
||||
|
||||
<style name="GR.Base.Theme" parent="Base.AppTheme">
|
||||
<item name="colorPrimary">@color/md_theme_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_error</item>
|
||||
<item name="colorOnError">@color/md_theme_onError</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_errorContainer</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_outline</item>
|
||||
<item name="colorOutlineVariant">@color/md_theme_outlineVariant</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item>
|
||||
<item name="colorPrimaryFixed">@color/md_theme_primaryFixed</item>
|
||||
<item name="colorOnPrimaryFixed">@color/md_theme_onPrimaryFixed</item>
|
||||
<item name="colorPrimaryFixedDim">@color/md_theme_primaryFixedDim</item>
|
||||
<item name="colorOnPrimaryFixedVariant">@color/md_theme_onPrimaryFixedVariant</item>
|
||||
<item name="colorSecondaryFixed">@color/md_theme_secondaryFixed</item>
|
||||
<item name="colorOnSecondaryFixed">@color/md_theme_onSecondaryFixed</item>
|
||||
<item name="colorSecondaryFixedDim">@color/md_theme_secondaryFixedDim</item>
|
||||
<item name="colorOnSecondaryFixedVariant">@color/md_theme_onSecondaryFixedVariant</item>
|
||||
<item name="colorTertiaryFixed">@color/md_theme_tertiaryFixed</item>
|
||||
<item name="colorOnTertiaryFixed">@color/md_theme_onTertiaryFixed</item>
|
||||
<item name="colorTertiaryFixedDim">@color/md_theme_tertiaryFixedDim</item>
|
||||
<item name="colorOnTertiaryFixedVariant">@color/md_theme_onTertiaryFixedVariant</item>
|
||||
<item name="colorSurfaceDim">@color/md_theme_surfaceDim</item>
|
||||
<item name="colorSurfaceBright">@color/md_theme_surfaceBright</item>
|
||||
<item name="colorSurfaceContainerLowest">@color/md_theme_surfaceContainerLowest</item>
|
||||
<item name="colorSurfaceContainerLow">@color/md_theme_surfaceContainerLow</item>
|
||||
<item name="colorSurfaceContainer">@color/md_theme_surfaceContainer</item>
|
||||
<item name="colorSurfaceContainerHigh">@color/md_theme_surfaceContainerHigh</item>
|
||||
<item name="colorSurfaceContainerHighest">@color/md_theme_surfaceContainerHighest</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Base.WH" parent="Base.AppTheme">
|
||||
<item name="colorPrimary">@color/wh_theme_primary</item>
|
||||
<item name="colorOnPrimary">@color/wh_theme_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/wh_theme_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/wh_theme_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/wh_theme_secondary</item>
|
||||
<item name="colorOnSecondary">@color/wh_theme_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/wh_theme_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/wh_theme_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/wh_theme_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/wh_theme_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/wh_theme_tertiaryContainer</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="colorOnSurfaceVariant">@color/wh_theme_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/wh_theme_outline</item>
|
||||
<item name="colorOutlineVariant">@color/wh_theme_outlineVariant</item>
|
||||
<item name="colorSurfaceInverse">@color/wh_theme_inverseSurface</item>
|
||||
<item name="colorOnSurfaceInverse">@color/wh_theme_inverseOnSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/wh_theme_inversePrimary</item>
|
||||
<item name="colorPrimaryFixed">@color/wh_theme_primaryFixed</item>
|
||||
<item name="colorOnPrimaryFixed">@color/wh_theme_onPrimaryFixed</item>
|
||||
<item name="colorPrimaryFixedDim">@color/wh_theme_primaryFixedDim</item>
|
||||
<item name="colorOnPrimaryFixedVariant">@color/wh_theme_onPrimaryFixedVariant</item>
|
||||
<item name="colorSecondaryFixed">@color/wh_theme_secondaryFixed</item>
|
||||
<item name="colorOnSecondaryFixed">@color/wh_theme_onSecondaryFixed</item>
|
||||
<item name="colorSecondaryFixedDim">@color/wh_theme_secondaryFixedDim</item>
|
||||
<item name="colorOnSecondaryFixedVariant">@color/wh_theme_onSecondaryFixedVariant</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>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="Widget.App.TabLayout" parent="Widget.Material3.TabLayout">
|
||||
<item name="tabBackground">@android:color/transparent</item>
|
||||
<item name="tabIndicator">@drawable/selected_chip_background</item>
|
||||
<item name="tabIndicatorColor">?attr/colorSecondaryContainer</item>
|
||||
<item name="tabIndicatorFullWidth">true</item>
|
||||
<item name="tabIndicatorGravity">stretch</item>
|
||||
<item name="tabMinWidth">0dp</item>
|
||||
<item name="tabMode">scrollable</item>
|
||||
<item name="tabGravity">start</item>
|
||||
<item name="tabPaddingEnd">12dp</item>
|
||||
<item name="tabPaddingStart">12dp</item>
|
||||
<item name="tabRippleColor">@android:color/transparent</item>
|
||||
<item name="tabSelectedTextColor">?attr/colorOnSecondaryContainer</item>
|
||||
<item name="tabTextColor">?attr/colorOnSurfaceVariant</item>
|
||||
<item name="tabTextAppearance">@style/TabTextAppearance</item>
|
||||
</style>
|
||||
|
||||
<style name="TabTextAppearance" parent="TextAppearance.Design.Tab">
|
||||
<item name="textAllCaps">false</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:textFontWeight" tools:targetApi="p">500</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AlertDialog" parent="ThemeOverlay.Material3.MaterialAlertDialog">
|
||||
<item name="dialogCornerRadius">28dp</item>
|
||||
<item name="cornerFamily">rounded</item>
|
||||
<item name="android:colorBackground">?attr/colorSurfaceContainer</item>
|
||||
<item name="android:layout" tools:ignore="PrivateResource">@layout/m3_alert_dialog</item>
|
||||
</style>
|
||||
|
||||
<style name="ChapterNameText">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:paddingBottom">4dp</item>
|
||||
<item name="android:maxLines">2</item>
|
||||
</style>
|
||||
|
||||
//**********System Style******************//
|
||||
|
||||
<style name="Style.NavigationView" parent="android:Widget">
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Style.Toolbar.NoPadding" parent="Base.Widget.AppCompat.Toolbar">
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Style.MenuItemText" parent="TextAppearance.Material3.BodyLarge">
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Activity.Permission" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="ToolbarTitle" parent="@style/TextAppearance.Material3.ActionBar.Title">
|
||||
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -11,7 +11,7 @@
|
||||
android:title="@string/theme_mode"
|
||||
android:summary="切换浅色/深色/跟随系统" />
|
||||
|
||||
<ListPreference
|
||||
<io.legato.kazusa.lib.prefs.NameListPreference
|
||||
android:key="app_theme"
|
||||
android:title="应用主题"
|
||||
android:summary="喵喵喵"
|
||||
|
||||
Reference in New Issue
Block a user