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