Theme View

This commit is contained in:
GKF 2019-05-30 16:16:11 +08:00
parent f87efa47ca
commit 369663073e
23 changed files with 798 additions and 1 deletions

View File

@ -0,0 +1,36 @@
package io.legado.app.lib.theme.prefs
import android.content.Context
import android.os.Build
import android.preference.PreferenceCategory
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
import androidx.annotation.RequiresApi
import io.legado.app.lib.theme.ThemeStore
class ATEPreferenceCategory : PreferenceCategory {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context) : super(context)
override fun onBindView(view: View) {
super.onBindView(view)
if (view is TextView) {
view.setTextColor(ThemeStore.accentColor(view.getContext()))//设置title文本的颜色
}
}
}

View File

@ -0,0 +1,52 @@
package io.legado.app.lib.theme.prefs
import android.content.Context
import android.os.Build
import android.preference.SwitchPreference
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import androidx.annotation.RequiresApi
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
import java.util.*
class ATESwitchPreference : SwitchPreference {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context) : super(context)
override fun onBindView(view: View) {
super.onBindView(view)
if (view is ViewGroup) {
val queue = LinkedList<ViewGroup>()
queue.add(view)
while (!queue.isEmpty()) {
val current = queue.removeFirst()
for (i in 0 until current.childCount) {
if (current.getChildAt(i) is Switch) {
ATH.setTint(current.getChildAt(i), ThemeStore.accentColor(view.getContext()))
return
} else if (current.getChildAt(i) is ViewGroup) {
queue.addLast(current.getChildAt(i) as ViewGroup)
}
}
}
}
}
}

View File

@ -0,0 +1,95 @@
package io.legado.app.lib.theme.prefs
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog.Builder
import android.content.Context
import android.graphics.drawable.Drawable
import android.preference.ListPreference
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.CheckedTextView
import android.widget.ImageView
import android.widget.ListAdapter
import io.legado.app.R
import java.util.*
class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) {
private val mEntryDrawables = ArrayList<Drawable>()
init {
val a = context.theme.obtainStyledAttributes(attrs, R.styleable.IconListPreference, 0, 0)
val drawables: Array<CharSequence>
try {
drawables = a.getTextArray(R.styleable.IconListPreference_icons)
} finally {
a.recycle()
}
for (drawable in drawables) {
val resId = context.resources.getIdentifier(drawable.toString(), "mipmap", context.packageName)
val d = context.resources.getDrawable(resId)
mEntryDrawables.add(d)
}
widgetLayoutResource = R.layout.view_icon
}
protected fun createListAdapter(): ListAdapter {
val selectedValue = value
val selectedIndex = findIndexOfValue(selectedValue)
return AppArrayAdapter(context, R.layout.item_icon_preference, entries, mEntryDrawables, selectedIndex)
}
override fun onBindView(view: View) {
super.onBindView(view)
val selectedValue = value
val selectedIndex = findIndexOfValue(selectedValue)
val drawable = mEntryDrawables[selectedIndex]
(view.findViewById<View>(R.id.preview) as ImageView).setImageDrawable(drawable)
}
override fun onPrepareDialogBuilder(builder: Builder) {
builder.setAdapter(createListAdapter(), this)
super.onPrepareDialogBuilder(builder)
}
inner class AppArrayAdapter(
context: Context, textViewResourceId: Int,
objects: Array<CharSequence>, imageDrawables: List<Drawable>,
selectedIndex: Int
) : ArrayAdapter<CharSequence>(context, textViewResourceId, objects) {
private var mImageDrawables: List<Drawable>? = null
private var mSelectedIndex = 0
init {
mSelectedIndex = selectedIndex
mImageDrawables = imageDrawables
}
@SuppressLint("ViewHolder")
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater = (context as Activity).layoutInflater
val view = inflater.inflate(R.layout.item_icon_preference, parent, false)
val textView = view.findViewById<View>(R.id.label) as CheckedTextView
textView.text = getItem(position)
textView.isChecked = position == mSelectedIndex
val imageView = view.findViewById<View>(R.id.icon) as ImageView
imageView.setImageDrawable(mImageDrawables!![position])
return view
}
}
}

View File

@ -0,0 +1,33 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.lib.theme.ColorUtil
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.dp
class ATEAccentBgTextView : AppCompatTextView {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
background = Selector.shapeBuild()
.setCornerRadius(3.dp)
.setDefaultBgColor(ThemeStore.accentColor(context))
.setPressedBgColor(ColorUtil.darkenColor(ThemeStore.accentColor(context)))
.create()
setTextColor(Color.WHITE)
}
}

View File

@ -0,0 +1,39 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.R
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.dp
class ATEAccentStrokeTextView : AppCompatTextView {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
background = Selector.shapeBuild()
.setCornerRadius(3.dp)
.setStrokeWidth(1.dp)
.setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500))
.setDefaultStrokeColor(ThemeStore.accentColor(context))
.setPressedBgColor(context.resources.getColor(R.color.transparent30))
.create()
setTextColor(
Selector.colorBuild()
.setDefaultColor(ThemeStore.accentColor(context))
.setDisabledColor(context.resources.getColor(R.color.md_grey_500))
.create()
)
}
}

View File

@ -0,0 +1,33 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatAutoCompleteTextView
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView {
constructor(context: Context) : super(context) {
init(context)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context)
}
private fun init(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
backgroundTintList = Selector.colorBuild()
.setFocusedColor(ThemeStore.accentColor(context))
.setDefaultColor(ThemeStore.textColorPrimary(context))
.create()
}
}
}

View File

@ -0,0 +1,29 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatCheckBox
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATECheckBox : AppCompatCheckBox {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
}

View File

@ -0,0 +1,29 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatEditText
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATEEditText : AppCompatEditText {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
}

View File

@ -0,0 +1,28 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATEPrimaryTextView : AppCompatTextView {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
setTextColor(ThemeStore.textColorPrimary(context))
}
}

View File

@ -0,0 +1,41 @@
package io.legado.app.lib.theme.view
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.ProgressBar
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATEProgressBar : ProgressBar {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
}

View File

@ -0,0 +1,29 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatRadioButton
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATERadioButton : AppCompatRadioButton {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
}

View File

@ -0,0 +1,37 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatRadioButton
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.dp
/**
* @author Aidan Follestad (afollestad)
*/
class ATERadioNoButton : AppCompatRadioButton {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
background = Selector.shapeBuild()
.setCornerRadius(3.dp)
.setStrokeWidth(3.dp)
.setCheckedBgColor(ThemeStore.accentColor(context))
.setCheckedStrokeColor(ThemeStore.accentColor(context))
.setDefaultStrokeColor(Color.WHITE)
.create()
}
}

View File

@ -0,0 +1,28 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATESecondaryTextView : AppCompatTextView {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
setTextColor(ThemeStore.textColorSecondary(context))
}
}

View File

@ -0,0 +1,29 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatSeekBar
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATESeekBar : AppCompatSeekBar {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
}

View File

@ -0,0 +1,34 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Switch
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATEStockSwitch : Switch {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
override fun isShown(): Boolean {
return parent != null && visibility == View.VISIBLE
}
}

View File

@ -0,0 +1,41 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.R
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.dp
class ATEStrokeTextView : AppCompatTextView {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
background = Selector.shapeBuild()
.setCornerRadius(1.dp)
.setStrokeWidth(1.dp)
.setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500))
.setDefaultStrokeColor(ThemeStore.textColorSecondary(context))
.setSelectedStrokeColor(ThemeStore.accentColor(context))
.setPressedBgColor(context.resources.getColor(R.color.transparent30))
.create()
setTextColor(
Selector.colorBuild()
.setDefaultColor(ThemeStore.textColorSecondary(context))
.setSelectedColor(ThemeStore.accentColor(context))
.setDisabledColor(context.resources.getColor(R.color.md_grey_500))
.create()
)
}
}

View File

@ -0,0 +1,34 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Switch
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATESwitch : Switch {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
override fun isShown(): Boolean {
return parent != null && visibility == View.VISIBLE
}
}

View File

@ -0,0 +1,31 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.google.android.material.textfield.TextInputLayout
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
class ATETextInputLayout : TextInputLayout {
constructor(context: Context) : super(context) {
init(context)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context)
}
private fun init(context: Context) {
defaultHintTextColor = Selector.colorBuild().setDefaultColor(ThemeStore.accentColor(context)).create()
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
}
}

View File

@ -0,0 +1,16 @@
package io.legado.app.utils
import android.content.res.Resources
val Float.dp: Float // [xxhdpi](360 -> 1080)
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics
)
val Float.sp: Float // [xxhdpi](360 -> 1080)
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_SP, this, Resources.getSystem().displayMetrics
)

View File

@ -0,0 +1,13 @@
package io.legado.app.utils
import android.content.res.Resources
val Int.dp: Int
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
).toInt()
val Int.sp: Int
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics
).toInt()

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:padding="6dip"/>
<CheckedTextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_toRightOf="@+id/icon"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorAlertDialogListItem"
android:textIsSelectable="false"
tools:ignore="RtlHardcoded"/>
</RelativeLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView android:id="@+id/preview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="48dp"
android:layout_height="48dp"/>

View File

@ -44,5 +44,59 @@
<attr name="emptyActionDescription" format="string|reference" />
<attr name="emptyDescription" format="string|reference" />
</declare-styleable>
<declare-styleable name="RefreshProgressBar">
<attr name="max_progress" format="integer"/>
<attr name="dur_progress" format="integer"/>
<attr name="second_dur_progress" format="dimension"/>
<attr name="second_max_progress" format="dimension"/>
<attr name="bg_color" format="color"/>
<attr name="second_color" format="color"/>
<attr name="font_color" format="color"/>
<attr name="speed" format="dimension"/>
</declare-styleable>
<declare-styleable name="SmoothCheckBox">
<attr name="duration" format="integer"/>
<attr name="stroke_width" format="dimension"/>
<attr name="color_tick" format="color"/>
<attr name="color_checked" format="color"/>
<attr name="color_unchecked" format="color"/>
<attr name="color_unchecked_stroke" format="color"/>
</declare-styleable>
<declare-styleable name="NumberPickerPreference">
<attr name="MinValue" format="integer"/>
<attr name="MaxValue" format="integer"/>
<attr name="android:summary"/>
</declare-styleable>
<declare-styleable name="RefreshLayout">
<attr name="layout_refresh_empty" format="reference"/>
<attr name="layout_refresh_error" format="reference"/>
<attr name="layout_refresh_loading" format="reference"/>
</declare-styleable>
<declare-styleable name="FastScroller">
<attr name="fadeScrollbar" format="boolean"/>
<attr name="showBubble" format="boolean"/>
<attr name="showTrack" format="boolean"/>
<attr name="trackColor" format="color"/>
<attr name="handleColor" format="color"/>
<attr name="bubbleColor" format="color"/>
<attr name="bubbleTextColor" format="color"/>
</declare-styleable>
<declare-styleable name="FilletImageView">
<attr name="radius" format="dimension"/>
<attr name="left_top_radius" format="dimension"/>
<attr name="right_top_radius" format="dimension"/>
<attr name="right_bottom_radius" format="dimension"/>
<attr name="left_bottom_radius" format="dimension"/>
</declare-styleable>
<declare-styleable name="IconListPreference">
<attr name="icons" format="reference"/>
</declare-styleable>
</resources>