统一主题颜色

pull/32/head
Administrator 5 years ago
parent b690838479
commit 757d955955
  1. 3
      app/src/main/java/io/legado/app/lib/theme/ATH.kt
  2. 445
      app/src/main/java/io/legado/app/lib/theme/prefs/ATEColorPreference.kt
  3. 184
      app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt
  4. 1
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  5. 1
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt
  6. 12
      app/src/main/res/xml/pref_config_theme.xml
  7. 6
      app/src/main/res/xml/pref_config_web_dav.xml

@ -117,6 +117,9 @@ object ATH {
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(colorStateList)
}
if (dialog.getButton(AlertDialog.BUTTON_NEUTRAL) != null) {
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(colorStateList)
}
return dialog
}

@ -0,0 +1,445 @@
package io.legado.app.lib.theme.prefs
import android.content.Context
import android.content.ContextWrapper
import android.content.res.TypedArray
import android.graphics.Color
import android.os.Bundle
import android.util.AttributeSet
import androidx.annotation.ColorInt
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import com.jaredrummler.android.colorpicker.*
import io.legado.app.lib.theme.ATH
class ATEColorPreference : Preference,
ColorPickerDialogListener {
private val SIZE_NORMAL = 0
private val SIZE_LARGE = 1
private var onShowDialogListener: OnShowDialogListener? = null
private var color = Color.BLACK
private var showDialog: Boolean = false
@ColorPickerDialog.DialogType
private var dialogType: Int = 0
private var colorShape: Int = 0
private var allowPresets: Boolean = false
private var allowCustom: Boolean = false
private var showAlphaSlider: Boolean = false
private var showColorShades: Boolean = false
private var previewSize: Int = 0
private var presets: IntArray? = null
private var dialogTitle: Int = 0
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
) {
init(attrs)
}
private fun init(attrs: AttributeSet) {
isPersistent = true
val a = context.obtainStyledAttributes(attrs, R.styleable.ColorPreference)
showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true)
dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS)
colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE)
allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true)
allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true)
showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false)
showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true)
previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL)
val presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0)
dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title)
if (presetsResId != 0) {
presets = context.resources.getIntArray(presetsResId)
} else {
presets = ColorPickerDialog.MATERIAL_COLORS
}
if (colorShape == ColorShape.CIRCLE) {
widgetLayoutResource =
if (previewSize == SIZE_LARGE) R.layout.cpv_preference_circle_large else R.layout.cpv_preference_circle
} else {
widgetLayoutResource =
if (previewSize == SIZE_LARGE) R.layout.cpv_preference_square_large else R.layout.cpv_preference_square
}
a.recycle()
}
override fun onClick() {
super.onClick()
if (onShowDialogListener != null) {
onShowDialogListener!!.onShowColorPickerDialog(title as String, color)
} else if (showDialog) {
val dialog = ColorPickerDialogCompat.newBuilder()
.setDialogType(dialogType)
.setDialogTitle(dialogTitle)
.setColorShape(colorShape)
.setPresets(presets!!)
.setAllowPresets(allowPresets)
.setAllowCustom(allowCustom)
.setShowAlphaSlider(showAlphaSlider)
.setShowColorShades(showColorShades)
.setColor(color)
.create()
dialog.setColorPickerDialogListener(this)
getActivity().supportFragmentManager
.beginTransaction()
.add(dialog, getFragmentTag())
.commitAllowingStateLoss()
}
}
fun getActivity(): FragmentActivity {
val context = context
if (context is FragmentActivity) {
return context
} else if (context is ContextWrapper) {
val baseContext = context.baseContext
if (baseContext is FragmentActivity) {
return baseContext
}
}
throw IllegalStateException("Error getting activity from context")
}
override fun onAttached() {
super.onAttached()
if (showDialog) {
val fragment =
getActivity().supportFragmentManager.findFragmentByTag(getFragmentTag()) as ColorPickerDialog?
fragment?.setColorPickerDialogListener(this)
}
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val preview = holder.itemView.findViewById(R.id.cpv_preference_preview_color_panel) as ColorPanelView
preview.color = color
}
override fun onSetInitialValue(defaultValue: Any?) {
super.onSetInitialValue(defaultValue)
if (defaultValue is Int) {
color = (defaultValue as Int?)!!
persistInt(color)
} else {
color = getPersistedInt(-0x1000000)
}
}
override fun onGetDefaultValue(a: TypedArray?, index: Int): Any {
return a!!.getInteger(index, Color.BLACK)
}
override fun onColorSelected(dialogId: Int, @ColorInt color: Int) {
saveValue(color)
}
override fun onDialogDismissed(dialogId: Int) {
// no-op
}
/**
* Set the new color
*
* @param color The newly selected color
*/
fun saveValue(@ColorInt color: Int) {
this.color = color
persistInt(this.color)
notifyChanged()
callChangeListener(color)
}
/**
* Get the colors that will be shown in the [ColorPickerDialog].
*
* @return An array of color ints
*/
fun getPresets(): IntArray? {
return presets
}
/**
* Set the colors shown in the [ColorPickerDialog].
*
* @param presets An array of color ints
*/
fun setPresets(presets: IntArray) {
this.presets = presets
}
/**
* The listener used for showing the [ColorPickerDialog].
* Call [.saveValue] after the user chooses a color.
* If this is set then it is up to you to show the dialog.
*
* @param listener The listener to show the dialog
*/
fun setOnShowDialogListener(listener: OnShowDialogListener) {
onShowDialogListener = listener
}
/**
* The tag used for the [ColorPickerDialog].
*
* @return The tag
*/
fun getFragmentTag(): String {
return "color_$key"
}
interface OnShowDialogListener {
fun onShowColorPickerDialog(title: String, currentColor: Int)
}
internal class ColorPickerDialogCompat : ColorPickerDialog() {
override fun onStart() {
super.onStart()
val alertDialog = dialog as? AlertDialog
alertDialog?.let {
ATH.setAlertDialogTint(it)
}
}
companion object {
fun newBuilder(): Builder {
return Builder()
}
private const val ARG_ID = "id"
private const val ARG_TYPE = "dialogType"
private const val ARG_COLOR = "color"
private const val ARG_ALPHA = "alpha"
private const val ARG_PRESETS = "presets"
private const val ARG_ALLOW_PRESETS = "allowPresets"
private const val ARG_ALLOW_CUSTOM = "allowCustom"
private const val ARG_DIALOG_TITLE = "dialogTitle"
private const val ARG_SHOW_COLOR_SHADES = "showColorShades"
private const val ARG_COLOR_SHAPE = "colorShape"
private const val ARG_PRESETS_BUTTON_TEXT = "presetsButtonText"
private const val ARG_CUSTOM_BUTTON_TEXT = "customButtonText"
private const val ARG_SELECTED_BUTTON_TEXT = "selectedButtonText"
}
class Builder internal constructor() {
internal var colorPickerDialogListener: ColorPickerDialogListener? = null
@StringRes
internal var dialogTitle = R.string.cpv_default_title
@StringRes
internal var presetsButtonText = R.string.cpv_presets
@StringRes
internal var customButtonText = R.string.cpv_custom
@StringRes
internal var selectedButtonText = R.string.cpv_select
@DialogType
internal var dialogType = TYPE_PRESETS
internal var presets = MATERIAL_COLORS
@ColorInt
internal var color = Color.BLACK
internal var dialogId = 0
internal var showAlphaSlider = false
internal var allowPresets = true
internal var allowCustom = true
internal var showColorShades = true
@ColorShape
internal var colorShape = ColorShape.CIRCLE
/**
* Set the dialog title string resource id
*
* @param dialogTitle The string resource used for the dialog title
* @return This builder object for chaining method calls
*/
fun setDialogTitle(@StringRes dialogTitle: Int): Builder {
this.dialogTitle = dialogTitle
return this
}
/**
* Set the selected button text string resource id
*
* @param selectedButtonText The string resource used for the selected button text
* @return This builder object for chaining method calls
*/
fun setSelectedButtonText(@StringRes selectedButtonText: Int): Builder {
this.selectedButtonText = selectedButtonText
return this
}
/**
* Set the presets button text string resource id
*
* @param presetsButtonText The string resource used for the presets button text
* @return This builder object for chaining method calls
*/
fun setPresetsButtonText(@StringRes presetsButtonText: Int): Builder {
this.presetsButtonText = presetsButtonText
return this
}
/**
* Set the custom button text string resource id
*
* @param customButtonText The string resource used for the custom button text
* @return This builder object for chaining method calls
*/
fun setCustomButtonText(@StringRes customButtonText: Int): Builder {
this.customButtonText = customButtonText
return this
}
/**
* Set which dialog view to show.
*
* @param dialogType Either [ColorPickerDialog.TYPE_CUSTOM] or [ColorPickerDialog.TYPE_PRESETS].
* @return This builder object for chaining method calls
*/
fun setDialogType(@DialogType dialogType: Int): Builder {
this.dialogType = dialogType
return this
}
/**
* Set the colors used for the presets
*
* @param presets An array of color ints.
* @return This builder object for chaining method calls
*/
fun setPresets(presets: IntArray): Builder {
this.presets = presets
return this
}
/**
* Set the original color
*
* @param color The default color for the color picker
* @return This builder object for chaining method calls
*/
fun setColor(color: Int): Builder {
this.color = color
return this
}
/**
* Set the dialog id used for callbacks
*
* @param dialogId The id that is sent back to the [ColorPickerDialogListener].
* @return This builder object for chaining method calls
*/
fun setDialogId(dialogId: Int): Builder {
this.dialogId = dialogId
return this
}
/**
* Show the alpha slider
*
* @param showAlphaSlider `true` to show the alpha slider. Currently only supported with the [ ].
* @return This builder object for chaining method calls
*/
fun setShowAlphaSlider(showAlphaSlider: Boolean): Builder {
this.showAlphaSlider = showAlphaSlider
return this
}
/**
* Show/Hide a neutral button to select preset colors.
*
* @param allowPresets `false` to disable showing the presets button.
* @return This builder object for chaining method calls
*/
fun setAllowPresets(allowPresets: Boolean): Builder {
this.allowPresets = allowPresets
return this
}
/**
* Show/Hide the neutral button to select a custom color.
*
* @param allowCustom `false` to disable showing the custom button.
* @return This builder object for chaining method calls
*/
fun setAllowCustom(allowCustom: Boolean): Builder {
this.allowCustom = allowCustom
return this
}
/**
* Show/Hide the color shades in the presets picker
*
* @param showColorShades `false` to hide the color shades.
* @return This builder object for chaining method calls
*/
fun setShowColorShades(showColorShades: Boolean): Builder {
this.showColorShades = showColorShades
return this
}
/**
* Set the shape of the color panel view.
*
* @param colorShape Either [ColorShape.CIRCLE] or [ColorShape.SQUARE].
* @return This builder object for chaining method calls
*/
fun setColorShape(colorShape: Int): Builder {
this.colorShape = colorShape
return this
}
/**
* Create the [ColorPickerDialog] instance.
*
* @return A new [ColorPickerDialog].
* @see .show
*/
fun create(): ColorPickerDialog {
val dialog = ColorPickerDialogCompat()
val args = Bundle()
args.putInt(ARG_ID, dialogId)
args.putInt(ARG_TYPE, dialogType)
args.putInt(ARG_COLOR, color)
args.putIntArray(ARG_PRESETS, presets)
args.putBoolean(ARG_ALPHA, showAlphaSlider)
args.putBoolean(ARG_ALLOW_CUSTOM, allowCustom)
args.putBoolean(ARG_ALLOW_PRESETS, allowPresets)
args.putInt(ARG_DIALOG_TITLE, dialogTitle)
args.putBoolean(ARG_SHOW_COLOR_SHADES, showColorShades)
args.putInt(ARG_COLOR_SHAPE, colorShape)
args.putInt(ARG_PRESETS_BUTTON_TEXT, presetsButtonText)
args.putInt(ARG_CUSTOM_BUTTON_TEXT, customButtonText)
args.putInt(ARG_SELECTED_BUTTON_TEXT, selectedButtonText)
dialog.arguments = args
return dialog
}
/**
* Create and show the [ColorPickerDialog] created with this builder.
*
* @param activity The current activity.
*/
fun show(activity: FragmentActivity) {
create().show(activity.supportFragmentManager, "color-picker-dialog")
}
}
}
}

@ -0,0 +1,184 @@
package io.legado.app.lib.theme.prefs
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable
import android.preference.Preference
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.preference.EditTextPreference
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.upTint
class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextPreference(
context,
attrs
),
DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
private var builder: AlertDialog.Builder? = null
private var dialog: AlertDialog? = null
private var editText: EditText? = null
/** Which button was clicked. */
private var mWhichButtonClicked: Int = 0
override fun onClick() {
if (dialog != null && dialog!!.isShowing) return
showDialog(null)
}
protected fun showDialog(state: Bundle?) {
val context = context
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE
builder = AlertDialog.Builder(context)
.setTitle(dialogTitle)
.setIcon(dialogIcon)
.setPositiveButton(positiveButtonText, this)
.setNegativeButton(negativeButtonText, this)
val builder = this.builder!!
val contentView = onCreateDialogView()
if (contentView != null) {
onBindDialogView(contentView)
builder.setView(contentView)
} else {
builder.setMessage(dialogMessage)
}
// Create the dialog
dialog = builder.create()
val dialog = this.dialog!!
if (state != null) {
dialog.onRestoreInstanceState(state)
}
requestInputMethod(dialog)
dialog.setOnDismissListener(this)
dialog.show()
dialog.upTint()
}
protected fun onCreateDialogView(): View? {
if (dialogLayoutResource == 0) {
return null
}
val inflater = LayoutInflater.from(context)
return inflater.inflate(dialogLayoutResource, null)
}
private fun requestInputMethod(dialog: Dialog?) {
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
}
protected fun onBindDialogView(view: View) {
editText = view.findViewById(android.R.id.edit)
if (editText == null) {
throw IllegalStateException("Dialog view must contain an EditText with id" + " @android:id/edit")
}
view.findViewById<TextView>(android.R.id.message).visibility = View.GONE
val editText = this.editText!!
ATH.setTint(editText, ThemeStore.accentColor(context))
editText.requestFocus()
editText.setText(text)
// Place cursor at the end
editText.setSelection(editText.length())
}
override fun onClick(dialog: DialogInterface?, which: Int) {
mWhichButtonClicked = which
}
override fun onDismiss(dialog: DialogInterface?) {
onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE)
text = editText?.text.toString()
callChangeListener(text)
}
protected fun onDialogClosed(positiveResult: Boolean) {
}
override fun onSaveInstanceState(): Parcelable {
val superState = super.onSaveInstanceState()
if (dialog == null || !dialog!!.isShowing) {
return superState
}
val myState = SavedState(superState)
myState.isDialogShowing = true
myState.dialogBundle = dialog!!.onSaveInstanceState()
return myState
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state == null || state.javaClass != SavedState::class.java) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state)
return
}
val myState = state as SavedState?
super.onRestoreInstanceState(myState!!.superState)
if (myState.isDialogShowing) {
showDialog(myState.dialogBundle)
}
}
private class SavedState : Preference.BaseSavedState {
internal var isDialogShowing: Boolean = false
internal var dialogBundle: Bundle? = null
@SuppressLint("ParcelClassLoader")
constructor(source: Parcel) : super(source) {
isDialogShowing = source.readInt() == 1
dialogBundle = source.readBundle()
}
override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)
dest.writeInt(if (isDialogShowing) 1 else 0)
dest.writeBundle(dialogBundle)
}
constructor(superState: Parcelable) : super(superState) {}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(`in`: Parcel): SavedState {
return SavedState(`in`)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
}
}

@ -6,6 +6,7 @@ import android.os.Handler
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.jaredrummler.android.colorpicker.ColorPreferenceCompat
import com.jeremyliao.liveeventbus.LiveEventBus
import io.legado.app.App
import io.legado.app.R

@ -23,7 +23,6 @@ import io.legado.app.ui.bookshelf.BookshelfActivity
import io.legado.app.ui.search.SearchActivity
import io.legado.app.utils.disableAutoFill
import kotlinx.android.synthetic.main.fragment_bookshelf.*
import kotlinx.android.synthetic.main.fragment_find_book.*
import kotlinx.android.synthetic.main.view_title_bar.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch

@ -33,7 +33,7 @@
android:title="白天"
app:iconSpaceReserved="false">
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/colorPrimary"
android:key="colorPrimary"
android:summary="白天,主色调"
@ -41,7 +41,7 @@
app:cpv_dialogType="preset"
app:iconSpaceReserved="false" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/colorAccent"
android:key="colorAccent"
android:summary="白天,强调色"
@ -49,7 +49,7 @@
app:cpv_dialogType="preset"
app:iconSpaceReserved="false" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/md_grey_100"
android:key="colorBackground"
android:summary="白天,背景色"
@ -63,7 +63,7 @@
android:title="夜间"
app:iconSpaceReserved="false">
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/colorPrimary"
android:key="colorPrimaryNight"
android:summary="夜间,主色调"
@ -71,7 +71,7 @@
app:cpv_dialogType="preset"
app:iconSpaceReserved="false" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/colorAccent"
android:key="colorAccentNight"
android:summary="夜间,强调色"
@ -79,7 +79,7 @@
app:cpv_dialogType="preset"
app:iconSpaceReserved="false" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
<io.legado.app.lib.theme.prefs.ATEColorPreference
android:defaultValue="@color/md_grey_800"
android:key="colorBackgroundNight"
android:summary="夜间,背景色"

@ -2,21 +2,21 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.preference.EditTextPreference
<io.legado.app.lib.theme.prefs.ATEEditTextPreference
android:key="web_dav_url"
android:title="WebDav 服务器地址"
android:summary="输入你的服务器地址"
android:singleLine="true"
app:iconSpaceReserved="false" />
<androidx.preference.EditTextPreference
<io.legado.app.lib.theme.prefs.ATEEditTextPreference
android:key="web_dav_account"
android:title="WebDav 账号"
android:summary="输入你的WebDav账号"
android:singleLine="true"
app:iconSpaceReserved="false" />
<androidx.preference.EditTextPreference
<io.legado.app.lib.theme.prefs.ATEEditTextPreference
android:key="web_dav_password"
android:title="WebDav 密码"
android:summary="输入你的WebDav授权密码"

Loading…
Cancel
Save