parent
e29e6fcbaa
commit
9cd970ccc1
@ -1,118 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.annotation.SuppressLint; |
|
||||||
import android.app.Activity; |
|
||||||
import android.app.ActivityManager; |
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.ColorStateList; |
|
||||||
import android.os.Build; |
|
||||||
import android.view.View; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.appcompat.app.AlertDialog; |
|
||||||
|
|
||||||
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class ATH { |
|
||||||
|
|
||||||
@SuppressLint("CommitPrefEdits") |
|
||||||
public static boolean didThemeValuesChange(@NonNull Context context, long since) { |
|
||||||
return ThemeStore.isConfigured(context) && ThemeStore.prefs(context).getLong(ThemeStore.VALUES_CHANGED, -1) > since; |
|
||||||
} |
|
||||||
|
|
||||||
public static void setStatusbarColorAuto(Activity activity) { |
|
||||||
setStatusbarColor(activity, ThemeStore.statusBarColor(activity)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setStatusbarColor(Activity activity, int color) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
activity.getWindow().setStatusBarColor(color); |
|
||||||
setLightStatusbarAuto(activity, color); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setLightStatusbarAuto(Activity activity, int bgColor) { |
|
||||||
setLightStatusbar(activity, ColorUtil.isColorLight(bgColor)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setLightStatusbar(Activity activity, boolean enabled) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
|
||||||
final View decorView = activity.getWindow().getDecorView(); |
|
||||||
final int systemUiVisibility = decorView.getSystemUiVisibility(); |
|
||||||
if (enabled) { |
|
||||||
decorView.setSystemUiVisibility(systemUiVisibility | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); |
|
||||||
} else { |
|
||||||
decorView.setSystemUiVisibility(systemUiVisibility & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setLightNavigationbar(Activity activity, boolean enabled) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|
||||||
final View decorView = activity.getWindow().getDecorView(); |
|
||||||
int systemUiVisibility = decorView.getSystemUiVisibility(); |
|
||||||
if (enabled) { |
|
||||||
systemUiVisibility |= SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; |
|
||||||
} else { |
|
||||||
systemUiVisibility &= ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; |
|
||||||
} |
|
||||||
decorView.setSystemUiVisibility(systemUiVisibility); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setLightNavigationbarAuto(Activity activity, int bgColor) { |
|
||||||
setLightNavigationbar(activity, ColorUtil.isColorLight(bgColor)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setNavigationbarColorAuto(Activity activity) { |
|
||||||
setNavigationbarColor(activity, ThemeStore.navigationBarColor(activity)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setNavigationbarColor(Activity activity, int color) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
activity.getWindow().setNavigationBarColor(color); |
|
||||||
setLightNavigationbarAuto(activity, color); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTaskDescriptionColorAuto(@NonNull Activity activity) { |
|
||||||
setTaskDescriptionColor(activity, ThemeStore.primaryColor(activity)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTaskDescriptionColor(@NonNull Activity activity, @ColorInt int color) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
// Task description requires fully opaque color
|
|
||||||
color = ColorUtil.stripAlpha(color); |
|
||||||
// Sets color of entry in the system recents page
|
|
||||||
activity.setTaskDescription(new ActivityManager.TaskDescription((String) activity.getTitle(), null, color)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull View view, @ColorInt int color) { |
|
||||||
TintHelper.setTintAuto(view, color, false); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setBackgroundTint(@NonNull View view, @ColorInt int color) { |
|
||||||
TintHelper.setTintAuto(view, color, true); |
|
||||||
} |
|
||||||
|
|
||||||
public static AlertDialog setAlertDialogTint(@NonNull AlertDialog dialog) { |
|
||||||
ColorStateList colorStateList = Selector.colorBuild() |
|
||||||
.setDefaultColor(ThemeStore.accentColor(dialog.getContext())) |
|
||||||
.setPressedColor(ColorUtil.darkenColor(ThemeStore.accentColor(dialog.getContext()))) |
|
||||||
.create(); |
|
||||||
if (dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEGATIVE) != null) { |
|
||||||
dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEGATIVE).setTextColor(colorStateList); |
|
||||||
} |
|
||||||
if (dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE) != null) { |
|
||||||
dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setTextColor(colorStateList); |
|
||||||
} |
|
||||||
return dialog; |
|
||||||
} |
|
||||||
|
|
||||||
private ATH() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,116 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.app.Activity |
||||||
|
import android.app.ActivityManager |
||||||
|
import android.content.Context |
||||||
|
import android.os.Build |
||||||
|
import android.view.View |
||||||
|
import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.appcompat.app.AlertDialog |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
object ATH { |
||||||
|
|
||||||
|
@SuppressLint("CommitPrefEdits") |
||||||
|
fun didThemeValuesChange(context: Context, since: Long): Boolean { |
||||||
|
return ThemeStore.isConfigured(context) && ThemeStore.prefs(context).getLong( |
||||||
|
ThemeStore.VALUES_CHANGED, |
||||||
|
-1 |
||||||
|
) > since |
||||||
|
} |
||||||
|
|
||||||
|
fun setStatusbarColorAuto(activity: Activity) { |
||||||
|
setStatusbarColor(activity, ThemeStore.statusBarColor(activity)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setStatusbarColor(activity: Activity, color: Int) { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
activity.window.statusBarColor = color |
||||||
|
setLightStatusbarAuto(activity, color) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setLightStatusbarAuto(activity: Activity, bgColor: Int) { |
||||||
|
setLightStatusbar(activity, ColorUtil.isColorLight(bgColor)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setLightStatusbar(activity: Activity, enabled: Boolean) { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||||
|
val decorView = activity.window.decorView |
||||||
|
val systemUiVisibility = decorView.systemUiVisibility |
||||||
|
if (enabled) { |
||||||
|
decorView.systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR |
||||||
|
} else { |
||||||
|
decorView.systemUiVisibility = systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setLightNavigationbar(activity: Activity, enabled: Boolean) { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||||
|
val decorView = activity.window.decorView |
||||||
|
var systemUiVisibility = decorView.systemUiVisibility |
||||||
|
if (enabled) { |
||||||
|
systemUiVisibility = systemUiVisibility or SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
||||||
|
} else { |
||||||
|
systemUiVisibility = systemUiVisibility and SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() |
||||||
|
} |
||||||
|
decorView.systemUiVisibility = systemUiVisibility |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setLightNavigationbarAuto(activity: Activity, bgColor: Int) { |
||||||
|
setLightNavigationbar(activity, ColorUtil.isColorLight(bgColor)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setNavigationbarColorAuto(activity: Activity) { |
||||||
|
setNavigationbarColor(activity, ThemeStore.navigationBarColor(activity)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setNavigationbarColor(activity: Activity, color: Int) { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
activity.window.navigationBarColor = color |
||||||
|
setLightNavigationbarAuto(activity, color) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTaskDescriptionColorAuto(activity: Activity) { |
||||||
|
setTaskDescriptionColor(activity, ThemeStore.primaryColor(activity)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setTaskDescriptionColor(activity: Activity, @ColorInt color: Int) { |
||||||
|
val color1: Int |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
// Task description requires fully opaque color |
||||||
|
color1 = ColorUtil.stripAlpha(color) |
||||||
|
// Sets color of entry in the system recents page |
||||||
|
activity.setTaskDescription(ActivityManager.TaskDescription(activity.title as String, null, color1)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(view: View, @ColorInt color: Int) { |
||||||
|
TintHelper.setTintAuto(view, color, false) |
||||||
|
} |
||||||
|
|
||||||
|
fun setBackgroundTint(view: View, @ColorInt color: Int) { |
||||||
|
TintHelper.setTintAuto(view, color, true) |
||||||
|
} |
||||||
|
|
||||||
|
fun setAlertDialogTint(dialog: AlertDialog): AlertDialog { |
||||||
|
val colorStateList = Selector.colorBuild() |
||||||
|
.setDefaultColor(ThemeStore.accentColor(dialog.context)) |
||||||
|
.setPressedColor(ColorUtil.darkenColor(ThemeStore.accentColor(dialog.context))) |
||||||
|
.create() |
||||||
|
if (dialog.getButton(AlertDialog.BUTTON_NEGATIVE) != null) { |
||||||
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(colorStateList) |
||||||
|
} |
||||||
|
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) { |
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(colorStateList) |
||||||
|
} |
||||||
|
return dialog |
||||||
|
} |
||||||
|
} |
@ -1,31 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.TypedArray; |
|
||||||
import androidx.annotation.AttrRes; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Aidan Follestad (afollestad) |
|
||||||
*/ |
|
||||||
public final class ATHUtil { |
|
||||||
|
|
||||||
public static boolean isWindowBackgroundDark(Context context) { |
|
||||||
return !ColorUtil.isColorLight(ATHUtil.resolveColor(context, android.R.attr.windowBackground)); |
|
||||||
} |
|
||||||
|
|
||||||
public static int resolveColor(Context context, @AttrRes int attr) { |
|
||||||
return resolveColor(context, attr, 0); |
|
||||||
} |
|
||||||
|
|
||||||
public static int resolveColor(Context context, @AttrRes int attr, int fallback) { |
|
||||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
|
||||||
try { |
|
||||||
return a.getColor(0, fallback); |
|
||||||
} finally { |
|
||||||
a.recycle(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private ATHUtil() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,24 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import androidx.annotation.AttrRes |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Aidan Follestad (afollestad) |
||||||
|
*/ |
||||||
|
object ATHUtil { |
||||||
|
|
||||||
|
fun isWindowBackgroundDark(context: Context): Boolean { |
||||||
|
return !ColorUtil.isColorLight(ATHUtil.resolveColor(context, android.R.attr.windowBackground)) |
||||||
|
} |
||||||
|
|
||||||
|
@JvmOverloads |
||||||
|
fun resolveColor(context: Context, @AttrRes attr: Int, fallback: Int = 0): Int { |
||||||
|
val a = context.theme.obtainStyledAttributes(intArrayOf(attr)) |
||||||
|
try { |
||||||
|
return a.getColor(0, fallback) |
||||||
|
} finally { |
||||||
|
a.recycle() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,80 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.graphics.Color; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.FloatRange; |
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "WeakerAccess"}) |
|
||||||
public class ColorUtil { |
|
||||||
|
|
||||||
public static String intToString(int intColor) { |
|
||||||
return String.format("#%06X", 0xFFFFFF & intColor); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static int stripAlpha(@ColorInt int color) { |
|
||||||
return 0xff000000 | color; |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int shiftColor(@ColorInt int color, @FloatRange(from = 0.0f, to = 2.0f) float by) { |
|
||||||
if (by == 1f) return color; |
|
||||||
int alpha = Color.alpha(color); |
|
||||||
float[] hsv = new float[3]; |
|
||||||
Color.colorToHSV(color, hsv); |
|
||||||
hsv[2] *= by; // value component
|
|
||||||
return (alpha << 24) + (0x00ffffff & Color.HSVToColor(hsv)); |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int darkenColor(@ColorInt int color) { |
|
||||||
return shiftColor(color, 0.9f); |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int lightenColor(@ColorInt int color) { |
|
||||||
return shiftColor(color, 1.1f); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isColorLight(@ColorInt int color) { |
|
||||||
final double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; |
|
||||||
return darkness < 0.4; |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int invertColor(@ColorInt int color) { |
|
||||||
final int r = 255 - Color.red(color); |
|
||||||
final int g = 255 - Color.green(color); |
|
||||||
final int b = 255 - Color.blue(color); |
|
||||||
return Color.argb(Color.alpha(color), r, g, b); |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int adjustAlpha(@ColorInt int color, @FloatRange(from = 0.0, to = 1.0) float factor) { |
|
||||||
int alpha = Math.round(Color.alpha(color) * factor); |
|
||||||
int red = Color.red(color); |
|
||||||
int green = Color.green(color); |
|
||||||
int blue = Color.blue(color); |
|
||||||
return Color.argb(alpha, red, green, blue); |
|
||||||
} |
|
||||||
|
|
||||||
@ColorInt |
|
||||||
public static int withAlpha(@ColorInt int baseColor, @FloatRange(from = 0.0, to = 1.0) float alpha) { |
|
||||||
int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24; |
|
||||||
int rgb = 0x00ffffff & baseColor; |
|
||||||
return a + rgb; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Taken from CollapsingToolbarLayout's CollapsingTextHelper class. |
|
||||||
*/ |
|
||||||
public static int blendColors(int color1, int color2, @FloatRange(from = 0.0, to = 1.0) float ratio) { |
|
||||||
final float inverseRatio = 1f - ratio; |
|
||||||
float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio); |
|
||||||
float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio); |
|
||||||
float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio); |
|
||||||
float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio); |
|
||||||
return Color.argb((int) a, (int) r, (int) g, (int) b); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,79 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.graphics.Color |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.annotation.FloatRange |
||||||
|
|
||||||
|
object ColorUtil { |
||||||
|
|
||||||
|
fun intToString(intColor: Int): String { |
||||||
|
return String.format("#%06X", 0xFFFFFF and intColor) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
fun stripAlpha(@ColorInt color: Int): Int { |
||||||
|
return -0x1000000 or color |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun shiftColor(@ColorInt color: Int, @FloatRange(from = 0.0, to = 2.0) by: Float): Int { |
||||||
|
if (by == 1f) return color |
||||||
|
val alpha = Color.alpha(color) |
||||||
|
val hsv = FloatArray(3) |
||||||
|
Color.colorToHSV(color, hsv) |
||||||
|
hsv[2] *= by // value component |
||||||
|
return (alpha shl 24) + (0x00ffffff and Color.HSVToColor(hsv)) |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun darkenColor(@ColorInt color: Int): Int { |
||||||
|
return shiftColor(color, 0.9f) |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun lightenColor(@ColorInt color: Int): Int { |
||||||
|
return shiftColor(color, 1.1f) |
||||||
|
} |
||||||
|
|
||||||
|
fun isColorLight(@ColorInt color: Int): Boolean { |
||||||
|
val darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 |
||||||
|
return darkness < 0.4 |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun invertColor(@ColorInt color: Int): Int { |
||||||
|
val r = 255 - Color.red(color) |
||||||
|
val g = 255 - Color.green(color) |
||||||
|
val b = 255 - Color.blue(color) |
||||||
|
return Color.argb(Color.alpha(color), r, g, b) |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun adjustAlpha(@ColorInt color: Int, @FloatRange(from = 0.0, to = 1.0) factor: Float): Int { |
||||||
|
val alpha = Math.round(Color.alpha(color) * factor) |
||||||
|
val red = Color.red(color) |
||||||
|
val green = Color.green(color) |
||||||
|
val blue = Color.blue(color) |
||||||
|
return Color.argb(alpha, red, green, blue) |
||||||
|
} |
||||||
|
|
||||||
|
@ColorInt |
||||||
|
fun withAlpha(@ColorInt baseColor: Int, @FloatRange(from = 0.0, to = 1.0) alpha: Float): Int { |
||||||
|
val a = Math.min(255, Math.max(0, (alpha * 255).toInt())) shl 24 |
||||||
|
val rgb = 0x00ffffff and baseColor |
||||||
|
return a + rgb |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Taken from CollapsingToolbarLayout's CollapsingTextHelper class. |
||||||
|
*/ |
||||||
|
fun blendColors(color1: Int, color2: Int, @FloatRange(from = 0.0, to = 1.0) ratio: Float): Int { |
||||||
|
val inverseRatio = 1f - ratio |
||||||
|
val a = Color.alpha(color1) * inverseRatio + Color.alpha(color2) * ratio |
||||||
|
val r = Color.red(color1) * inverseRatio + Color.red(color2) * ratio |
||||||
|
val g = Color.green(color1) * inverseRatio + Color.green(color2) * ratio |
||||||
|
val b = Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio |
||||||
|
return Color.argb(a.toInt(), r.toInt(), g.toInt(), b.toInt()) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,28 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.graphics.drawable.ColorDrawable; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.graphics.drawable.TransitionDrawable; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class DrawableUtil { |
|
||||||
|
|
||||||
public static TransitionDrawable createTransitionDrawable(@ColorInt int startColor, @ColorInt int endColor) { |
|
||||||
return createTransitionDrawable(new ColorDrawable(startColor), new ColorDrawable(endColor)); |
|
||||||
} |
|
||||||
|
|
||||||
public static TransitionDrawable createTransitionDrawable(Drawable start, Drawable end) { |
|
||||||
final Drawable[] drawables = new Drawable[2]; |
|
||||||
|
|
||||||
drawables[0] = start; |
|
||||||
drawables[1] = end; |
|
||||||
|
|
||||||
return new TransitionDrawable(drawables); |
|
||||||
} |
|
||||||
|
|
||||||
private DrawableUtil() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,25 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.graphics.drawable.ColorDrawable |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.graphics.drawable.TransitionDrawable |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
object DrawableUtil { |
||||||
|
|
||||||
|
fun createTransitionDrawable(@ColorInt startColor: Int, @ColorInt endColor: Int): TransitionDrawable { |
||||||
|
return createTransitionDrawable(ColorDrawable(startColor), ColorDrawable(endColor)) |
||||||
|
} |
||||||
|
|
||||||
|
fun createTransitionDrawable(start: Drawable, end: Drawable): TransitionDrawable { |
||||||
|
val drawables = arrayOfNulls<Drawable>(2) |
||||||
|
|
||||||
|
drawables[0] = start |
||||||
|
drawables[1] = end |
||||||
|
|
||||||
|
return TransitionDrawable(drawables) |
||||||
|
} |
||||||
|
} |
@ -1,52 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.annotation.SuppressLint; |
|
||||||
import android.content.Context; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.core.content.ContextCompat; |
|
||||||
import io.legado.app.R; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class MaterialValueHelper { |
|
||||||
|
|
||||||
@SuppressLint("PrivateResource") |
|
||||||
@ColorInt |
|
||||||
public static int getPrimaryTextColor(final Context context, boolean dark) { |
|
||||||
if (dark) { |
|
||||||
return ContextCompat.getColor(context, R.color.primary_text_default_material_light); |
|
||||||
} |
|
||||||
return ContextCompat.getColor(context, R.color.primary_text_default_material_dark); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressLint("PrivateResource") |
|
||||||
@ColorInt |
|
||||||
public static int getSecondaryTextColor(final Context context, boolean dark) { |
|
||||||
if (dark) { |
|
||||||
return ContextCompat.getColor(context, R.color.secondary_text_default_material_light); |
|
||||||
} |
|
||||||
return ContextCompat.getColor(context, R.color.secondary_text_default_material_dark); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressLint("PrivateResource") |
|
||||||
@ColorInt |
|
||||||
public static int getPrimaryDisabledTextColor(final Context context, boolean dark) { |
|
||||||
if (dark) { |
|
||||||
return ContextCompat.getColor(context, R.color.primary_text_disabled_material_light); |
|
||||||
} |
|
||||||
return ContextCompat.getColor(context, R.color.primary_text_disabled_material_dark); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressLint("PrivateResource") |
|
||||||
@ColorInt |
|
||||||
public static int getSecondaryDisabledTextColor(final Context context, boolean dark) { |
|
||||||
if (dark) { |
|
||||||
return ContextCompat.getColor(context, R.color.secondary_text_disabled_material_light); |
|
||||||
} |
|
||||||
return ContextCompat.getColor(context, R.color.secondary_text_disabled_material_dark); |
|
||||||
} |
|
||||||
|
|
||||||
private MaterialValueHelper() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,45 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.content.Context |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import io.legado.app.R |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
object MaterialValueHelper { |
||||||
|
|
||||||
|
@SuppressLint("PrivateResource") |
||||||
|
@ColorInt |
||||||
|
fun getPrimaryTextColor(context: Context, dark: Boolean): Int { |
||||||
|
return if (dark) { |
||||||
|
ContextCompat.getColor(context, R.color.primary_text_default_material_light) |
||||||
|
} else ContextCompat.getColor(context, R.color.primary_text_default_material_dark) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("PrivateResource") |
||||||
|
@ColorInt |
||||||
|
fun getSecondaryTextColor(context: Context, dark: Boolean): Int { |
||||||
|
return if (dark) { |
||||||
|
ContextCompat.getColor(context, R.color.secondary_text_default_material_light) |
||||||
|
} else ContextCompat.getColor(context, R.color.secondary_text_default_material_dark) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("PrivateResource") |
||||||
|
@ColorInt |
||||||
|
fun getPrimaryDisabledTextColor(context: Context, dark: Boolean): Int { |
||||||
|
return if (dark) { |
||||||
|
ContextCompat.getColor(context, R.color.primary_text_disabled_material_light) |
||||||
|
} else ContextCompat.getColor(context, R.color.primary_text_disabled_material_dark) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("PrivateResource") |
||||||
|
@ColorInt |
||||||
|
fun getSecondaryDisabledTextColor(context: Context, dark: Boolean): Int { |
||||||
|
return if (dark) { |
||||||
|
ContextCompat.getColor(context, R.color.secondary_text_disabled_material_light) |
||||||
|
} else ContextCompat.getColor(context, R.color.secondary_text_disabled_material_dark) |
||||||
|
} |
||||||
|
} |
@ -1,55 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.content.res.ColorStateList; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import com.google.android.material.internal.NavigationMenuView; |
|
||||||
import com.google.android.material.navigation.NavigationView; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class NavigationViewUtil { |
|
||||||
|
|
||||||
public static void setItemIconColors(@NonNull NavigationView navigationView, @ColorInt int normalColor, @ColorInt int selectedColor) { |
|
||||||
final ColorStateList iconSl = new ColorStateList( |
|
||||||
new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_checked} |
|
||||||
}, |
|
||||||
new int[]{ |
|
||||||
normalColor, |
|
||||||
selectedColor |
|
||||||
}); |
|
||||||
navigationView.setItemIconTintList(iconSl); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setItemTextColors(@NonNull NavigationView navigationView, @ColorInt int normalColor, @ColorInt int selectedColor) { |
|
||||||
final ColorStateList textSl = new ColorStateList( |
|
||||||
new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_checked} |
|
||||||
}, |
|
||||||
new int[]{ |
|
||||||
normalColor, |
|
||||||
selectedColor |
|
||||||
}); |
|
||||||
navigationView.setItemTextColor(textSl); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 去掉navigationView的滚动条 |
|
||||||
* @param navigationView NavigationView |
|
||||||
*/ |
|
||||||
public static void disableScrollbar(NavigationView navigationView) { |
|
||||||
if (navigationView != null) { |
|
||||||
NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView.getChildAt(0); |
|
||||||
if (navigationMenuView != null) { |
|
||||||
navigationMenuView.setVerticalScrollBarEnabled(false); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private NavigationViewUtil() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,38 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.content.res.ColorStateList |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import com.google.android.material.internal.NavigationMenuView |
||||||
|
import com.google.android.material.navigation.NavigationView |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
object NavigationViewUtil { |
||||||
|
|
||||||
|
fun setItemIconColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) { |
||||||
|
val iconSl = ColorStateList( |
||||||
|
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)), |
||||||
|
intArrayOf(normalColor, selectedColor) |
||||||
|
) |
||||||
|
navigationView.itemIconTintList = iconSl |
||||||
|
} |
||||||
|
|
||||||
|
fun setItemTextColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) { |
||||||
|
val textSl = ColorStateList( |
||||||
|
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)), |
||||||
|
intArrayOf(normalColor, selectedColor) |
||||||
|
) |
||||||
|
navigationView.itemTextColor = textSl |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 去掉navigationView的滚动条 |
||||||
|
* @param navigationView NavigationView |
||||||
|
*/ |
||||||
|
fun disableScrollbar(navigationView: NavigationView?) { |
||||||
|
navigationView ?: return |
||||||
|
val navigationMenuView = navigationView.getChildAt(0) as? NavigationMenuView |
||||||
|
navigationMenuView?.isVerticalScrollBarEnabled = false |
||||||
|
} |
||||||
|
} |
@ -1,430 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.ColorStateList; |
|
||||||
import android.graphics.Color; |
|
||||||
import android.graphics.drawable.ColorDrawable; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.graphics.drawable.GradientDrawable; |
|
||||||
import android.graphics.drawable.StateListDrawable; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.Dimension; |
|
||||||
import androidx.annotation.DrawableRes; |
|
||||||
import androidx.annotation.IntDef; |
|
||||||
import androidx.core.content.ContextCompat; |
|
||||||
|
|
||||||
public class Selector { |
|
||||||
public static ShapeSelector shapeBuild() { |
|
||||||
return new ShapeSelector(); |
|
||||||
} |
|
||||||
|
|
||||||
public static ColorSelector colorBuild() { |
|
||||||
return new ColorSelector(); |
|
||||||
} |
|
||||||
|
|
||||||
public static DrawableSelector drawableBuild() { |
|
||||||
return new DrawableSelector(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 形状ShapeSelector |
|
||||||
* |
|
||||||
* @author hjy |
|
||||||
* created at 2017/12/11 22:26 |
|
||||||
*/ |
|
||||||
public static final class ShapeSelector { |
|
||||||
@IntDef({GradientDrawable.RECTANGLE, GradientDrawable.OVAL, |
|
||||||
GradientDrawable.LINE, GradientDrawable.RING}) |
|
||||||
private @interface Shape { |
|
||||||
} |
|
||||||
|
|
||||||
private int mShape; //the shape of background
|
|
||||||
private int mDefaultBgColor; //default background color
|
|
||||||
private int mDisabledBgColor; //state_enabled = false
|
|
||||||
private int mPressedBgColor; //state_pressed = true
|
|
||||||
private int mSelectedBgColor; //state_selected = true
|
|
||||||
private int mFocusedBgColor; //state_focused = true
|
|
||||||
private int mCheckedBgColor; //state_checked = true
|
|
||||||
private int mStrokeWidth; //stroke width in pixel
|
|
||||||
private int mDefaultStrokeColor; //default stroke color
|
|
||||||
private int mDisabledStrokeColor; //state_enabled = false
|
|
||||||
private int mPressedStrokeColor; //state_pressed = true
|
|
||||||
private int mSelectedStrokeColor; //state_selected = true
|
|
||||||
private int mFocusedStrokeColor; //state_focused = true
|
|
||||||
private int mCheckedStrokeColor; //state_checked = true
|
|
||||||
private int mCornerRadius; //corner radius
|
|
||||||
|
|
||||||
private boolean hasSetDisabledBgColor = false; |
|
||||||
private boolean hasSetPressedBgColor = false; |
|
||||||
private boolean hasSetSelectedBgColor = false; |
|
||||||
private boolean hasSetFocusedBgColor = false; |
|
||||||
private boolean hasSetCheckedBgColor = false; |
|
||||||
|
|
||||||
private boolean hasSetDisabledStrokeColor = false; |
|
||||||
private boolean hasSetPressedStrokeColor = false; |
|
||||||
private boolean hasSetSelectedStrokeColor = false; |
|
||||||
private boolean hasSetFocusedStrokeColor = false; |
|
||||||
private boolean hasSetCheckedStrokeColor = false; |
|
||||||
|
|
||||||
public ShapeSelector() { |
|
||||||
//initialize default values
|
|
||||||
mShape = GradientDrawable.RECTANGLE; |
|
||||||
mDefaultBgColor = Color.TRANSPARENT; |
|
||||||
mDisabledBgColor = Color.TRANSPARENT; |
|
||||||
mPressedBgColor = Color.TRANSPARENT; |
|
||||||
mSelectedBgColor = Color.TRANSPARENT; |
|
||||||
mFocusedBgColor = Color.TRANSPARENT; |
|
||||||
mStrokeWidth = 0; |
|
||||||
mDefaultStrokeColor = Color.TRANSPARENT; |
|
||||||
mDisabledStrokeColor = Color.TRANSPARENT; |
|
||||||
mPressedStrokeColor = Color.TRANSPARENT; |
|
||||||
mSelectedStrokeColor = Color.TRANSPARENT; |
|
||||||
mFocusedStrokeColor = Color.TRANSPARENT; |
|
||||||
mCornerRadius = 0; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setShape(@Shape int shape) { |
|
||||||
mShape = shape; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setDefaultBgColor(@ColorInt int color) { |
|
||||||
mDefaultBgColor = color; |
|
||||||
if (!hasSetDisabledBgColor) |
|
||||||
mDisabledBgColor = color; |
|
||||||
if (!hasSetPressedBgColor) |
|
||||||
mPressedBgColor = color; |
|
||||||
if (!hasSetSelectedBgColor) |
|
||||||
mSelectedBgColor = color; |
|
||||||
if (!hasSetFocusedBgColor) |
|
||||||
mFocusedBgColor = color; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setDisabledBgColor(@ColorInt int color) { |
|
||||||
mDisabledBgColor = color; |
|
||||||
hasSetDisabledBgColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setPressedBgColor(@ColorInt int color) { |
|
||||||
mPressedBgColor = color; |
|
||||||
hasSetPressedBgColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setSelectedBgColor(@ColorInt int color) { |
|
||||||
mSelectedBgColor = color; |
|
||||||
hasSetSelectedBgColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setFocusedBgColor(@ColorInt int color) { |
|
||||||
mFocusedBgColor = color; |
|
||||||
hasSetPressedBgColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setCheckedBgColor(@ColorInt int color) { |
|
||||||
mCheckedBgColor = color; |
|
||||||
hasSetCheckedBgColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setStrokeWidth(@Dimension int width) { |
|
||||||
mStrokeWidth = width; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setDefaultStrokeColor(@ColorInt int color) { |
|
||||||
mDefaultStrokeColor = color; |
|
||||||
if (!hasSetDisabledStrokeColor) |
|
||||||
mDisabledStrokeColor = color; |
|
||||||
if (!hasSetPressedStrokeColor) |
|
||||||
mPressedStrokeColor = color; |
|
||||||
if (!hasSetSelectedStrokeColor) |
|
||||||
mSelectedStrokeColor = color; |
|
||||||
if (!hasSetFocusedStrokeColor) |
|
||||||
mFocusedStrokeColor = color; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setDisabledStrokeColor(@ColorInt int color) { |
|
||||||
mDisabledStrokeColor = color; |
|
||||||
hasSetDisabledStrokeColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setPressedStrokeColor(@ColorInt int color) { |
|
||||||
mPressedStrokeColor = color; |
|
||||||
hasSetPressedStrokeColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setSelectedStrokeColor(@ColorInt int color) { |
|
||||||
mSelectedStrokeColor = color; |
|
||||||
hasSetSelectedStrokeColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setCheckedStrokeColor(@ColorInt int color) { |
|
||||||
mCheckedStrokeColor = color; |
|
||||||
hasSetCheckedStrokeColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setFocusedStrokeColor(@ColorInt int color) { |
|
||||||
mFocusedStrokeColor = color; |
|
||||||
hasSetFocusedStrokeColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ShapeSelector setCornerRadius(@Dimension int radius) { |
|
||||||
mCornerRadius = radius; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public StateListDrawable create() { |
|
||||||
StateListDrawable selector = new StateListDrawable(); |
|
||||||
|
|
||||||
//enabled = false
|
|
||||||
if (hasSetDisabledBgColor || hasSetDisabledStrokeColor) { |
|
||||||
GradientDrawable disabledShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mDisabledBgColor, mStrokeWidth, mDisabledStrokeColor); |
|
||||||
selector.addState(new int[]{-android.R.attr.state_enabled}, disabledShape); |
|
||||||
} |
|
||||||
|
|
||||||
//pressed = true
|
|
||||||
if (hasSetPressedBgColor || hasSetPressedStrokeColor) { |
|
||||||
GradientDrawable pressedShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mPressedBgColor, mStrokeWidth, mPressedStrokeColor); |
|
||||||
selector.addState(new int[]{android.R.attr.state_pressed}, pressedShape); |
|
||||||
} |
|
||||||
|
|
||||||
//selected = true
|
|
||||||
if (hasSetSelectedBgColor || hasSetSelectedStrokeColor) { |
|
||||||
GradientDrawable selectedShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mSelectedBgColor, mStrokeWidth, mSelectedStrokeColor); |
|
||||||
selector.addState(new int[]{android.R.attr.state_selected}, selectedShape); |
|
||||||
} |
|
||||||
|
|
||||||
//focused = true
|
|
||||||
if (hasSetFocusedBgColor || hasSetFocusedStrokeColor) { |
|
||||||
GradientDrawable focusedShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mFocusedBgColor, mStrokeWidth, mFocusedStrokeColor); |
|
||||||
selector.addState(new int[]{android.R.attr.state_focused}, focusedShape); |
|
||||||
} |
|
||||||
|
|
||||||
//checked = true
|
|
||||||
if (hasSetCheckedBgColor || hasSetCheckedStrokeColor) { |
|
||||||
GradientDrawable checkedShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mCheckedBgColor, mStrokeWidth, mCheckedStrokeColor); |
|
||||||
selector.addState(new int[]{android.R.attr.state_checked}, checkedShape); |
|
||||||
} |
|
||||||
|
|
||||||
//default
|
|
||||||
GradientDrawable defaultShape = getItemShape(mShape, mCornerRadius, |
|
||||||
mDefaultBgColor, mStrokeWidth, mDefaultStrokeColor); |
|
||||||
selector.addState(new int[]{}, defaultShape); |
|
||||||
|
|
||||||
return selector; |
|
||||||
} |
|
||||||
|
|
||||||
private GradientDrawable getItemShape(int shape, int cornerRadius, |
|
||||||
int solidColor, int strokeWidth, int strokeColor) { |
|
||||||
GradientDrawable drawable = new GradientDrawable(); |
|
||||||
drawable.setShape(shape); |
|
||||||
drawable.setStroke(strokeWidth, strokeColor); |
|
||||||
drawable.setCornerRadius(cornerRadius); |
|
||||||
drawable.setColor(solidColor); |
|
||||||
return drawable; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 资源DrawableSelector |
|
||||||
* |
|
||||||
* @author hjy |
|
||||||
* created at 2017/12/11 22:34 |
|
||||||
*/ |
|
||||||
public static final class DrawableSelector { |
|
||||||
|
|
||||||
private Drawable mDefaultDrawable; |
|
||||||
private Drawable mDisabledDrawable; |
|
||||||
private Drawable mPressedDrawable; |
|
||||||
private Drawable mSelectedDrawable; |
|
||||||
private Drawable mFocusedDrawable; |
|
||||||
|
|
||||||
private boolean hasSetDisabledDrawable = false; |
|
||||||
private boolean hasSetPressedDrawable = false; |
|
||||||
private boolean hasSetSelectedDrawable = false; |
|
||||||
private boolean hasSetFocusedDrawable = false; |
|
||||||
|
|
||||||
private DrawableSelector() { |
|
||||||
mDefaultDrawable = new ColorDrawable(Color.TRANSPARENT); |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setDefaultDrawable(Drawable drawable) { |
|
||||||
mDefaultDrawable = drawable; |
|
||||||
if (!hasSetDisabledDrawable) |
|
||||||
mDisabledDrawable = drawable; |
|
||||||
if (!hasSetPressedDrawable) |
|
||||||
mPressedDrawable = drawable; |
|
||||||
if (!hasSetSelectedDrawable) |
|
||||||
mSelectedDrawable = drawable; |
|
||||||
if (!hasSetFocusedDrawable) |
|
||||||
mFocusedDrawable = drawable; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setDisabledDrawable(Drawable drawable) { |
|
||||||
mDisabledDrawable = drawable; |
|
||||||
hasSetDisabledDrawable = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setPressedDrawable(Drawable drawable) { |
|
||||||
mPressedDrawable = drawable; |
|
||||||
hasSetPressedDrawable = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setSelectedDrawable(Drawable drawable) { |
|
||||||
mSelectedDrawable = drawable; |
|
||||||
hasSetSelectedDrawable = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setFocusedDrawable(Drawable drawable) { |
|
||||||
mFocusedDrawable = drawable; |
|
||||||
hasSetFocusedDrawable = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public StateListDrawable create() { |
|
||||||
StateListDrawable selector = new StateListDrawable(); |
|
||||||
if (hasSetDisabledDrawable) |
|
||||||
selector.addState(new int[]{-android.R.attr.state_enabled}, mDisabledDrawable); |
|
||||||
if (hasSetPressedDrawable) |
|
||||||
selector.addState(new int[]{android.R.attr.state_pressed}, mPressedDrawable); |
|
||||||
if (hasSetSelectedDrawable) |
|
||||||
selector.addState(new int[]{android.R.attr.state_selected}, mSelectedDrawable); |
|
||||||
if (hasSetFocusedDrawable) |
|
||||||
selector.addState(new int[]{android.R.attr.state_focused}, mFocusedDrawable); |
|
||||||
selector.addState(new int[]{}, mDefaultDrawable); |
|
||||||
return selector; |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setDefaultDrawable(Context context, @DrawableRes int drawableRes) { |
|
||||||
return setDefaultDrawable(ContextCompat.getDrawable(context, drawableRes)); |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setDisabledDrawable(Context context, @DrawableRes int drawableRes) { |
|
||||||
return setDisabledDrawable(ContextCompat.getDrawable(context, drawableRes)); |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setPressedDrawable(Context context, @DrawableRes int drawableRes) { |
|
||||||
return setPressedDrawable(ContextCompat.getDrawable(context, drawableRes)); |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setSelectedDrawable(Context context, @DrawableRes int drawableRes) { |
|
||||||
return setSelectedDrawable(ContextCompat.getDrawable(context, drawableRes)); |
|
||||||
} |
|
||||||
|
|
||||||
public DrawableSelector setFocusedDrawable(Context context, @DrawableRes int drawableRes) { |
|
||||||
return setFocusedDrawable(ContextCompat.getDrawable(context, drawableRes)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 颜色ColorSelector |
|
||||||
* |
|
||||||
* @author hjy |
|
||||||
* created at 2017/12/11 22:26 |
|
||||||
*/ |
|
||||||
public static final class ColorSelector { |
|
||||||
|
|
||||||
private int mDefaultColor; |
|
||||||
private int mDisabledColor; |
|
||||||
private int mPressedColor; |
|
||||||
private int mSelectedColor; |
|
||||||
private int mFocusedColor; |
|
||||||
private int mCheckedColor; |
|
||||||
|
|
||||||
private boolean hasSetDisabledColor = false; |
|
||||||
private boolean hasSetPressedColor = false; |
|
||||||
private boolean hasSetSelectedColor = false; |
|
||||||
private boolean hasSetFocusedColor = false; |
|
||||||
private boolean hasSetCheckedColor = false; |
|
||||||
|
|
||||||
private ColorSelector() { |
|
||||||
mDefaultColor = Color.BLACK; |
|
||||||
mDisabledColor = Color.GRAY; |
|
||||||
mPressedColor = Color.BLACK; |
|
||||||
mSelectedColor = Color.BLACK; |
|
||||||
mFocusedColor = Color.BLACK; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setDefaultColor(@ColorInt int color) { |
|
||||||
mDefaultColor = color; |
|
||||||
if (!hasSetDisabledColor) |
|
||||||
mDisabledColor = color; |
|
||||||
if (!hasSetPressedColor) |
|
||||||
mPressedColor = color; |
|
||||||
if (!hasSetSelectedColor) |
|
||||||
mSelectedColor = color; |
|
||||||
if (!hasSetFocusedColor) |
|
||||||
mFocusedColor = color; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setDisabledColor(@ColorInt int color) { |
|
||||||
mDisabledColor = color; |
|
||||||
hasSetDisabledColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setPressedColor(@ColorInt int color) { |
|
||||||
mPressedColor = color; |
|
||||||
hasSetPressedColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setSelectedColor(@ColorInt int color) { |
|
||||||
mSelectedColor = color; |
|
||||||
hasSetSelectedColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setFocusedColor(@ColorInt int color) { |
|
||||||
mFocusedColor = color; |
|
||||||
hasSetFocusedColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorSelector setCheckedColor(@ColorInt int color) { |
|
||||||
mCheckedColor = color; |
|
||||||
hasSetCheckedColor = true; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ColorStateList create() { |
|
||||||
int[] colors = new int[]{ |
|
||||||
hasSetDisabledColor ? mDisabledColor : mDefaultColor, |
|
||||||
hasSetPressedColor ? mPressedColor : mDefaultColor, |
|
||||||
hasSetSelectedColor ? mSelectedColor : mDefaultColor, |
|
||||||
hasSetFocusedColor ? mFocusedColor : mDefaultColor, |
|
||||||
hasSetCheckedColor ? mCheckedColor : mDefaultColor, |
|
||||||
mDefaultColor |
|
||||||
}; |
|
||||||
int[][] states = new int[6][]; |
|
||||||
states[0] = new int[]{-android.R.attr.state_enabled}; |
|
||||||
states[1] = new int[]{android.R.attr.state_pressed}; |
|
||||||
states[2] = new int[]{android.R.attr.state_selected}; |
|
||||||
states[3] = new int[]{android.R.attr.state_focused}; |
|
||||||
states[4] = new int[]{android.R.attr.state_checked}; |
|
||||||
states[5] = new int[]{}; |
|
||||||
return new ColorStateList(states, colors); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,443 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.res.ColorStateList |
||||||
|
import android.graphics.Color |
||||||
|
import android.graphics.drawable.ColorDrawable |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.graphics.drawable.GradientDrawable |
||||||
|
import android.graphics.drawable.StateListDrawable |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.annotation.Dimension |
||||||
|
import androidx.annotation.DrawableRes |
||||||
|
import androidx.annotation.IntDef |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
|
||||||
|
object Selector { |
||||||
|
fun shapeBuild(): ShapeSelector { |
||||||
|
return ShapeSelector() |
||||||
|
} |
||||||
|
|
||||||
|
fun colorBuild(): ColorSelector { |
||||||
|
return ColorSelector() |
||||||
|
} |
||||||
|
|
||||||
|
fun drawableBuild(): DrawableSelector { |
||||||
|
return DrawableSelector() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 形状ShapeSelector |
||||||
|
* |
||||||
|
* @author hjy |
||||||
|
* created at 2017/12/11 22:26 |
||||||
|
*/ |
||||||
|
class ShapeSelector { |
||||||
|
|
||||||
|
private var mShape: Int = 0 //the shape of background |
||||||
|
private var mDefaultBgColor: Int = 0 //default background color |
||||||
|
private var mDisabledBgColor: Int = 0 //state_enabled = false |
||||||
|
private var mPressedBgColor: Int = 0 //state_pressed = true |
||||||
|
private var mSelectedBgColor: Int = 0 //state_selected = true |
||||||
|
private var mFocusedBgColor: Int = 0 //state_focused = true |
||||||
|
private var mCheckedBgColor: Int = 0 //state_checked = true |
||||||
|
private var mStrokeWidth: Int = 0 //stroke width in pixel |
||||||
|
private var mDefaultStrokeColor: Int = 0 //default stroke color |
||||||
|
private var mDisabledStrokeColor: Int = 0 //state_enabled = false |
||||||
|
private var mPressedStrokeColor: Int = 0 //state_pressed = true |
||||||
|
private var mSelectedStrokeColor: Int = 0 //state_selected = true |
||||||
|
private var mFocusedStrokeColor: Int = 0 //state_focused = true |
||||||
|
private var mCheckedStrokeColor: Int = 0 //state_checked = true |
||||||
|
private var mCornerRadius: Int = 0 //corner radius |
||||||
|
|
||||||
|
private var hasSetDisabledBgColor = false |
||||||
|
private var hasSetPressedBgColor = false |
||||||
|
private var hasSetSelectedBgColor = false |
||||||
|
private val hasSetFocusedBgColor = false |
||||||
|
private var hasSetCheckedBgColor = false |
||||||
|
|
||||||
|
private var hasSetDisabledStrokeColor = false |
||||||
|
private var hasSetPressedStrokeColor = false |
||||||
|
private var hasSetSelectedStrokeColor = false |
||||||
|
private var hasSetFocusedStrokeColor = false |
||||||
|
private var hasSetCheckedStrokeColor = false |
||||||
|
|
||||||
|
@IntDef(GradientDrawable.RECTANGLE, GradientDrawable.OVAL, GradientDrawable.LINE, GradientDrawable.RING) |
||||||
|
private annotation class Shape |
||||||
|
|
||||||
|
init { |
||||||
|
//initialize default values |
||||||
|
mShape = GradientDrawable.RECTANGLE |
||||||
|
mDefaultBgColor = Color.TRANSPARENT |
||||||
|
mDisabledBgColor = Color.TRANSPARENT |
||||||
|
mPressedBgColor = Color.TRANSPARENT |
||||||
|
mSelectedBgColor = Color.TRANSPARENT |
||||||
|
mFocusedBgColor = Color.TRANSPARENT |
||||||
|
mStrokeWidth = 0 |
||||||
|
mDefaultStrokeColor = Color.TRANSPARENT |
||||||
|
mDisabledStrokeColor = Color.TRANSPARENT |
||||||
|
mPressedStrokeColor = Color.TRANSPARENT |
||||||
|
mSelectedStrokeColor = Color.TRANSPARENT |
||||||
|
mFocusedStrokeColor = Color.TRANSPARENT |
||||||
|
mCornerRadius = 0 |
||||||
|
} |
||||||
|
|
||||||
|
fun setShape(@Shape shape: Int): ShapeSelector { |
||||||
|
mShape = shape |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDefaultBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mDefaultBgColor = color |
||||||
|
if (!hasSetDisabledBgColor) |
||||||
|
mDisabledBgColor = color |
||||||
|
if (!hasSetPressedBgColor) |
||||||
|
mPressedBgColor = color |
||||||
|
if (!hasSetSelectedBgColor) |
||||||
|
mSelectedBgColor = color |
||||||
|
if (!hasSetFocusedBgColor) |
||||||
|
mFocusedBgColor = color |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDisabledBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mDisabledBgColor = color |
||||||
|
hasSetDisabledBgColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setPressedBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mPressedBgColor = color |
||||||
|
hasSetPressedBgColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setSelectedBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mSelectedBgColor = color |
||||||
|
hasSetSelectedBgColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setFocusedBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mFocusedBgColor = color |
||||||
|
hasSetPressedBgColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setCheckedBgColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mCheckedBgColor = color |
||||||
|
hasSetCheckedBgColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setStrokeWidth(@Dimension width: Int): ShapeSelector { |
||||||
|
mStrokeWidth = width |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDefaultStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mDefaultStrokeColor = color |
||||||
|
if (!hasSetDisabledStrokeColor) |
||||||
|
mDisabledStrokeColor = color |
||||||
|
if (!hasSetPressedStrokeColor) |
||||||
|
mPressedStrokeColor = color |
||||||
|
if (!hasSetSelectedStrokeColor) |
||||||
|
mSelectedStrokeColor = color |
||||||
|
if (!hasSetFocusedStrokeColor) |
||||||
|
mFocusedStrokeColor = color |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDisabledStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mDisabledStrokeColor = color |
||||||
|
hasSetDisabledStrokeColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setPressedStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mPressedStrokeColor = color |
||||||
|
hasSetPressedStrokeColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setSelectedStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mSelectedStrokeColor = color |
||||||
|
hasSetSelectedStrokeColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setCheckedStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mCheckedStrokeColor = color |
||||||
|
hasSetCheckedStrokeColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setFocusedStrokeColor(@ColorInt color: Int): ShapeSelector { |
||||||
|
mFocusedStrokeColor = color |
||||||
|
hasSetFocusedStrokeColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setCornerRadius(@Dimension radius: Int): ShapeSelector { |
||||||
|
mCornerRadius = radius |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun create(): StateListDrawable { |
||||||
|
val selector = StateListDrawable() |
||||||
|
|
||||||
|
//enabled = false |
||||||
|
if (hasSetDisabledBgColor || hasSetDisabledStrokeColor) { |
||||||
|
val disabledShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mDisabledBgColor, mStrokeWidth, mDisabledStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(-android.R.attr.state_enabled), disabledShape) |
||||||
|
} |
||||||
|
|
||||||
|
//pressed = true |
||||||
|
if (hasSetPressedBgColor || hasSetPressedStrokeColor) { |
||||||
|
val pressedShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mPressedBgColor, mStrokeWidth, mPressedStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_pressed), pressedShape) |
||||||
|
} |
||||||
|
|
||||||
|
//selected = true |
||||||
|
if (hasSetSelectedBgColor || hasSetSelectedStrokeColor) { |
||||||
|
val selectedShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mSelectedBgColor, mStrokeWidth, mSelectedStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_selected), selectedShape) |
||||||
|
} |
||||||
|
|
||||||
|
//focused = true |
||||||
|
if (hasSetFocusedBgColor || hasSetFocusedStrokeColor) { |
||||||
|
val focusedShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mFocusedBgColor, mStrokeWidth, mFocusedStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_focused), focusedShape) |
||||||
|
} |
||||||
|
|
||||||
|
//checked = true |
||||||
|
if (hasSetCheckedBgColor || hasSetCheckedStrokeColor) { |
||||||
|
val checkedShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mCheckedBgColor, mStrokeWidth, mCheckedStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_checked), checkedShape) |
||||||
|
} |
||||||
|
|
||||||
|
//default |
||||||
|
val defaultShape = getItemShape( |
||||||
|
mShape, mCornerRadius, |
||||||
|
mDefaultBgColor, mStrokeWidth, mDefaultStrokeColor |
||||||
|
) |
||||||
|
selector.addState(intArrayOf(), defaultShape) |
||||||
|
|
||||||
|
return selector |
||||||
|
} |
||||||
|
|
||||||
|
private fun getItemShape( |
||||||
|
shape: Int, cornerRadius: Int, |
||||||
|
solidColor: Int, strokeWidth: Int, strokeColor: Int |
||||||
|
): GradientDrawable { |
||||||
|
val drawable = GradientDrawable() |
||||||
|
drawable.shape = shape |
||||||
|
drawable.setStroke(strokeWidth, strokeColor) |
||||||
|
drawable.cornerRadius = cornerRadius.toFloat() |
||||||
|
drawable.setColor(solidColor) |
||||||
|
return drawable |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 资源DrawableSelector |
||||||
|
* |
||||||
|
* @author hjy |
||||||
|
* created at 2017/12/11 22:34 |
||||||
|
*/ |
||||||
|
class DrawableSelector constructor() { |
||||||
|
|
||||||
|
private var mDefaultDrawable: Drawable? = null |
||||||
|
private var mDisabledDrawable: Drawable? = null |
||||||
|
private var mPressedDrawable: Drawable? = null |
||||||
|
private var mSelectedDrawable: Drawable? = null |
||||||
|
private var mFocusedDrawable: Drawable? = null |
||||||
|
|
||||||
|
private var hasSetDisabledDrawable = false |
||||||
|
private var hasSetPressedDrawable = false |
||||||
|
private var hasSetSelectedDrawable = false |
||||||
|
private var hasSetFocusedDrawable = false |
||||||
|
|
||||||
|
init { |
||||||
|
mDefaultDrawable = ColorDrawable(Color.TRANSPARENT) |
||||||
|
} |
||||||
|
|
||||||
|
fun setDefaultDrawable(drawable: Drawable?): DrawableSelector { |
||||||
|
mDefaultDrawable = drawable |
||||||
|
if (!hasSetDisabledDrawable) |
||||||
|
mDisabledDrawable = drawable |
||||||
|
if (!hasSetPressedDrawable) |
||||||
|
mPressedDrawable = drawable |
||||||
|
if (!hasSetSelectedDrawable) |
||||||
|
mSelectedDrawable = drawable |
||||||
|
if (!hasSetFocusedDrawable) |
||||||
|
mFocusedDrawable = drawable |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDisabledDrawable(drawable: Drawable?): DrawableSelector { |
||||||
|
mDisabledDrawable = drawable |
||||||
|
hasSetDisabledDrawable = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setPressedDrawable(drawable: Drawable?): DrawableSelector { |
||||||
|
mPressedDrawable = drawable |
||||||
|
hasSetPressedDrawable = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setSelectedDrawable(drawable: Drawable?): DrawableSelector { |
||||||
|
mSelectedDrawable = drawable |
||||||
|
hasSetSelectedDrawable = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setFocusedDrawable(drawable: Drawable?): DrawableSelector { |
||||||
|
mFocusedDrawable = drawable |
||||||
|
hasSetFocusedDrawable = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun create(): StateListDrawable { |
||||||
|
val selector = StateListDrawable() |
||||||
|
if (hasSetDisabledDrawable) |
||||||
|
selector.addState(intArrayOf(-android.R.attr.state_enabled), mDisabledDrawable) |
||||||
|
if (hasSetPressedDrawable) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_pressed), mPressedDrawable) |
||||||
|
if (hasSetSelectedDrawable) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_selected), mSelectedDrawable) |
||||||
|
if (hasSetFocusedDrawable) |
||||||
|
selector.addState(intArrayOf(android.R.attr.state_focused), mFocusedDrawable) |
||||||
|
selector.addState(intArrayOf(), mDefaultDrawable) |
||||||
|
return selector |
||||||
|
} |
||||||
|
|
||||||
|
fun setDefaultDrawable(context: Context, @DrawableRes drawableRes: Int): DrawableSelector { |
||||||
|
return setDefaultDrawable(ContextCompat.getDrawable(context, drawableRes)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setDisabledDrawable(context: Context, @DrawableRes drawableRes: Int): DrawableSelector { |
||||||
|
return setDisabledDrawable(ContextCompat.getDrawable(context, drawableRes)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setPressedDrawable(context: Context, @DrawableRes drawableRes: Int): DrawableSelector { |
||||||
|
return setPressedDrawable(ContextCompat.getDrawable(context, drawableRes)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setSelectedDrawable(context: Context, @DrawableRes drawableRes: Int): DrawableSelector { |
||||||
|
return setSelectedDrawable(ContextCompat.getDrawable(context, drawableRes)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setFocusedDrawable(context: Context, @DrawableRes drawableRes: Int): DrawableSelector { |
||||||
|
return setFocusedDrawable(ContextCompat.getDrawable(context, drawableRes)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 颜色ColorSelector |
||||||
|
* |
||||||
|
* @author hjy |
||||||
|
* created at 2017/12/11 22:26 |
||||||
|
*/ |
||||||
|
class ColorSelector constructor() { |
||||||
|
|
||||||
|
private var mDefaultColor: Int = 0 |
||||||
|
private var mDisabledColor: Int = 0 |
||||||
|
private var mPressedColor: Int = 0 |
||||||
|
private var mSelectedColor: Int = 0 |
||||||
|
private var mFocusedColor: Int = 0 |
||||||
|
private var mCheckedColor: Int = 0 |
||||||
|
|
||||||
|
private var hasSetDisabledColor = false |
||||||
|
private var hasSetPressedColor = false |
||||||
|
private var hasSetSelectedColor = false |
||||||
|
private var hasSetFocusedColor = false |
||||||
|
private var hasSetCheckedColor = false |
||||||
|
|
||||||
|
init { |
||||||
|
mDefaultColor = Color.BLACK |
||||||
|
mDisabledColor = Color.GRAY |
||||||
|
mPressedColor = Color.BLACK |
||||||
|
mSelectedColor = Color.BLACK |
||||||
|
mFocusedColor = Color.BLACK |
||||||
|
} |
||||||
|
|
||||||
|
fun setDefaultColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mDefaultColor = color |
||||||
|
if (!hasSetDisabledColor) |
||||||
|
mDisabledColor = color |
||||||
|
if (!hasSetPressedColor) |
||||||
|
mPressedColor = color |
||||||
|
if (!hasSetSelectedColor) |
||||||
|
mSelectedColor = color |
||||||
|
if (!hasSetFocusedColor) |
||||||
|
mFocusedColor = color |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setDisabledColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mDisabledColor = color |
||||||
|
hasSetDisabledColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setPressedColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mPressedColor = color |
||||||
|
hasSetPressedColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setSelectedColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mSelectedColor = color |
||||||
|
hasSetSelectedColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setFocusedColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mFocusedColor = color |
||||||
|
hasSetFocusedColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun setCheckedColor(@ColorInt color: Int): ColorSelector { |
||||||
|
mCheckedColor = color |
||||||
|
hasSetCheckedColor = true |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun create(): ColorStateList { |
||||||
|
val colors = intArrayOf( |
||||||
|
if (hasSetDisabledColor) mDisabledColor else mDefaultColor, |
||||||
|
if (hasSetPressedColor) mPressedColor else mDefaultColor, |
||||||
|
if (hasSetSelectedColor) mSelectedColor else mDefaultColor, |
||||||
|
if (hasSetFocusedColor) mFocusedColor else mDefaultColor, |
||||||
|
if (hasSetCheckedColor) mCheckedColor else mDefaultColor, |
||||||
|
mDefaultColor |
||||||
|
) |
||||||
|
val states = arrayOfNulls<IntArray>(6) |
||||||
|
states[0] = intArrayOf(-android.R.attr.state_enabled) |
||||||
|
states[1] = intArrayOf(android.R.attr.state_pressed) |
||||||
|
states[2] = intArrayOf(android.R.attr.state_selected) |
||||||
|
states[3] = intArrayOf(android.R.attr.state_focused) |
||||||
|
states[4] = intArrayOf(android.R.attr.state_checked) |
||||||
|
states[5] = intArrayOf() |
||||||
|
return ColorStateList(states, colors) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,318 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.annotation.SuppressLint; |
|
||||||
import android.content.Context; |
|
||||||
import android.content.SharedPreferences; |
|
||||||
import android.graphics.Color; |
|
||||||
import androidx.annotation.*; |
|
||||||
import androidx.core.content.ContextCompat; |
|
||||||
import io.legado.app.R; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class ThemeStore implements ThemeStorePrefKeys, ThemeStoreInterface { |
|
||||||
|
|
||||||
private final Context mContext; |
|
||||||
private final SharedPreferences.Editor mEditor; |
|
||||||
|
|
||||||
public static ThemeStore editTheme(@NonNull Context context) { |
|
||||||
return new ThemeStore(context); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressLint("CommitPrefEdits") |
|
||||||
private ThemeStore(@NonNull Context context) { |
|
||||||
mContext = context; |
|
||||||
mEditor = prefs(context).edit(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColor(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_PRIMARY_COLOR, color); |
|
||||||
if (autoGeneratePrimaryDark(mContext)) |
|
||||||
primaryColorDark(ColorUtil.darkenColor(color)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColorRes(@ColorRes int colorRes) { |
|
||||||
return primaryColor(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColorAttr(@AttrRes int colorAttr) { |
|
||||||
return primaryColor(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColorDark(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_PRIMARY_COLOR_DARK, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColorDarkRes(@ColorRes int colorRes) { |
|
||||||
return primaryColorDark(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore primaryColorDarkAttr(@AttrRes int colorAttr) { |
|
||||||
return primaryColorDark(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore accentColor(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_ACCENT_COLOR, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore accentColorRes(@ColorRes int colorRes) { |
|
||||||
return accentColor(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore accentColorAttr(@AttrRes int colorAttr) { |
|
||||||
return accentColor(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore statusBarColor(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_STATUS_BAR_COLOR, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore statusBarColorRes(@ColorRes int colorRes) { |
|
||||||
return statusBarColor(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore statusBarColorAttr(@AttrRes int colorAttr) { |
|
||||||
return statusBarColor(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore navigationBarColor(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_NAVIGATION_BAR_COLOR, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore navigationBarColorRes(@ColorRes int colorRes) { |
|
||||||
return navigationBarColor(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore navigationBarColorAttr(@AttrRes int colorAttr) { |
|
||||||
return navigationBarColor(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimary(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_TEXT_COLOR_PRIMARY, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimaryRes(@ColorRes int colorRes) { |
|
||||||
return textColorPrimary(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimaryAttr(@AttrRes int colorAttr) { |
|
||||||
return textColorPrimary(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimaryInverse(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_TEXT_COLOR_PRIMARY_INVERSE, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimaryInverseRes(@ColorRes int colorRes) { |
|
||||||
return textColorPrimaryInverse(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorPrimaryInverseAttr(@AttrRes int colorAttr) { |
|
||||||
return textColorPrimaryInverse(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondary(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_TEXT_COLOR_SECONDARY, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondaryRes(@ColorRes int colorRes) { |
|
||||||
return textColorSecondary(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondaryAttr(@AttrRes int colorAttr) { |
|
||||||
return textColorSecondary(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondaryInverse(@ColorInt int color) { |
|
||||||
mEditor.putInt(KEY_TEXT_COLOR_SECONDARY_INVERSE, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondaryInverseRes(@ColorRes int colorRes) { |
|
||||||
return textColorSecondaryInverse(ContextCompat.getColor(mContext, colorRes)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore textColorSecondaryInverseAttr(@AttrRes int colorAttr) { |
|
||||||
return textColorSecondaryInverse(ATHUtil.resolveColor(mContext, colorAttr)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore backgroundColor(int color) { |
|
||||||
mEditor.putInt(KEY_BACKGROUND_COLOR, color); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore coloredStatusBar(boolean colored) { |
|
||||||
mEditor.putBoolean(KEY_APPLY_PRIMARYDARK_STATUSBAR, colored); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore coloredNavigationBar(boolean applyToNavBar) { |
|
||||||
mEditor.putBoolean(KEY_APPLY_PRIMARY_NAVBAR, applyToNavBar); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ThemeStore autoGeneratePrimaryDark(boolean autoGenerate) { |
|
||||||
mEditor.putBoolean(KEY_AUTO_GENERATE_PRIMARYDARK, autoGenerate); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
// Commit method
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
@Override |
|
||||||
public void apply() { |
|
||||||
mEditor.putLong(VALUES_CHANGED, System.currentTimeMillis()) |
|
||||||
.putBoolean(IS_CONFIGURED_KEY, true) |
|
||||||
.apply(); |
|
||||||
} |
|
||||||
|
|
||||||
// Static getters
|
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@NonNull |
|
||||||
protected static SharedPreferences prefs(@NonNull Context context) { |
|
||||||
return context.getSharedPreferences(CONFIG_PREFS_KEY_DEFAULT, Context.MODE_PRIVATE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void markChanged(@NonNull Context context) { |
|
||||||
new ThemeStore(context).apply(); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int primaryColor(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_PRIMARY_COLOR, ATHUtil.resolveColor(context, R.attr.colorPrimary, Color.parseColor("#455A64"))); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int primaryColorDark(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_PRIMARY_COLOR_DARK, ATHUtil.resolveColor(context, R.attr.colorPrimaryDark, Color.parseColor("#37474F"))); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int accentColor(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_ACCENT_COLOR, ATHUtil.resolveColor(context, R.attr.colorAccent, Color.parseColor("#263238"))); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int statusBarColor(@NonNull Context context) { |
|
||||||
if (!coloredStatusBar(context)) { |
|
||||||
return Color.BLACK; |
|
||||||
} |
|
||||||
return prefs(context).getInt(KEY_STATUS_BAR_COLOR, primaryColorDark(context)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int navigationBarColor(@NonNull Context context) { |
|
||||||
if (!coloredNavigationBar(context)) { |
|
||||||
return Color.BLACK; |
|
||||||
} |
|
||||||
return prefs(context).getInt(KEY_NAVIGATION_BAR_COLOR, primaryColor(context)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int textColorPrimary(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_TEXT_COLOR_PRIMARY, ATHUtil.resolveColor(context, android.R.attr.textColorPrimary)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int textColorPrimaryInverse(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_TEXT_COLOR_PRIMARY_INVERSE, ATHUtil.resolveColor(context, android.R.attr.textColorPrimaryInverse)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int textColorSecondary(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_TEXT_COLOR_SECONDARY, ATHUtil.resolveColor(context, android.R.attr.textColorSecondary)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int textColorSecondaryInverse(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_TEXT_COLOR_SECONDARY_INVERSE, ATHUtil.resolveColor(context, android.R.attr.textColorSecondaryInverse)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
@ColorInt |
|
||||||
public static int backgroundColor(@NonNull Context context) { |
|
||||||
return prefs(context).getInt(KEY_BACKGROUND_COLOR, ATHUtil.resolveColor(context, android.R.attr.colorBackground)); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
public static boolean coloredStatusBar(@NonNull Context context) { |
|
||||||
return prefs(context).getBoolean(KEY_APPLY_PRIMARYDARK_STATUSBAR, true); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
public static boolean coloredNavigationBar(@NonNull Context context) { |
|
||||||
return prefs(context).getBoolean(KEY_APPLY_PRIMARY_NAVBAR, false); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
public static boolean autoGeneratePrimaryDark(@NonNull Context context) { |
|
||||||
return prefs(context).getBoolean(KEY_AUTO_GENERATE_PRIMARYDARK, true); |
|
||||||
} |
|
||||||
|
|
||||||
@CheckResult |
|
||||||
public static boolean isConfigured(Context context) { |
|
||||||
return prefs(context).getBoolean(IS_CONFIGURED_KEY, false); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressLint("CommitPrefEdits") |
|
||||||
public static boolean isConfigured(Context context, @IntRange(from = 0, to = Integer.MAX_VALUE) int version) { |
|
||||||
final SharedPreferences prefs = prefs(context); |
|
||||||
final int lastVersion = prefs.getInt(IS_CONFIGURED_VERSION_KEY, -1); |
|
||||||
if (version > lastVersion) { |
|
||||||
prefs.edit().putInt(IS_CONFIGURED_VERSION_KEY, version).apply(); |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,309 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.content.Context |
||||||
|
import android.content.SharedPreferences |
||||||
|
import android.graphics.Color |
||||||
|
import androidx.annotation.AttrRes |
||||||
|
import androidx.annotation.CheckResult |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.annotation.ColorRes |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import io.legado.app.R |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
class ThemeStore @SuppressLint("CommitPrefEdits") |
||||||
|
private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeStoreInterface { |
||||||
|
private val mEditor: SharedPreferences.Editor |
||||||
|
|
||||||
|
init { |
||||||
|
mEditor = prefs(mContext).edit() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
override fun primaryColor(@ColorInt color: Int): ThemeStore { |
||||||
|
mEditor.putInt(ThemeStorePrefKeys.KEY_PRIMARY_COLOR, color) |
||||||
|
if (autoGeneratePrimaryDark(mContext)) |
||||||
|
primaryColorDark(ColorUtil.darkenColor(color)) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
override fun primaryColorRes(@ColorRes colorRes: Int): ThemeStore { |
||||||
|
return primaryColor(ContextCompat.getColor(mContext, colorRes)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun primaryColorAttr(@AttrRes colorAttr: Int): ThemeStore { |
||||||
|
return primaryColor(ATHUtil.resolveColor(mContext, colorAttr)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun primaryColorDark(@ColorInt color: Int): ThemeStore { |
||||||
|
mEditor.putInt(ThemeStorePrefKeys.KEY_PRIMARY_COLOR_DARK, color) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
override fun primaryColorDarkRes(@ColorRes colorRes: Int): ThemeStore { |
||||||
|
return primaryColorDark(ContextCompat.getColor(mContext, colorRes)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun primaryColorDarkAttr(@AttrRes colorAttr: Int): ThemeStore { |
||||||
|
return primaryColorDark(ATHUtil.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(ATHUtil.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(ATHUtil.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(ATHUtil.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(ATHUtil.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(ATHUtil.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(ATHUtil.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(ATHUtil.resolveColor(mContext, colorAttr)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun backgroundColor(color: Int): ThemeStore { |
||||||
|
mEditor.putInt(ThemeStorePrefKeys.KEY_BACKGROUND_COLOR, color) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
override fun coloredStatusBar(colored: Boolean): ThemeStore { |
||||||
|
mEditor.putBoolean(ThemeStorePrefKeys.KEY_APPLY_PRIMARYDARK_STATUSBAR, colored) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
override fun coloredNavigationBar(applyToNavBar: Boolean): ThemeStore { |
||||||
|
mEditor.putBoolean(ThemeStorePrefKeys.KEY_APPLY_PRIMARY_NAVBAR, applyToNavBar) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
override fun autoGeneratePrimaryDark(autoGenerate: Boolean): ThemeStore { |
||||||
|
mEditor.putBoolean(ThemeStorePrefKeys.KEY_AUTO_GENERATE_PRIMARYDARK, autoGenerate) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
// Commit method |
||||||
|
|
||||||
|
override fun apply() { |
||||||
|
mEditor.putLong(ThemeStorePrefKeys.VALUES_CHANGED, System.currentTimeMillis()) |
||||||
|
.putBoolean(ThemeStorePrefKeys.IS_CONFIGURED_KEY, true) |
||||||
|
.apply() |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
fun editTheme(context: Context): ThemeStore { |
||||||
|
return ThemeStore(context) |
||||||
|
} |
||||||
|
|
||||||
|
// Static getters |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
protected fun prefs(context: Context): SharedPreferences { |
||||||
|
return context.getSharedPreferences(ThemeStorePrefKeys.CONFIG_PREFS_KEY_DEFAULT, Context.MODE_PRIVATE) |
||||||
|
} |
||||||
|
|
||||||
|
fun markChanged(context: Context) { |
||||||
|
ThemeStore(context).apply() |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun primaryColor(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_PRIMARY_COLOR, |
||||||
|
ATHUtil.resolveColor(context, R.attr.colorPrimary, Color.parseColor("#455A64")) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun primaryColorDark(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_PRIMARY_COLOR_DARK, |
||||||
|
ATHUtil.resolveColor(context, R.attr.colorPrimaryDark, Color.parseColor("#37474F")) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun accentColor(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_ACCENT_COLOR, |
||||||
|
ATHUtil.resolveColor(context, R.attr.colorAccent, Color.parseColor("#263238")) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun statusBarColor(context: Context): Int { |
||||||
|
return if (!coloredStatusBar(context)) { |
||||||
|
Color.BLACK |
||||||
|
} else prefs(context).getInt(ThemeStorePrefKeys.KEY_STATUS_BAR_COLOR, primaryColorDark(context)) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun navigationBarColor(context: Context): Int { |
||||||
|
return if (!coloredNavigationBar(context)) { |
||||||
|
Color.BLACK |
||||||
|
} else prefs(context).getInt(ThemeStorePrefKeys.KEY_NAVIGATION_BAR_COLOR, primaryColor(context)) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun textColorPrimary(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY, |
||||||
|
ATHUtil.resolveColor(context, android.R.attr.textColorPrimary) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun textColorPrimaryInverse(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_TEXT_COLOR_PRIMARY_INVERSE, |
||||||
|
ATHUtil.resolveColor(context, android.R.attr.textColorPrimaryInverse) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun textColorSecondary(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY, |
||||||
|
ATHUtil.resolveColor(context, android.R.attr.textColorSecondary) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun textColorSecondaryInverse(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_TEXT_COLOR_SECONDARY_INVERSE, |
||||||
|
ATHUtil.resolveColor(context, android.R.attr.textColorSecondaryInverse) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
@ColorInt |
||||||
|
fun backgroundColor(context: Context): Int { |
||||||
|
return prefs(context).getInt( |
||||||
|
ThemeStorePrefKeys.KEY_BACKGROUND_COLOR, |
||||||
|
ATHUtil.resolveColor(context, android.R.attr.colorBackground) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
fun coloredStatusBar(context: Context): Boolean { |
||||||
|
return prefs(context).getBoolean(ThemeStorePrefKeys.KEY_APPLY_PRIMARYDARK_STATUSBAR, true) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
fun coloredNavigationBar(context: Context): Boolean { |
||||||
|
return prefs(context).getBoolean(ThemeStorePrefKeys.KEY_APPLY_PRIMARY_NAVBAR, false) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
fun autoGeneratePrimaryDark(context: Context): Boolean { |
||||||
|
return prefs(context).getBoolean(ThemeStorePrefKeys.KEY_AUTO_GENERATE_PRIMARYDARK, true) |
||||||
|
} |
||||||
|
|
||||||
|
@CheckResult |
||||||
|
fun isConfigured(context: Context): Boolean { |
||||||
|
return prefs(context).getBoolean(ThemeStorePrefKeys.IS_CONFIGURED_KEY, false) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("CommitPrefEdits") |
||||||
|
fun isConfigured(context: Context, version: Int): Boolean { |
||||||
|
val prefs = prefs(context) |
||||||
|
val lastVersion = prefs.getInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, -1) |
||||||
|
if (version > lastVersion) { |
||||||
|
prefs.edit().putInt(ThemeStorePrefKeys.IS_CONFIGURED_VERSION_KEY, version).apply() |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,92 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.AttrRes; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.ColorRes; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
interface ThemeStoreInterface { |
|
||||||
|
|
||||||
// Primary colors
|
|
||||||
|
|
||||||
ThemeStore primaryColor(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore primaryColorRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore primaryColorAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
ThemeStore autoGeneratePrimaryDark(boolean autoGenerate); |
|
||||||
|
|
||||||
ThemeStore primaryColorDark(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore primaryColorDarkRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore primaryColorDarkAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
// Accent colors
|
|
||||||
|
|
||||||
ThemeStore accentColor(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore accentColorRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore accentColorAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
// Status bar color
|
|
||||||
|
|
||||||
ThemeStore statusBarColor(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore statusBarColorRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore statusBarColorAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
// Navigation bar color
|
|
||||||
|
|
||||||
ThemeStore navigationBarColor(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore navigationBarColorRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore navigationBarColorAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
// Primary text color
|
|
||||||
|
|
||||||
ThemeStore textColorPrimary(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore textColorPrimaryRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore textColorPrimaryAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
ThemeStore textColorPrimaryInverse(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore textColorPrimaryInverseRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore textColorPrimaryInverseAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
// Secondary text color
|
|
||||||
|
|
||||||
ThemeStore textColorSecondary(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore textColorSecondaryRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore textColorSecondaryAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
ThemeStore textColorSecondaryInverse(@ColorInt int color); |
|
||||||
|
|
||||||
ThemeStore textColorSecondaryInverseRes(@ColorRes int colorRes); |
|
||||||
|
|
||||||
ThemeStore textColorSecondaryInverseAttr(@AttrRes int colorAttr); |
|
||||||
|
|
||||||
ThemeStore backgroundColor(@ColorInt int color); |
|
||||||
|
|
||||||
// Toggle configurations
|
|
||||||
|
|
||||||
ThemeStore coloredStatusBar(boolean colored); |
|
||||||
|
|
||||||
ThemeStore coloredNavigationBar(boolean applyToNavBar); |
|
||||||
|
|
||||||
// Commit/apply
|
|
||||||
|
|
||||||
void apply(); |
|
||||||
} |
|
@ -0,0 +1,92 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
|
||||||
|
import androidx.annotation.AttrRes |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.annotation.ColorRes |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
internal interface ThemeStoreInterface { |
||||||
|
|
||||||
|
// Primary colors |
||||||
|
|
||||||
|
fun primaryColor(@ColorInt color: Int): ThemeStore |
||||||
|
|
||||||
|
fun primaryColorRes(@ColorRes colorRes: Int): ThemeStore |
||||||
|
|
||||||
|
fun primaryColorAttr(@AttrRes colorAttr: Int): ThemeStore |
||||||
|
|
||||||
|
fun autoGeneratePrimaryDark(autoGenerate: Boolean): ThemeStore |
||||||
|
|
||||||
|
fun primaryColorDark(@ColorInt color: Int): ThemeStore |
||||||
|
|
||||||
|
fun primaryColorDarkRes(@ColorRes colorRes: Int): ThemeStore |
||||||
|
|
||||||
|
fun primaryColorDarkAttr(@AttrRes colorAttr: Int): ThemeStore |
||||||
|
|
||||||
|
// Accent colors |
||||||
|
|
||||||
|
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 |
||||||
|
|
||||||
|
fun backgroundColor(@ColorInt color: Int): ThemeStore |
||||||
|
|
||||||
|
// Toggle configurations |
||||||
|
|
||||||
|
fun coloredStatusBar(colored: Boolean): ThemeStore |
||||||
|
|
||||||
|
fun coloredNavigationBar(applyToNavBar: Boolean): ThemeStore |
||||||
|
|
||||||
|
// Commit/apply |
||||||
|
|
||||||
|
fun apply() |
||||||
|
} |
@ -1,29 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
interface ThemeStorePrefKeys { |
|
||||||
|
|
||||||
String CONFIG_PREFS_KEY_DEFAULT = "app_themes"; |
|
||||||
String IS_CONFIGURED_KEY = "is_configured"; |
|
||||||
String IS_CONFIGURED_VERSION_KEY = "is_configured_version"; |
|
||||||
String VALUES_CHANGED = "values_changed"; |
|
||||||
|
|
||||||
String KEY_PRIMARY_COLOR = "primary_color"; |
|
||||||
String KEY_PRIMARY_COLOR_DARK = "primary_color_dark"; |
|
||||||
String KEY_ACCENT_COLOR = "accent_color"; |
|
||||||
String KEY_STATUS_BAR_COLOR = "status_bar_color"; |
|
||||||
String KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color"; |
|
||||||
|
|
||||||
String KEY_TEXT_COLOR_PRIMARY = "text_color_primary"; |
|
||||||
String KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse"; |
|
||||||
String KEY_TEXT_COLOR_SECONDARY = "text_color_secondary"; |
|
||||||
String KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse"; |
|
||||||
|
|
||||||
String KEY_BACKGROUND_COLOR = "backgroundColor"; |
|
||||||
|
|
||||||
String KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"; |
|
||||||
String KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"; |
|
||||||
String KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"; |
|
||||||
} |
|
@ -0,0 +1,31 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
internal interface ThemeStorePrefKeys { |
||||||
|
companion object { |
||||||
|
|
||||||
|
val CONFIG_PREFS_KEY_DEFAULT = "app_themes" |
||||||
|
val IS_CONFIGURED_KEY = "is_configured" |
||||||
|
val IS_CONFIGURED_VERSION_KEY = "is_configured_version" |
||||||
|
val VALUES_CHANGED = "values_changed" |
||||||
|
|
||||||
|
val KEY_PRIMARY_COLOR = "primary_color" |
||||||
|
val KEY_PRIMARY_COLOR_DARK = "primary_color_dark" |
||||||
|
val KEY_ACCENT_COLOR = "accent_color" |
||||||
|
val KEY_STATUS_BAR_COLOR = "status_bar_color" |
||||||
|
val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color" |
||||||
|
|
||||||
|
val KEY_TEXT_COLOR_PRIMARY = "text_color_primary" |
||||||
|
val KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse" |
||||||
|
val KEY_TEXT_COLOR_SECONDARY = "text_color_secondary" |
||||||
|
val KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse" |
||||||
|
|
||||||
|
val KEY_BACKGROUND_COLOR = "backgroundColor" |
||||||
|
|
||||||
|
val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar" |
||||||
|
val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar" |
||||||
|
val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" |
||||||
|
} |
||||||
|
} |
@ -1,384 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.annotation.SuppressLint; |
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.ColorStateList; |
|
||||||
import android.graphics.PorterDuff; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.graphics.drawable.RippleDrawable; |
|
||||||
import android.os.Build; |
|
||||||
import android.view.View; |
|
||||||
import android.widget.*; |
|
||||||
import androidx.annotation.CheckResult; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.appcompat.widget.AppCompatEditText; |
|
||||||
import androidx.appcompat.widget.SearchView; |
|
||||||
import androidx.appcompat.widget.SwitchCompat; |
|
||||||
import androidx.core.content.ContextCompat; |
|
||||||
import androidx.core.graphics.drawable.DrawableCompat; |
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton; |
|
||||||
import io.legado.app.R; |
|
||||||
|
|
||||||
import java.lang.reflect.Field; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author afollestad, plusCubed |
|
||||||
*/ |
|
||||||
public final class TintHelper { |
|
||||||
|
|
||||||
@SuppressLint("PrivateResource") |
|
||||||
@ColorInt |
|
||||||
private static int getDefaultRippleColor(@NonNull Context context, boolean useDarkRipple) { |
|
||||||
// Light ripple is actually translucent black, and vice versa
|
|
||||||
return ContextCompat.getColor(context, useDarkRipple ? |
|
||||||
R.color.ripple_material_light : R.color.ripple_material_dark); |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
private static ColorStateList getDisabledColorStateList(@ColorInt int normal, @ColorInt int disabled) { |
|
||||||
return new ColorStateList(new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled} |
|
||||||
}, new int[]{ |
|
||||||
disabled, |
|
||||||
normal |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") |
|
||||||
public static void setTintSelector(@NonNull View view, @ColorInt final int color, final boolean darker, final boolean useDarkTheme) { |
|
||||||
final boolean isColorLight = ColorUtil.isColorLight(color); |
|
||||||
final int disabled = ContextCompat.getColor(view.getContext(), useDarkTheme ? R.color.ate_button_disabled_dark : R.color.ate_button_disabled_light); |
|
||||||
final int pressed = ColorUtil.shiftColor(color, darker ? 0.9f : 1.1f); |
|
||||||
final int activated = ColorUtil.shiftColor(color, darker ? 1.1f : 0.9f); |
|
||||||
final int rippleColor = getDefaultRippleColor(view.getContext(), isColorLight); |
|
||||||
final int textColor = ContextCompat.getColor(view.getContext(), isColorLight ? R.color.ate_primary_text_light : R.color.ate_primary_text_dark); |
|
||||||
|
|
||||||
final ColorStateList sl; |
|
||||||
if (view instanceof Button) { |
|
||||||
sl = getDisabledColorStateList(color, disabled); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && |
|
||||||
view.getBackground() instanceof RippleDrawable) { |
|
||||||
RippleDrawable rd = (RippleDrawable) view.getBackground(); |
|
||||||
rd.setColor(ColorStateList.valueOf(rippleColor)); |
|
||||||
} |
|
||||||
|
|
||||||
// Disabled text color state for buttons, may get overridden later by ATE tags
|
|
||||||
final Button button = (Button) view; |
|
||||||
button.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), useDarkTheme ? R.color.ate_button_text_disabled_dark : R.color.ate_button_text_disabled_light))); |
|
||||||
} else if (view instanceof FloatingActionButton) { |
|
||||||
// FloatingActionButton doesn't support disabled state?
|
|
||||||
sl = new ColorStateList(new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_pressed}, |
|
||||||
new int[]{android.R.attr.state_pressed} |
|
||||||
}, new int[]{ |
|
||||||
color, |
|
||||||
pressed |
|
||||||
}); |
|
||||||
|
|
||||||
final FloatingActionButton fab = (FloatingActionButton) view; |
|
||||||
fab.setRippleColor(rippleColor); |
|
||||||
fab.setBackgroundTintList(sl); |
|
||||||
if (fab.getDrawable() != null) |
|
||||||
fab.setImageDrawable(createTintedDrawable(fab.getDrawable(), textColor)); |
|
||||||
return; |
|
||||||
} else { |
|
||||||
sl = new ColorStateList( |
|
||||||
new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} |
|
||||||
}, |
|
||||||
new int[]{ |
|
||||||
disabled, |
|
||||||
color, |
|
||||||
pressed, |
|
||||||
activated, |
|
||||||
activated |
|
||||||
} |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
Drawable drawable = view.getBackground(); |
|
||||||
if (drawable != null) { |
|
||||||
drawable = createTintedDrawable(drawable, sl); |
|
||||||
ViewUtil.setBackgroundCompat(view, drawable); |
|
||||||
} |
|
||||||
|
|
||||||
if (view instanceof TextView && !(view instanceof Button)) { |
|
||||||
final TextView tv = (TextView) view; |
|
||||||
tv.setTextColor(getDisabledColorStateList(textColor, ContextCompat.getColor(view.getContext(), isColorLight ? R.color.ate_text_disabled_light : R.color.ate_text_disabled_dark))); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTintAuto(final @NonNull View view, final @ColorInt int color, |
|
||||||
boolean background) { |
|
||||||
setTintAuto(view, color, background, ATHUtil.isWindowBackgroundDark(view.getContext())); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") |
|
||||||
public static void setTintAuto(final @NonNull View view, final @ColorInt int color, |
|
||||||
boolean background, final boolean isDark) { |
|
||||||
if (!background) { |
|
||||||
if (view instanceof RadioButton) |
|
||||||
setTint((RadioButton) view, color, isDark); |
|
||||||
else if (view instanceof SeekBar) |
|
||||||
setTint((SeekBar) view, color, isDark); |
|
||||||
else if (view instanceof ProgressBar) |
|
||||||
setTint((ProgressBar) view, color); |
|
||||||
else if (view instanceof AppCompatEditText) |
|
||||||
setTint((AppCompatEditText) view, color, isDark); |
|
||||||
else if (view instanceof CheckBox) |
|
||||||
setTint((CheckBox) view, color, isDark); |
|
||||||
else if (view instanceof ImageView) |
|
||||||
setTint((ImageView) view, color); |
|
||||||
else if (view instanceof Switch) |
|
||||||
setTint((Switch) view, color, isDark); |
|
||||||
else if (view instanceof SwitchCompat) |
|
||||||
setTint((SwitchCompat) view, color, isDark); |
|
||||||
else if (view instanceof SearchView) { |
|
||||||
int iconIdS[] = new int[]{androidx.appcompat.R.id.search_button, androidx.appcompat.R.id.search_close_btn,}; |
|
||||||
for (int iconId : iconIdS) { |
|
||||||
ImageView icon = view.findViewById(iconId); |
|
||||||
if (icon != null) { |
|
||||||
setTint(icon, color); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} else { |
|
||||||
background = true; |
|
||||||
} |
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && |
|
||||||
!background && view.getBackground() instanceof RippleDrawable) { |
|
||||||
// Ripples for the above views (e.g. when you tap and hold a switch or checkbox)
|
|
||||||
RippleDrawable rd = (RippleDrawable) view.getBackground(); |
|
||||||
@SuppressLint("PrivateResource") final int unchecked = ContextCompat.getColor(view.getContext(), |
|
||||||
isDark ? R.color.ripple_material_dark : R.color.ripple_material_light); |
|
||||||
final int checked = ColorUtil.adjustAlpha(color, 0.4f); |
|
||||||
final ColorStateList sl = new ColorStateList( |
|
||||||
new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_activated, -android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_activated}, |
|
||||||
new int[]{android.R.attr.state_checked} |
|
||||||
}, |
|
||||||
new int[]{ |
|
||||||
unchecked, |
|
||||||
checked, |
|
||||||
checked |
|
||||||
} |
|
||||||
); |
|
||||||
rd.setColor(sl); |
|
||||||
} |
|
||||||
} |
|
||||||
if (background) { |
|
||||||
// Need to tint the background of a view
|
|
||||||
if (view instanceof FloatingActionButton || view instanceof Button) { |
|
||||||
setTintSelector(view, color, false, isDark); |
|
||||||
} else if (view.getBackground() != null) { |
|
||||||
Drawable drawable = view.getBackground(); |
|
||||||
if (drawable != null) { |
|
||||||
drawable = createTintedDrawable(drawable, color); |
|
||||||
ViewUtil.setBackgroundCompat(view, drawable); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull RadioButton radioButton, @ColorInt int color, boolean useDarker) { |
|
||||||
ColorStateList sl = new ColorStateList(new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} |
|
||||||
}, new int[]{ |
|
||||||
// Rdio button includes own alpha for disabled state
|
|
||||||
ColorUtil.stripAlpha(ContextCompat.getColor(radioButton.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)), |
|
||||||
ContextCompat.getColor(radioButton.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), |
|
||||||
color |
|
||||||
}); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
radioButton.setButtonTintList(sl); |
|
||||||
} else { |
|
||||||
Drawable d = createTintedDrawable(ContextCompat.getDrawable(radioButton.getContext(), R.drawable.abc_btn_radio_material), sl); |
|
||||||
radioButton.setButtonDrawable(d); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull SeekBar seekBar, @ColorInt int color, boolean useDarker) { |
|
||||||
final ColorStateList s1 = getDisabledColorStateList(color, |
|
||||||
ContextCompat.getColor(seekBar.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light)); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
seekBar.setThumbTintList(s1); |
|
||||||
seekBar.setProgressTintList(s1); |
|
||||||
} else { |
|
||||||
Drawable progressDrawable = createTintedDrawable(seekBar.getProgressDrawable(), s1); |
|
||||||
seekBar.setProgressDrawable(progressDrawable); |
|
||||||
Drawable thumbDrawable = createTintedDrawable(seekBar.getThumb(), s1); |
|
||||||
seekBar.setThumb(thumbDrawable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color) { |
|
||||||
setTint(progressBar, color, false); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull ProgressBar progressBar, @ColorInt int color, boolean skipIndeterminate) { |
|
||||||
ColorStateList sl = ColorStateList.valueOf(color); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
progressBar.setProgressTintList(sl); |
|
||||||
progressBar.setSecondaryProgressTintList(sl); |
|
||||||
if (!skipIndeterminate) |
|
||||||
progressBar.setIndeterminateTintList(sl); |
|
||||||
} else { |
|
||||||
PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; |
|
||||||
if (!skipIndeterminate && progressBar.getIndeterminateDrawable() != null) |
|
||||||
progressBar.getIndeterminateDrawable().setColorFilter(color, mode); |
|
||||||
if (progressBar.getProgressDrawable() != null) |
|
||||||
progressBar.getProgressDrawable().setColorFilter(color, mode); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi") |
|
||||||
public static void setTint(@NonNull AppCompatEditText editText, @ColorInt int color, boolean useDarker) { |
|
||||||
final ColorStateList editTextColorStateList = new ColorStateList(new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled, -android.R.attr.state_pressed, -android.R.attr.state_focused}, |
|
||||||
new int[]{} |
|
||||||
}, new int[]{ |
|
||||||
ContextCompat.getColor(editText.getContext(), useDarker ? R.color.ate_text_disabled_dark : R.color.ate_text_disabled_light), |
|
||||||
ContextCompat.getColor(editText.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), |
|
||||||
color |
|
||||||
}); |
|
||||||
editText.setSupportBackgroundTintList(editTextColorStateList); |
|
||||||
setCursorTint(editText, color); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull CheckBox box, @ColorInt int color, boolean useDarker) { |
|
||||||
ColorStateList sl = new ColorStateList(new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} |
|
||||||
}, new int[]{ |
|
||||||
ContextCompat.getColor(box.getContext(), useDarker ? R.color.ate_control_disabled_dark : R.color.ate_control_disabled_light), |
|
||||||
ContextCompat.getColor(box.getContext(), useDarker ? R.color.ate_control_normal_dark : R.color.ate_control_normal_light), |
|
||||||
color |
|
||||||
}); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|
||||||
box.setButtonTintList(sl); |
|
||||||
} else { |
|
||||||
Drawable drawable = createTintedDrawable(ContextCompat.getDrawable(box.getContext(), R.drawable.abc_btn_check_material), sl); |
|
||||||
box.setButtonDrawable(drawable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull ImageView image, @ColorInt int color) { |
|
||||||
image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); |
|
||||||
} |
|
||||||
|
|
||||||
private static Drawable modifySwitchDrawable(@NonNull Context context, @NonNull Drawable from, @ColorInt int tint, boolean thumb, boolean compatSwitch, boolean useDarker) { |
|
||||||
if (useDarker) { |
|
||||||
tint = ColorUtil.shiftColor(tint, 1.1f); |
|
||||||
} |
|
||||||
tint = ColorUtil.adjustAlpha(tint, (compatSwitch && !thumb) ? 0.5f : 1.0f); |
|
||||||
int disabled; |
|
||||||
int normal; |
|
||||||
if (thumb) { |
|
||||||
disabled = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_thumb_disabled_dark : R.color.ate_switch_thumb_disabled_light); |
|
||||||
normal = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_thumb_normal_dark : R.color.ate_switch_thumb_normal_light); |
|
||||||
} else { |
|
||||||
disabled = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_track_disabled_dark : R.color.ate_switch_track_disabled_light); |
|
||||||
normal = ContextCompat.getColor(context, useDarker ? R.color.ate_switch_track_normal_dark : R.color.ate_switch_track_normal_light); |
|
||||||
} |
|
||||||
|
|
||||||
// Stock switch includes its own alpha
|
|
||||||
if (!compatSwitch) { |
|
||||||
normal = ColorUtil.stripAlpha(normal); |
|
||||||
} |
|
||||||
|
|
||||||
final ColorStateList sl = new ColorStateList( |
|
||||||
new int[][]{ |
|
||||||
new int[]{-android.R.attr.state_enabled}, |
|
||||||
new int[]{android.R.attr.state_enabled, -android.R.attr.state_activated, -android.R.attr.state_checked}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_activated}, |
|
||||||
new int[]{android.R.attr.state_enabled, android.R.attr.state_checked} |
|
||||||
}, |
|
||||||
new int[]{ |
|
||||||
disabled, |
|
||||||
normal, |
|
||||||
tint, |
|
||||||
tint |
|
||||||
} |
|
||||||
); |
|
||||||
return createTintedDrawable(from, sl); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull Switch switchView, @ColorInt int color, boolean useDarker) { |
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return; |
|
||||||
if (switchView.getTrackDrawable() != null) { |
|
||||||
switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), |
|
||||||
switchView.getTrackDrawable(), color, false, false, useDarker)); |
|
||||||
} |
|
||||||
if (switchView.getThumbDrawable() != null) { |
|
||||||
switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), |
|
||||||
switchView.getThumbDrawable(), color, true, false, useDarker)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setTint(@NonNull SwitchCompat switchView, @ColorInt int color, boolean useDarker) { |
|
||||||
if (switchView.getTrackDrawable() != null) { |
|
||||||
switchView.setTrackDrawable(modifySwitchDrawable(switchView.getContext(), |
|
||||||
switchView.getTrackDrawable(), color, false, true, useDarker)); |
|
||||||
} |
|
||||||
if (switchView.getThumbDrawable() != null) { |
|
||||||
switchView.setThumbDrawable(modifySwitchDrawable(switchView.getContext(), |
|
||||||
switchView.getThumbDrawable(), color, true, true, useDarker)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise.
|
|
||||||
@CheckResult |
|
||||||
@Nullable |
|
||||||
public static Drawable createTintedDrawable(@Nullable Drawable drawable, @ColorInt int color) { |
|
||||||
if (drawable == null) return null; |
|
||||||
drawable = DrawableCompat.wrap(drawable.mutate()); |
|
||||||
DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_IN); |
|
||||||
DrawableCompat.setTint(drawable, color); |
|
||||||
return drawable; |
|
||||||
} |
|
||||||
|
|
||||||
// This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise.
|
|
||||||
@CheckResult |
|
||||||
@Nullable |
|
||||||
public static Drawable createTintedDrawable(@Nullable Drawable drawable, @NonNull ColorStateList sl) { |
|
||||||
if (drawable == null) return null; |
|
||||||
drawable = DrawableCompat.wrap(drawable.mutate()); |
|
||||||
DrawableCompat.setTintList(drawable, sl); |
|
||||||
return drawable; |
|
||||||
} |
|
||||||
|
|
||||||
public static void setCursorTint(@NonNull EditText editText, @ColorInt int color) { |
|
||||||
try { |
|
||||||
Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); |
|
||||||
fCursorDrawableRes.setAccessible(true); |
|
||||||
int mCursorDrawableRes = fCursorDrawableRes.getInt(editText); |
|
||||||
Field fEditor = TextView.class.getDeclaredField("mEditor"); |
|
||||||
fEditor.setAccessible(true); |
|
||||||
Object editor = fEditor.get(editText); |
|
||||||
Class<?> clazz = editor.getClass(); |
|
||||||
Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable"); |
|
||||||
fCursorDrawable.setAccessible(true); |
|
||||||
Drawable[] drawables = new Drawable[2]; |
|
||||||
drawables[0] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); |
|
||||||
drawables[0] = createTintedDrawable(drawables[0], color); |
|
||||||
drawables[1] = ContextCompat.getDrawable(editText.getContext(), mCursorDrawableRes); |
|
||||||
drawables[1] = createTintedDrawable(drawables[1], color); |
|
||||||
fCursorDrawable.set(editor, drawables); |
|
||||||
} catch (Exception ignored) { |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,455 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.content.Context |
||||||
|
import android.content.res.ColorStateList |
||||||
|
import android.graphics.PorterDuff |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.graphics.drawable.RippleDrawable |
||||||
|
import android.os.Build |
||||||
|
import android.view.View |
||||||
|
import android.widget.* |
||||||
|
import androidx.annotation.CheckResult |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
import androidx.appcompat.widget.AppCompatEditText |
||||||
|
import androidx.appcompat.widget.SearchView |
||||||
|
import androidx.appcompat.widget.SwitchCompat |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import androidx.core.graphics.drawable.DrawableCompat |
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton |
||||||
|
import io.legado.app.R |
||||||
|
|
||||||
|
/** |
||||||
|
* @author afollestad, plusCubed |
||||||
|
*/ |
||||||
|
object TintHelper { |
||||||
|
|
||||||
|
@SuppressLint("PrivateResource") |
||||||
|
@ColorInt |
||||||
|
private fun getDefaultRippleColor(context: Context, useDarkRipple: Boolean): Int { |
||||||
|
// Light ripple is actually translucent black, and vice versa |
||||||
|
return ContextCompat.getColor( |
||||||
|
context, if (useDarkRipple) |
||||||
|
R.color.ripple_material_light |
||||||
|
else |
||||||
|
R.color.ripple_material_dark |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
private fun getDisabledColorStateList(@ColorInt normal: Int, @ColorInt disabled: Int): ColorStateList { |
||||||
|
return ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled) |
||||||
|
), intArrayOf(disabled, normal) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
fun setTintSelector(view: View, @ColorInt color: Int, darker: Boolean, useDarkTheme: Boolean) { |
||||||
|
val isColorLight = ColorUtil.isColorLight(color) |
||||||
|
val disabled = ContextCompat.getColor( |
||||||
|
view.context, |
||||||
|
if (useDarkTheme) R.color.ate_button_disabled_dark else R.color.ate_button_disabled_light |
||||||
|
) |
||||||
|
val pressed = ColorUtil.shiftColor(color, if (darker) 0.9f else 1.1f) |
||||||
|
val activated = ColorUtil.shiftColor(color, if (darker) 1.1f else 0.9f) |
||||||
|
val rippleColor = getDefaultRippleColor(view.context, isColorLight) |
||||||
|
val textColor = ContextCompat.getColor( |
||||||
|
view.context, |
||||||
|
if (isColorLight) R.color.ate_primary_text_light else R.color.ate_primary_text_dark |
||||||
|
) |
||||||
|
|
||||||
|
val sl: ColorStateList |
||||||
|
if (view is Button) { |
||||||
|
sl = getDisabledColorStateList(color, disabled) |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && view.getBackground() is RippleDrawable) { |
||||||
|
val rd = view.getBackground() as RippleDrawable |
||||||
|
rd.setColor(ColorStateList.valueOf(rippleColor)) |
||||||
|
} |
||||||
|
|
||||||
|
// Disabled text color state for buttons, may get overridden later by ATE tags |
||||||
|
view.setTextColor( |
||||||
|
getDisabledColorStateList( |
||||||
|
textColor, |
||||||
|
ContextCompat.getColor( |
||||||
|
view.getContext(), |
||||||
|
if (useDarkTheme) R.color.ate_button_text_disabled_dark else R.color.ate_button_text_disabled_light |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
} else if (view is FloatingActionButton) { |
||||||
|
// FloatingActionButton doesn't support disabled state? |
||||||
|
sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_pressed), |
||||||
|
intArrayOf(android.R.attr.state_pressed) |
||||||
|
), intArrayOf(color, pressed) |
||||||
|
) |
||||||
|
|
||||||
|
view.rippleColor = rippleColor |
||||||
|
view.backgroundTintList = sl |
||||||
|
if (view.drawable != null) |
||||||
|
view.setImageDrawable(createTintedDrawable(view.drawable, textColor)) |
||||||
|
return |
||||||
|
} else { |
||||||
|
sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_activated), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) |
||||||
|
), |
||||||
|
intArrayOf(disabled, color, pressed, activated, activated) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
var drawable: Drawable? = view.background |
||||||
|
if (drawable != null) { |
||||||
|
drawable = createTintedDrawable(drawable, sl) |
||||||
|
ViewUtil.setBackgroundCompat(view, drawable) |
||||||
|
} |
||||||
|
|
||||||
|
if (view is TextView && view !is Button) { |
||||||
|
view.setTextColor( |
||||||
|
getDisabledColorStateList( |
||||||
|
textColor, |
||||||
|
ContextCompat.getColor( |
||||||
|
view.getContext(), |
||||||
|
if (isColorLight) R.color.ate_text_disabled_light else R.color.ate_text_disabled_dark |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTintAuto( |
||||||
|
view: View, @ColorInt color: Int, |
||||||
|
background: Boolean |
||||||
|
) { |
||||||
|
setTintAuto(view, color, background, ATHUtil.isWindowBackgroundDark(view.context)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setTintAuto( |
||||||
|
view: View, @ColorInt color: Int, |
||||||
|
background: Boolean, isDark: Boolean |
||||||
|
) { |
||||||
|
var background = background |
||||||
|
if (!background) { |
||||||
|
if (view is RadioButton) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is SeekBar) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is ProgressBar) |
||||||
|
setTint(view, color) |
||||||
|
else if (view is AppCompatEditText) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is CheckBox) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is ImageView) |
||||||
|
setTint(view, color) |
||||||
|
else if (view is Switch) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is SwitchCompat) |
||||||
|
setTint(view, color, isDark) |
||||||
|
else if (view is SearchView) { |
||||||
|
val iconIdS = |
||||||
|
intArrayOf(androidx.appcompat.R.id.search_button, androidx.appcompat.R.id.search_close_btn) |
||||||
|
for (iconId in iconIdS) { |
||||||
|
val icon = view.findViewById<ImageView>(iconId) |
||||||
|
if (icon != null) { |
||||||
|
setTint(icon, color) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
background = true |
||||||
|
} |
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && |
||||||
|
!background && view.background is RippleDrawable |
||||||
|
) { |
||||||
|
// Ripples for the above views (e.g. when you tap and hold a switch or checkbox) |
||||||
|
val rd = view.background as RippleDrawable |
||||||
|
@SuppressLint("PrivateResource") val unchecked = ContextCompat.getColor( |
||||||
|
view.context, |
||||||
|
if (isDark) R.color.ripple_material_dark else R.color.ripple_material_light |
||||||
|
) |
||||||
|
val checked = ColorUtil.adjustAlpha(color, 0.4f) |
||||||
|
val sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_activated, -android.R.attr.state_checked), |
||||||
|
intArrayOf(android.R.attr.state_activated), |
||||||
|
intArrayOf(android.R.attr.state_checked) |
||||||
|
), |
||||||
|
intArrayOf(unchecked, checked, checked) |
||||||
|
) |
||||||
|
rd.setColor(sl) |
||||||
|
} |
||||||
|
} |
||||||
|
if (background) { |
||||||
|
// Need to tint the background of a view |
||||||
|
if (view is FloatingActionButton || view is Button) { |
||||||
|
setTintSelector(view, color, false, isDark) |
||||||
|
} else if (view.background != null) { |
||||||
|
var drawable: Drawable? = view.background |
||||||
|
if (drawable != null) { |
||||||
|
drawable = createTintedDrawable(drawable, color) |
||||||
|
ViewUtil.setBackgroundCompat(view, drawable) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(radioButton: RadioButton, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
val sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) |
||||||
|
), intArrayOf( |
||||||
|
// Rdio button includes own alpha for disabled state |
||||||
|
ColorUtil.stripAlpha( |
||||||
|
ContextCompat.getColor( |
||||||
|
radioButton.context, |
||||||
|
if (useDarker) R.color.ate_control_disabled_dark else R.color.ate_control_disabled_light |
||||||
|
) |
||||||
|
), |
||||||
|
ContextCompat.getColor( |
||||||
|
radioButton.context, |
||||||
|
if (useDarker) R.color.ate_control_normal_dark else R.color.ate_control_normal_light |
||||||
|
), |
||||||
|
color |
||||||
|
) |
||||||
|
) |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
radioButton.buttonTintList = sl |
||||||
|
} else { |
||||||
|
val d = createTintedDrawable( |
||||||
|
ContextCompat.getDrawable(radioButton.context, R.drawable.abc_btn_radio_material), |
||||||
|
sl |
||||||
|
) |
||||||
|
radioButton.buttonDrawable = d |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(seekBar: SeekBar, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
val s1 = getDisabledColorStateList( |
||||||
|
color, |
||||||
|
ContextCompat.getColor( |
||||||
|
seekBar.context, |
||||||
|
if (useDarker) R.color.ate_control_disabled_dark else R.color.ate_control_disabled_light |
||||||
|
) |
||||||
|
) |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
seekBar.thumbTintList = s1 |
||||||
|
seekBar.progressTintList = s1 |
||||||
|
} else { |
||||||
|
val progressDrawable = createTintedDrawable(seekBar.progressDrawable, s1) |
||||||
|
seekBar.progressDrawable = progressDrawable |
||||||
|
val thumbDrawable = createTintedDrawable(seekBar.thumb, s1) |
||||||
|
seekBar.thumb = thumbDrawable |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@JvmOverloads |
||||||
|
fun setTint(progressBar: ProgressBar, @ColorInt color: Int, skipIndeterminate: Boolean = false) { |
||||||
|
val sl = ColorStateList.valueOf(color) |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
progressBar.progressTintList = sl |
||||||
|
progressBar.secondaryProgressTintList = sl |
||||||
|
if (!skipIndeterminate) |
||||||
|
progressBar.indeterminateTintList = sl |
||||||
|
} else { |
||||||
|
val mode = PorterDuff.Mode.SRC_IN |
||||||
|
if (!skipIndeterminate && progressBar.indeterminateDrawable != null) |
||||||
|
progressBar.indeterminateDrawable.setColorFilter(color, mode) |
||||||
|
if (progressBar.progressDrawable != null) |
||||||
|
progressBar.progressDrawable.setColorFilter(color, mode) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi") |
||||||
|
fun setTint(editText: AppCompatEditText, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
val editTextColorStateList = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_pressed, -android.R.attr.state_focused), |
||||||
|
intArrayOf() |
||||||
|
), |
||||||
|
intArrayOf( |
||||||
|
ContextCompat.getColor( |
||||||
|
editText.context, |
||||||
|
if (useDarker) R.color.ate_text_disabled_dark else R.color.ate_text_disabled_light |
||||||
|
), |
||||||
|
ContextCompat.getColor( |
||||||
|
editText.context, |
||||||
|
if (useDarker) R.color.ate_control_normal_dark else R.color.ate_control_normal_light |
||||||
|
), |
||||||
|
color |
||||||
|
) |
||||||
|
) |
||||||
|
editText.supportBackgroundTintList = editTextColorStateList |
||||||
|
setCursorTint(editText, color) |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(box: CheckBox, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
val sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) |
||||||
|
), |
||||||
|
intArrayOf( |
||||||
|
ContextCompat.getColor( |
||||||
|
box.context, |
||||||
|
if (useDarker) R.color.ate_control_disabled_dark else R.color.ate_control_disabled_light |
||||||
|
), |
||||||
|
ContextCompat.getColor( |
||||||
|
box.context, |
||||||
|
if (useDarker) R.color.ate_control_normal_dark else R.color.ate_control_normal_light |
||||||
|
), |
||||||
|
color |
||||||
|
) |
||||||
|
) |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||||
|
box.buttonTintList = sl |
||||||
|
} else { |
||||||
|
val drawable = |
||||||
|
createTintedDrawable(ContextCompat.getDrawable(box.context, R.drawable.abc_btn_check_material), sl) |
||||||
|
box.buttonDrawable = drawable |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(image: ImageView, @ColorInt color: Int) { |
||||||
|
image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP) |
||||||
|
} |
||||||
|
|
||||||
|
private fun modifySwitchDrawable( |
||||||
|
context: Context, |
||||||
|
from: Drawable, @ColorInt tint: Int, |
||||||
|
thumb: Boolean, |
||||||
|
compatSwitch: Boolean, |
||||||
|
useDarker: Boolean |
||||||
|
): Drawable? { |
||||||
|
var tint = tint |
||||||
|
if (useDarker) { |
||||||
|
tint = ColorUtil.shiftColor(tint, 1.1f) |
||||||
|
} |
||||||
|
tint = ColorUtil.adjustAlpha(tint, if (compatSwitch && !thumb) 0.5f else 1.0f) |
||||||
|
val disabled: Int |
||||||
|
var normal: Int |
||||||
|
if (thumb) { |
||||||
|
disabled = ContextCompat.getColor( |
||||||
|
context, |
||||||
|
if (useDarker) R.color.ate_switch_thumb_disabled_dark else R.color.ate_switch_thumb_disabled_light |
||||||
|
) |
||||||
|
normal = ContextCompat.getColor( |
||||||
|
context, |
||||||
|
if (useDarker) R.color.ate_switch_thumb_normal_dark else R.color.ate_switch_thumb_normal_light |
||||||
|
) |
||||||
|
} else { |
||||||
|
disabled = ContextCompat.getColor( |
||||||
|
context, |
||||||
|
if (useDarker) R.color.ate_switch_track_disabled_dark else R.color.ate_switch_track_disabled_light |
||||||
|
) |
||||||
|
normal = ContextCompat.getColor( |
||||||
|
context, |
||||||
|
if (useDarker) R.color.ate_switch_track_normal_dark else R.color.ate_switch_track_normal_light |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
// Stock switch includes its own alpha |
||||||
|
if (!compatSwitch) { |
||||||
|
normal = ColorUtil.stripAlpha(normal) |
||||||
|
} |
||||||
|
|
||||||
|
val sl = ColorStateList( |
||||||
|
arrayOf( |
||||||
|
intArrayOf(-android.R.attr.state_enabled), |
||||||
|
intArrayOf( |
||||||
|
android.R.attr.state_enabled, |
||||||
|
-android.R.attr.state_activated, |
||||||
|
-android.R.attr.state_checked |
||||||
|
), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_activated), |
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) |
||||||
|
), |
||||||
|
intArrayOf(disabled, normal, tint, tint) |
||||||
|
) |
||||||
|
return createTintedDrawable(from, sl) |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(switchView: Switch, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return |
||||||
|
if (switchView.trackDrawable != null) { |
||||||
|
switchView.trackDrawable = modifySwitchDrawable( |
||||||
|
switchView.context, |
||||||
|
switchView.trackDrawable, color, false, false, useDarker |
||||||
|
) |
||||||
|
} |
||||||
|
if (switchView.thumbDrawable != null) { |
||||||
|
switchView.thumbDrawable = modifySwitchDrawable( |
||||||
|
switchView.context, |
||||||
|
switchView.thumbDrawable, color, true, false, useDarker |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setTint(switchView: SwitchCompat, @ColorInt color: Int, useDarker: Boolean) { |
||||||
|
if (switchView.trackDrawable != null) { |
||||||
|
switchView.trackDrawable = modifySwitchDrawable( |
||||||
|
switchView.context, |
||||||
|
switchView.trackDrawable, color, false, true, useDarker |
||||||
|
) |
||||||
|
} |
||||||
|
if (switchView.thumbDrawable != null) { |
||||||
|
switchView.thumbDrawable = modifySwitchDrawable( |
||||||
|
switchView.context, |
||||||
|
switchView.thumbDrawable, color, true, true, useDarker |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. |
||||||
|
@CheckResult |
||||||
|
fun createTintedDrawable(drawable: Drawable?, @ColorInt color: Int): Drawable? { |
||||||
|
var drawable: Drawable? = drawable ?: return null |
||||||
|
drawable = DrawableCompat.wrap(drawable!!.mutate()) |
||||||
|
DrawableCompat.setTintMode(drawable!!, PorterDuff.Mode.SRC_IN) |
||||||
|
DrawableCompat.setTint(drawable, color) |
||||||
|
return drawable |
||||||
|
} |
||||||
|
|
||||||
|
// This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. |
||||||
|
@CheckResult |
||||||
|
fun createTintedDrawable(drawable: Drawable?, sl: ColorStateList): Drawable? { |
||||||
|
var drawable: Drawable? = drawable ?: return null |
||||||
|
drawable = DrawableCompat.wrap(drawable!!.mutate()) |
||||||
|
DrawableCompat.setTintList(drawable!!, sl) |
||||||
|
return drawable |
||||||
|
} |
||||||
|
|
||||||
|
fun setCursorTint(editText: EditText, @ColorInt color: Int) { |
||||||
|
try { |
||||||
|
val fCursorDrawableRes = TextView::class.java.getDeclaredField("mCursorDrawableRes") |
||||||
|
fCursorDrawableRes.isAccessible = true |
||||||
|
val mCursorDrawableRes = fCursorDrawableRes.getInt(editText) |
||||||
|
val fEditor = TextView::class.java.getDeclaredField("mEditor") |
||||||
|
fEditor.isAccessible = true |
||||||
|
val editor = fEditor.get(editText) |
||||||
|
val clazz = editor.javaClass |
||||||
|
val fCursorDrawable = clazz.getDeclaredField("mCursorDrawable") |
||||||
|
fCursorDrawable.isAccessible = true |
||||||
|
val drawables = arrayOfNulls<Drawable>(2) |
||||||
|
drawables[0] = ContextCompat.getDrawable(editText.context, mCursorDrawableRes) |
||||||
|
drawables[0] = createTintedDrawable(drawables[0], color) |
||||||
|
drawables[1] = ContextCompat.getDrawable(editText.context, mCursorDrawableRes) |
||||||
|
drawables[1] = createTintedDrawable(drawables[1], color) |
||||||
|
fCursorDrawable.set(editor, drawables) |
||||||
|
} catch (ignored: Exception) { |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -1,48 +0,0 @@ |
|||||||
package io.legado.app.lib.theme; |
|
||||||
|
|
||||||
import android.graphics.drawable.ColorDrawable; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.graphics.drawable.TransitionDrawable; |
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewTreeObserver; |
|
||||||
import androidx.annotation.ColorInt; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Karim Abou Zeid (kabouzeid) |
|
||||||
*/ |
|
||||||
public final class ViewUtil { |
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") |
|
||||||
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener) { |
|
||||||
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") |
|
||||||
public static void setBackgroundCompat(@NonNull View view, @Nullable Drawable drawable) { |
|
||||||
view.setBackground(drawable); |
|
||||||
} |
|
||||||
|
|
||||||
public static TransitionDrawable setBackgroundTransition(@NonNull View view, @NonNull Drawable newDrawable) { |
|
||||||
TransitionDrawable transition = DrawableUtil.createTransitionDrawable(view.getBackground(), newDrawable); |
|
||||||
setBackgroundCompat(view, transition); |
|
||||||
return transition; |
|
||||||
} |
|
||||||
|
|
||||||
public static TransitionDrawable setBackgroundColorTransition(@NonNull View view, @ColorInt int newColor) { |
|
||||||
final Drawable oldColor = view.getBackground(); |
|
||||||
|
|
||||||
Drawable start = oldColor != null ? oldColor : new ColorDrawable(view.getSolidColor()); |
|
||||||
Drawable end = new ColorDrawable(newColor); |
|
||||||
|
|
||||||
TransitionDrawable transition = DrawableUtil.createTransitionDrawable(start, end); |
|
||||||
|
|
||||||
setBackgroundCompat(view, transition); |
|
||||||
|
|
||||||
return transition; |
|
||||||
} |
|
||||||
|
|
||||||
private ViewUtil() { |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,41 @@ |
|||||||
|
package io.legado.app.lib.theme |
||||||
|
|
||||||
|
import android.graphics.drawable.ColorDrawable |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.graphics.drawable.TransitionDrawable |
||||||
|
import android.view.View |
||||||
|
import android.view.ViewTreeObserver |
||||||
|
import androidx.annotation.ColorInt |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Karim Abou Zeid (kabouzeid) |
||||||
|
*/ |
||||||
|
object ViewUtil { |
||||||
|
|
||||||
|
fun removeOnGlobalLayoutListener(v: View, listener: ViewTreeObserver.OnGlobalLayoutListener) { |
||||||
|
v.viewTreeObserver.removeOnGlobalLayoutListener(listener) |
||||||
|
} |
||||||
|
|
||||||
|
fun setBackgroundCompat(view: View, drawable: Drawable?) { |
||||||
|
view.background = drawable |
||||||
|
} |
||||||
|
|
||||||
|
fun setBackgroundTransition(view: View, newDrawable: Drawable): TransitionDrawable { |
||||||
|
val transition = DrawableUtil.createTransitionDrawable(view.background, newDrawable) |
||||||
|
setBackgroundCompat(view, transition) |
||||||
|
return transition |
||||||
|
} |
||||||
|
|
||||||
|
fun setBackgroundColorTransition(view: View, @ColorInt newColor: Int): TransitionDrawable { |
||||||
|
val oldColor = view.background |
||||||
|
|
||||||
|
val start = oldColor ?: ColorDrawable(view.solidColor) |
||||||
|
val end = ColorDrawable(newColor) |
||||||
|
|
||||||
|
val transition = DrawableUtil.createTransitionDrawable(start, end) |
||||||
|
|
||||||
|
setBackgroundCompat(view, transition) |
||||||
|
|
||||||
|
return transition |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue