Covert to kotlin
This commit is contained in:
parent
79e0db37ef
commit
a773074c77
51 changed files with 2817 additions and 0 deletions
119
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATH.kt
Executable file
119
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATH.kt
Executable file
|
@ -0,0 +1,119 @@
|
||||||
|
package code.name.monkey.appthemehelper
|
||||||
|
|
||||||
|
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 androidx.annotation.ColorInt
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
|
|
||||||
|
import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.O) {
|
||||||
|
activity.window.navigationBarColor = color
|
||||||
|
} else {
|
||||||
|
activity.window.navigationBarColor = ColorUtil.darkenColor(color)
|
||||||
|
}
|
||||||
|
setLightNavigationbarAuto(activity, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setActivityToolbarColorAuto(activity: Activity, toolbar: Toolbar?) {
|
||||||
|
setActivityToolbarColor(activity, toolbar, ThemeStore.primaryColor(activity))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setActivityToolbarColor(activity: Activity, toolbar: Toolbar?,
|
||||||
|
color: Int) {
|
||||||
|
if (toolbar == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toolbar.setBackgroundColor(color)
|
||||||
|
ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(activity, toolbar, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTaskDescriptionColorAuto(activity: Activity) {
|
||||||
|
setTaskDescriptionColor(activity, ThemeStore.primaryColor(activity))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTaskDescriptionColor(activity: Activity, @ColorInt color: Int) {
|
||||||
|
var colorFinal = color
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// Task description requires fully opaque color
|
||||||
|
colorFinal = ColorUtil.stripAlpha(colorFinal)
|
||||||
|
// Sets color of entry in the system recents page
|
||||||
|
activity.setTaskDescription(ActivityManager.TaskDescription(activity.title as String, null, colorFinal))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTint(view: View, @ColorInt color: Int) {
|
||||||
|
TintHelper.setTintAuto(view, color, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBackgroundTint(view: View, @ColorInt color: Int) {
|
||||||
|
TintHelper.setTintAuto(view, color, true)
|
||||||
|
}
|
||||||
|
}
|
43
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATHActivity.kt
Executable file
43
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ATHActivity.kt
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
package code.name.monkey.appthemehelper
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
open class ATHActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private var updateTime: Long = -1
|
||||||
|
|
||||||
|
private val themeRes: Int
|
||||||
|
@StyleRes
|
||||||
|
get() = ThemeStore.activityTheme(this)
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
setTheme(themeRes)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
updateTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (ATH.didThemeValuesChange(this, updateTime)) {
|
||||||
|
onThemeChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onThemeChanged() {
|
||||||
|
postRecreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postRecreate() {
|
||||||
|
// hack to prevent java.lang.RuntimeException: Performing pause of activity that is not resumed
|
||||||
|
// makes sure recreate() is called right after and not in onResume()
|
||||||
|
Handler().post { recreate() }
|
||||||
|
}
|
||||||
|
}
|
288
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ThemeStore.kt
Executable file
288
appthemehelper/src/main/java/code/name/monkey/appthemehelper/ThemeStore.kt
Executable file
|
@ -0,0 +1,288 @@
|
||||||
|
package code.name.monkey.appthemehelper
|
||||||
|
|
||||||
|
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.annotation.IntRange
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 activityTheme(@StyleRes theme: Int): ThemeStore {
|
||||||
|
mEditor.putInt(ThemeStorePrefKeys.KEY_ACTIVITY_THEME, theme)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit method
|
||||||
|
|
||||||
|
override fun navigationBarColorRes(@ColorRes colorRes: Int): ThemeStore {
|
||||||
|
return navigationBarColor(ContextCompat.getColor(mContext, colorRes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static getters
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun commit() {
|
||||||
|
mEditor.putLong(ThemeStorePrefKeys.VALUES_CHANGED, System.currentTimeMillis())
|
||||||
|
.putBoolean(ThemeStorePrefKeys.IS_CONFIGURED_KEY, true)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun editTheme(context: Context): ThemeStore {
|
||||||
|
return ThemeStore(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
protected fun prefs(context: Context): SharedPreferences {
|
||||||
|
return context.getSharedPreferences(ThemeStorePrefKeys.CONFIG_PREFS_KEY_DEFAULT, Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun markChanged(context: Context) {
|
||||||
|
ThemeStore(context).commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
@StyleRes
|
||||||
|
fun activityTheme(context: Context): Int {
|
||||||
|
return prefs(context).getInt(ThemeStorePrefKeys.KEY_ACTIVITY_THEME, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
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, @IntRange(from = 0, to = Integer.MAX_VALUE.toLong()) 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).commit()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package code.name.monkey.appthemehelper
|
||||||
|
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
internal interface ThemeStoreInterface {
|
||||||
|
|
||||||
|
// Activity theme
|
||||||
|
|
||||||
|
fun activityTheme(@StyleRes theme: Int): ThemeStore
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Toggle configurations
|
||||||
|
|
||||||
|
fun coloredStatusBar(colored: Boolean): ThemeStore
|
||||||
|
|
||||||
|
fun coloredNavigationBar(applyToNavBar: Boolean): ThemeStore
|
||||||
|
|
||||||
|
// Commit/apply
|
||||||
|
|
||||||
|
fun commit()
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package code.name.monkey.appthemehelper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
internal interface ThemeStorePrefKeys {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val CONFIG_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
||||||
|
const val IS_CONFIGURED_KEY = "is_configured"
|
||||||
|
const val IS_CONFIGURED_VERSION_KEY = "is_configured_version"
|
||||||
|
const val VALUES_CHANGED = "values_changed"
|
||||||
|
|
||||||
|
const val KEY_ACTIVITY_THEME = "activity_theme"
|
||||||
|
|
||||||
|
const val KEY_PRIMARY_COLOR = "primary_color"
|
||||||
|
const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark"
|
||||||
|
const val KEY_ACCENT_COLOR = "accent_color"
|
||||||
|
const val KEY_STATUS_BAR_COLOR = "status_bar_color"
|
||||||
|
const val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color"
|
||||||
|
|
||||||
|
const val KEY_TEXT_COLOR_PRIMARY = "text_color_primary"
|
||||||
|
const val KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse"
|
||||||
|
const val KEY_TEXT_COLOR_SECONDARY = "text_color_secondary"
|
||||||
|
const val KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse"
|
||||||
|
|
||||||
|
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
|
||||||
|
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
|
||||||
|
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package code.name.monkey.appthemehelper.common
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
|
|
||||||
|
class ATHActionBarActivity : ATHToolbarActivity() {
|
||||||
|
|
||||||
|
override fun getATHToolbar(): Toolbar? {
|
||||||
|
return ToolbarContentTintHelper.getSupportActionBarView(supportActionBar)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.preference.CheckBoxPreference
|
||||||
|
import android.preference.Preference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATECheckBoxPreference @TargetApi(Build.VERSION_CODES.LOLLIPOP) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : CheckBoxPreference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
|
||||||
|
try {
|
||||||
|
val canRecycleLayoutField = Preference::class.java.getDeclaredField("mCanRecycleLayout")
|
||||||
|
canRecycleLayoutField.isAccessible = true
|
||||||
|
canRecycleLayoutField.setBoolean(this, true)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val hasSpecifiedLayout = Preference::class.java.getDeclaredField("mHasSpecifiedLayout")
|
||||||
|
hasSpecifiedLayout.isAccessible = true
|
||||||
|
hasSpecifiedLayout.setBoolean(this, true)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindView(view: View) {
|
||||||
|
super.onBindView(view)
|
||||||
|
|
||||||
|
val parentCheckbox = findCheckboxView(view)
|
||||||
|
if (parentCheckbox != null) {
|
||||||
|
ATH.setTint(parentCheckbox, ThemeStore.accentColor(view.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findCheckboxView(view: View): View? {
|
||||||
|
if (view is ViewGroup) {
|
||||||
|
for (i in 0 until view.childCount) {
|
||||||
|
val child = view.getChildAt(i)
|
||||||
|
if (child is CheckBox) {
|
||||||
|
return child
|
||||||
|
} else if (child is ViewGroup) {
|
||||||
|
val potentialCheckbox = findCheckboxView(child)
|
||||||
|
if (potentialCheckbox != null) return potentialCheckbox
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (view is CheckBox) {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.preference.Preference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEColorPreference(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : Preference(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private var mView: View? = null
|
||||||
|
private var color: Int = 0
|
||||||
|
private var border: Int = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
widgetLayoutResource = R.layout.ate_preference_color
|
||||||
|
isPersistent = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindView(view: View) {
|
||||||
|
super.onBindView(view)
|
||||||
|
mView = view
|
||||||
|
invalidateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setColor(color: Int, border: Int) {
|
||||||
|
this.color = color
|
||||||
|
this.border = border
|
||||||
|
invalidateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidateColor() {
|
||||||
|
if (mView != null) {
|
||||||
|
val circle = mView!!.findViewById<View>(R.id.circle) as BorderCircleView
|
||||||
|
if (this.color != 0) {
|
||||||
|
circle.visibility = View.VISIBLE
|
||||||
|
circle.setBackgroundColor(color)
|
||||||
|
circle.setBorderColor(border)
|
||||||
|
} else {
|
||||||
|
circle.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
import com.afollestad.materialdialogs.prefs.MaterialDialogPreference
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEDialogPreference(context: Context) : MaterialDialogPreference(context) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.prefs.MaterialEditTextPreference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEEditTextPreference(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : MaterialEditTextPreference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = code.name.monkey.appthemehelper.R.layout.ate_preference_custom
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEListPreference : MaterialListPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
if (summary == null || summary.toString().trim { it <= ' ' }.isEmpty())
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEMultiSelectPreference(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : MaterialListPreference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.preference.Preference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEPreference @TargetApi(Build.VERSION_CODES.LOLLIPOP) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : Preference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.preference.PreferenceCategory
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
class ATEPreferenceCategory @TargetApi(Build.VERSION_CODES.LOLLIPOP) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : PreferenceCategory(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
override fun onBindView(view: View) {
|
||||||
|
super.onBindView(view)
|
||||||
|
val mTitle = view.findViewById<View>(android.R.id.title) as TextView
|
||||||
|
mTitle.setTextColor(ThemeStore.accentColor(view.context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.preference.Preference
|
||||||
|
import android.preference.SwitchPreference
|
||||||
|
import androidx.appcompat.widget.SwitchCompat
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Switch
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.appthemehelper.common.views.ATESwitch
|
||||||
|
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATESwitchPreference : SwitchPreference {
|
||||||
|
|
||||||
|
private var mSwitch: ATESwitch? = null
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom
|
||||||
|
if (COMPAT_MODE) {
|
||||||
|
widgetLayoutResource = R.layout.ate_preference_switch
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
val canRecycleLayoutField = Preference::class.java.getDeclaredField("mCanRecycleLayout")
|
||||||
|
canRecycleLayoutField.isAccessible = true
|
||||||
|
canRecycleLayoutField.setBoolean(this, true)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val hasSpecifiedLayout = Preference::class.java.getDeclaredField("mHasSpecifiedLayout")
|
||||||
|
hasSpecifiedLayout.isAccessible = true
|
||||||
|
hasSpecifiedLayout.setBoolean(this, true)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindView(view: View) {
|
||||||
|
super.onBindView(view)
|
||||||
|
if (COMPAT_MODE) {
|
||||||
|
mSwitch = view.findViewById<View>(R.id.switchWidget) as ATESwitch
|
||||||
|
mSwitch!!.isChecked = isChecked
|
||||||
|
} else {
|
||||||
|
val parentSwitch = findSwitchView(view)
|
||||||
|
if (parentSwitch != null) {
|
||||||
|
ATH.setTint(parentSwitch, ThemeStore.accentColor(view.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findSwitchView(view: View): View? {
|
||||||
|
if (view is ViewGroup) {
|
||||||
|
for (i in 0 until view.childCount) {
|
||||||
|
val child = view.getChildAt(i)
|
||||||
|
if (child is Switch || child is SwitchCompat) {
|
||||||
|
return child
|
||||||
|
} else if (child is ViewGroup) {
|
||||||
|
val potentialSwitch = findSwitchView(child)
|
||||||
|
if (potentialSwitch != null) return potentialSwitch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (view is Switch || view is SwitchCompat) {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChecked(checked: Boolean) {
|
||||||
|
super.setChecked(checked)
|
||||||
|
if (COMPAT_MODE) {
|
||||||
|
if (mSwitch != null) {
|
||||||
|
mSwitch!!.isChecked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
internal val COMPAT_MODE = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
class BorderCircleView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private val mCheck: Drawable? = ContextCompat.getDrawable(context, R.drawable.ate_check)
|
||||||
|
private val paint: Paint = Paint()
|
||||||
|
private val paintBorder: Paint
|
||||||
|
private val borderWidth: Int = resources.getDimension(R.dimen.ate_circleview_border).toInt()
|
||||||
|
|
||||||
|
private var paintCheck: Paint? = null
|
||||||
|
private var blackFilter: PorterDuffColorFilter? = null
|
||||||
|
private var whiteFilter: PorterDuffColorFilter? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
paint.isAntiAlias = true
|
||||||
|
|
||||||
|
paintBorder = Paint()
|
||||||
|
paintBorder.isAntiAlias = true
|
||||||
|
paintBorder.color = Color.BLACK
|
||||||
|
|
||||||
|
setWillNotDraw(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBackgroundColor(color: Int) {
|
||||||
|
paint.color = color
|
||||||
|
requestLayout()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBorderColor(color: Int) {
|
||||||
|
paintBorder.color = color
|
||||||
|
requestLayout()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
val widthMode = View.MeasureSpec.getMode(widthMeasureSpec)
|
||||||
|
val heightMode = View.MeasureSpec.getMode(heightMeasureSpec)
|
||||||
|
if (widthMode == View.MeasureSpec.EXACTLY && heightMode != View.MeasureSpec.EXACTLY) {
|
||||||
|
val width = View.MeasureSpec.getSize(widthMeasureSpec)
|
||||||
|
|
||||||
|
var height = width
|
||||||
|
if (heightMode == View.MeasureSpec.AT_MOST) {
|
||||||
|
height = Math.min(height, View.MeasureSpec.getSize(heightMeasureSpec))
|
||||||
|
}
|
||||||
|
setMeasuredDimension(width, height)
|
||||||
|
} else {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
|
||||||
|
var canvasSize = canvas.width
|
||||||
|
if (canvas.height < canvasSize) {
|
||||||
|
canvasSize = canvas.height
|
||||||
|
}
|
||||||
|
|
||||||
|
val circleCenter = (canvasSize - borderWidth * 2) / 2
|
||||||
|
canvas.drawCircle((circleCenter + borderWidth).toFloat(), (circleCenter + borderWidth).toFloat(), (canvasSize - borderWidth * 2) / 2 + borderWidth - 4.0f, paintBorder)
|
||||||
|
canvas.drawCircle((circleCenter + borderWidth).toFloat(), (circleCenter + borderWidth).toFloat(), (canvasSize - borderWidth * 2) / 2 - 4.0f, paint)
|
||||||
|
|
||||||
|
if (isActivated) {
|
||||||
|
val offset = canvasSize / 2 - mCheck!!.intrinsicWidth / 2
|
||||||
|
if (paintCheck == null) {
|
||||||
|
paintCheck = Paint()
|
||||||
|
paintCheck!!.isAntiAlias = true
|
||||||
|
}
|
||||||
|
if (whiteFilter == null || blackFilter == null) {
|
||||||
|
blackFilter = PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN)
|
||||||
|
whiteFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
|
||||||
|
}
|
||||||
|
if (paint.color == Color.WHITE) {
|
||||||
|
paintCheck!!.colorFilter = blackFilter
|
||||||
|
} else {
|
||||||
|
paintCheck!!.colorFilter = whiteFilter
|
||||||
|
}
|
||||||
|
mCheck.setBounds(offset, offset, mCheck.intrinsicWidth - offset, mCheck.intrinsicHeight - offset)
|
||||||
|
mCheck.draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.preference.CheckBoxPreference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATECheckBoxPreference : CheckBoxPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
widgetLayoutResource = R.layout.ate_preference_checkbox
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceViewHolder
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.BorderCircleView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEColorPreference(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : Preference(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private var mView: View? = null
|
||||||
|
private var color: Int = 0
|
||||||
|
private var border: Int = 0
|
||||||
|
|
||||||
|
constructor(context: Context) : this(context, null, 0) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
init(context, attrs)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
widgetLayoutResource = R.layout.ate_preference_color
|
||||||
|
isPersistent = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
|
super.onBindViewHolder(holder)
|
||||||
|
mView = holder.itemView
|
||||||
|
invalidateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setColor(color: Int, border: Int) {
|
||||||
|
this.color = color
|
||||||
|
this.border = border
|
||||||
|
invalidateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidateColor() {
|
||||||
|
if (mView != null) {
|
||||||
|
val circle = mView!!.findViewById<View>(R.id.circle) as BorderCircleView
|
||||||
|
if (this.color != 0) {
|
||||||
|
circle.visibility = View.VISIBLE
|
||||||
|
circle.setBackgroundColor(color)
|
||||||
|
circle.setBorderColor(border)
|
||||||
|
} else {
|
||||||
|
circle.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.DialogPreference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
open class ATEDialogPreference : DialogPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEEditTextPreference : EditTextPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEListPreference : ListPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
if (summary == null || summary.toString().trim { it <= ' ' }.isEmpty())
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEPreference : Preference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.preference.PreferenceCategory
|
||||||
|
import androidx.preference.PreferenceViewHolder
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
class ATEPreferenceCategory : PreferenceCategory {
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
|
super.onBindViewHolder(holder)
|
||||||
|
val mTitle = holder.itemView as TextView
|
||||||
|
mTitle.setTextColor(ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_category
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs.ATEEditTextPreferenceDialogFragmentCompat
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs.ATEListPreferenceDialogFragmentCompat
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs.ATEPreferenceDialogFragment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
abstract class ATEPreferenceFragmentCompat : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
|
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||||
|
if (this.callbackFragment is PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback) {
|
||||||
|
(this.callbackFragment as PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback).onPreferenceDisplayDialog(this, preference)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.activity is PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback) {
|
||||||
|
(this.activity as PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback).onPreferenceDisplayDialog(this, preference)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fragmentManager!!.findFragmentByTag("android.support.v7.preference.PreferenceFragment.DIALOG") == null) {
|
||||||
|
val dialogFragment = onCreatePreferenceDialog(preference)
|
||||||
|
|
||||||
|
if (dialogFragment != null) {
|
||||||
|
dialogFragment.setTargetFragment(this, 0)
|
||||||
|
dialogFragment.show(this.fragmentManager!!, "android.support.v7.preference.PreferenceFragment.DIALOG")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onDisplayPreferenceDialog(preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onCreatePreferenceDialog(preference: Preference): DialogFragment? {
|
||||||
|
if (preference is ATEEditTextPreference) {
|
||||||
|
return ATEEditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey())
|
||||||
|
} else if (preference is ATEListPreference) {
|
||||||
|
return ATEListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
|
||||||
|
} else if (preference is ATEDialogPreference) {
|
||||||
|
return ATEPreferenceDialogFragment.newInstance(preference.getKey())
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import androidx.preference.SeekBarPreference
|
||||||
|
|
||||||
|
class ATESeekBarPreference(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : SeekBarPreference(context, attrs, defStyleAttr, defStyleRes)
|
|
@ -0,0 +1,37 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.preference.CheckBoxPreference
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATESwitchPreference : CheckBoxPreference {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
layoutResource = R.layout.ate_preference_custom_support
|
||||||
|
widgetLayoutResource = R.layout.ate_preference_switch_support
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEEditTextPreference
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
class ATEEditTextPreferenceDialogFragmentCompat : ATEPreferenceDialogFragment(), MaterialDialog.InputCallback {
|
||||||
|
|
||||||
|
private var input: CharSequence? = null
|
||||||
|
|
||||||
|
private val editTextPreference: ATEEditTextPreference
|
||||||
|
get() = preference as ATEEditTextPreference
|
||||||
|
|
||||||
|
override fun onPrepareDialogBuilder(builder: MaterialDialog.Builder) {
|
||||||
|
super.onPrepareDialogBuilder(builder)
|
||||||
|
builder.input("", editTextPreference.text, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun needInputMethod(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDialogClosed(positiveResult: Boolean) {
|
||||||
|
if (positiveResult) {
|
||||||
|
val value = input!!.toString()
|
||||||
|
if (this.editTextPreference.callChangeListener(value)) {
|
||||||
|
this.editTextPreference.text = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInput(dialog: MaterialDialog, input: CharSequence) {
|
||||||
|
this.input = input
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance(key: String): ATEEditTextPreferenceDialogFragmentCompat {
|
||||||
|
val fragment = ATEEditTextPreferenceDialogFragmentCompat()
|
||||||
|
val b = Bundle(1)
|
||||||
|
b.putString(ATEPreferenceDialogFragment.ARG_KEY, key)
|
||||||
|
fragment.arguments = b
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.DialogAction
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEListPreference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
class ATEListPreferenceDialogFragmentCompat : ATEPreferenceDialogFragment(), MaterialDialog.ListCallbackSingleChoice {
|
||||||
|
private var mClickedDialogEntryIndex: Int = 0
|
||||||
|
|
||||||
|
private val listPreference: ATEListPreference
|
||||||
|
get() = preference as ATEListPreference
|
||||||
|
|
||||||
|
override fun onPrepareDialogBuilder(builder: MaterialDialog.Builder) {
|
||||||
|
super.onPrepareDialogBuilder(builder)
|
||||||
|
|
||||||
|
val preference = listPreference
|
||||||
|
|
||||||
|
if (preference.entries == null || preference.entryValues == null) {
|
||||||
|
throw IllegalStateException(
|
||||||
|
"ListPreference requires an entries array and an entryValues array.")
|
||||||
|
}
|
||||||
|
|
||||||
|
mClickedDialogEntryIndex = preference.findIndexOfValue(preference.value)
|
||||||
|
builder.items(*preference.entries)
|
||||||
|
.alwaysCallSingleChoiceCallback()
|
||||||
|
.itemsCallbackSingleChoice(mClickedDialogEntryIndex, this)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The typical interaction for list-based dialogs is to have
|
||||||
|
* click-on-an-item dismiss the dialog instead of the user having to
|
||||||
|
* press 'Ok'.
|
||||||
|
*/
|
||||||
|
builder.positiveText("")
|
||||||
|
builder.negativeText("")
|
||||||
|
builder.neutralText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDialogClosed(positiveResult: Boolean) {
|
||||||
|
val preference = listPreference
|
||||||
|
if (positiveResult && mClickedDialogEntryIndex >= 0 &&
|
||||||
|
preference.entryValues != null) {
|
||||||
|
val value = preference.entryValues[mClickedDialogEntryIndex].toString()
|
||||||
|
if (preference.callChangeListener(value)) {
|
||||||
|
preference.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSelection(dialog: MaterialDialog, itemView: View, which: Int, text: CharSequence): Boolean {
|
||||||
|
mClickedDialogEntryIndex = which
|
||||||
|
onClick(dialog, DialogAction.POSITIVE)
|
||||||
|
dismiss()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance(key: String): ATEListPreferenceDialogFragmentCompat {
|
||||||
|
val fragment = ATEListPreferenceDialogFragmentCompat()
|
||||||
|
val b = Bundle(1)
|
||||||
|
b.putString(ATEPreferenceDialogFragment.ARG_KEY, key)
|
||||||
|
fragment.arguments = b
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.prefs.supportv7.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.preference.DialogPreference
|
||||||
|
import com.afollestad.materialdialogs.DialogAction
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
open class ATEPreferenceDialogFragment : DialogFragment(), MaterialDialog.SingleButtonCallback {
|
||||||
|
private var mWhichButtonClicked: DialogAction? = null
|
||||||
|
var preference: DialogPreference? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val rawFragment = this.targetFragment
|
||||||
|
if (rawFragment !is DialogPreference.TargetFragment) {
|
||||||
|
throw IllegalStateException("Target fragment must implement TargetFragment interface")
|
||||||
|
} else {
|
||||||
|
val fragment = rawFragment as DialogPreference.TargetFragment?
|
||||||
|
val key = this.arguments!!.getString(ARG_KEY)
|
||||||
|
this.preference = fragment!!.findPreference(key) as DialogPreference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val context = this.activity
|
||||||
|
val builder = MaterialDialog.Builder(context!!)
|
||||||
|
.title(this.preference!!.dialogTitle)
|
||||||
|
.icon(this.preference!!.dialogIcon)
|
||||||
|
.onAny(this)
|
||||||
|
.positiveText(this.preference!!.positiveButtonText)
|
||||||
|
.negativeText(this.preference!!.negativeButtonText)
|
||||||
|
|
||||||
|
builder.content(this.preference!!.dialogMessage)
|
||||||
|
this.onPrepareDialogBuilder(builder)
|
||||||
|
val dialog = builder.build()
|
||||||
|
if (this.needInputMethod()) {
|
||||||
|
this.requestInputMethod(dialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onPrepareDialogBuilder(builder: MaterialDialog.Builder) {}
|
||||||
|
|
||||||
|
protected open fun needInputMethod(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestInputMethod(dialog: Dialog) {
|
||||||
|
val window = dialog.window
|
||||||
|
window!!.setSoftInputMode(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(dialog: MaterialDialog, which: DialogAction) {
|
||||||
|
mWhichButtonClicked = which
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface?) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
onDialogClosed(mWhichButtonClicked == DialogAction.POSITIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onDialogClosed(positiveResult: Boolean) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ARG_KEY = "key"
|
||||||
|
|
||||||
|
fun newInstance(key: String): ATEPreferenceDialogFragment {
|
||||||
|
val fragment = ATEPreferenceDialogFragment()
|
||||||
|
val b = Bundle(1)
|
||||||
|
b.putString(ARG_KEY, key)
|
||||||
|
fragment.arguments = b
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.widget.AppCompatCheckBox
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATECheckBox : AppCompatCheckBox {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEEditText : AppCompatEditText {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
setTextColor(ThemeStore.textColorPrimary(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
|
|
||||||
|
import android.text.Layout
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEPrimaryTextView : AppCompatTextView {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
setTextColor(ThemeStore.textColorPrimary(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEProgressBar : ProgressBar {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.RadioButton
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATERadioButton : RadioButton {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATESecondaryTextView : AppCompatTextView {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
setTextColor(ThemeStore.textColorSecondary(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.SeekBar
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATESeekBar : SeekBar {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Switch
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATEStockSwitch : Switch {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isShown(): Boolean {
|
||||||
|
return parent != null && visibility == View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package code.name.monkey.appthemehelper.common.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.widget.SwitchCompat
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ATH
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class ATESwitch : SwitchCompat {
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
ATH.setTint(this, ThemeStore.accentColor(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isShown(): Boolean {
|
||||||
|
return parent != null && visibility == View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
43
appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ATHUtil.kt
Executable file
43
appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/ATHUtil.kt
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.TypedArray
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isInClassPath(clsName: String): Boolean {
|
||||||
|
try {
|
||||||
|
return inClassPath(clsName) != null
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun inClassPath(clsName: String): Class<*> {
|
||||||
|
try {
|
||||||
|
return Class.forName(clsName)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
throw IllegalStateException(String.format("%s is not in your class path! You must include the associated library.", clsName))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
|
|
||||||
|
|
||||||
|
object ColorUtil {
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.graphics.drawable.TransitionDrawable
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,342 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import androidx.core.widget.EdgeEffectCompat
|
||||||
|
import androidx.core.widget.NestedScrollView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import android.widget.AbsListView
|
||||||
|
import android.widget.EdgeEffect
|
||||||
|
import android.widget.ScrollView
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.BuildConfig
|
||||||
|
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
class EdgeGlowUtil protected constructor() {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
// Invalidation methods
|
||||||
|
|
||||||
|
private var EDGE_GLOW_FIELD_EDGE: Field? = null
|
||||||
|
private var EDGE_GLOW_FIELD_GLOW: Field? = null
|
||||||
|
private var EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateEdgeEffectFields() {
|
||||||
|
if (EDGE_GLOW_FIELD_EDGE != null && EDGE_GLOW_FIELD_GLOW != null &&
|
||||||
|
EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT != null) {
|
||||||
|
EDGE_GLOW_FIELD_EDGE!!.isAccessible = true
|
||||||
|
EDGE_GLOW_FIELD_GLOW!!.isAccessible = true
|
||||||
|
EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
var edge: Field? = null
|
||||||
|
var glow: Field? = null
|
||||||
|
var cls: Class<*>? = null
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||||
|
try {
|
||||||
|
cls = Class.forName("android.widget.EdgeGlow")
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
if (BuildConfig.DEBUG) e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cls = EdgeEffect::class.java
|
||||||
|
}
|
||||||
|
if (cls != null) {
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mEdge" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
edge = f
|
||||||
|
}
|
||||||
|
"mGlow" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
glow = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EDGE_GLOW_FIELD_EDGE = edge
|
||||||
|
EDGE_GLOW_FIELD_GLOW = glow
|
||||||
|
} else {
|
||||||
|
EDGE_GLOW_FIELD_EDGE = null
|
||||||
|
EDGE_GLOW_FIELD_GLOW = null
|
||||||
|
}
|
||||||
|
|
||||||
|
var efc: Field? = null
|
||||||
|
try {
|
||||||
|
efc = EdgeEffectCompat::class.java.getDeclaredField("mEdgeEffect")
|
||||||
|
} catch (e: NoSuchFieldException) {
|
||||||
|
if (BuildConfig.DEBUG) e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT = efc
|
||||||
|
}
|
||||||
|
|
||||||
|
private var SCROLL_VIEW_FIELD_EDGE_GLOW_TOP: Field? = null
|
||||||
|
private var SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateScrollViewFields() {
|
||||||
|
if (SCROLL_VIEW_FIELD_EDGE_GLOW_TOP != null && SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM != null) {
|
||||||
|
SCROLL_VIEW_FIELD_EDGE_GLOW_TOP!!.isAccessible = true
|
||||||
|
SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cls = ScrollView::class.java
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mEdgeGlowTop" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = f
|
||||||
|
}
|
||||||
|
"mEdgeGlowBottom" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP: Field? = null
|
||||||
|
private var NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateNestedScrollViewFields() {
|
||||||
|
if (NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP != null && NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM != null) {
|
||||||
|
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP!!.isAccessible = true
|
||||||
|
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cls = ATHUtil.inClassPath("android.support.v4.widget.NestedScrollView")
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mEdgeGlowTop" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = f
|
||||||
|
}
|
||||||
|
"mEdgeGlowBottom" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var LIST_VIEW_FIELD_EDGE_GLOW_TOP: Field? = null
|
||||||
|
private var LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateListViewFields() {
|
||||||
|
if (LIST_VIEW_FIELD_EDGE_GLOW_TOP != null && LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM != null) {
|
||||||
|
LIST_VIEW_FIELD_EDGE_GLOW_TOP!!.isAccessible = true
|
||||||
|
LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cls = AbsListView::class.java
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mEdgeGlowTop" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
LIST_VIEW_FIELD_EDGE_GLOW_TOP = f
|
||||||
|
}
|
||||||
|
"mEdgeGlowBottom" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP: Field? = null
|
||||||
|
private var RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT: Field? = null
|
||||||
|
private var RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT: Field? = null
|
||||||
|
private var RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateRecyclerViewFields() {
|
||||||
|
if (RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP != null && RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT != null &&
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT != null && RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM != null) {
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP!!.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT!!.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT!!.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cls = ATHUtil.inClassPath("android.support.v7.widget.RecyclerView")
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mTopGlow" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP = f
|
||||||
|
}
|
||||||
|
"mBottomGlow" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM = f
|
||||||
|
}
|
||||||
|
"mLeftGlow" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT = f
|
||||||
|
}
|
||||||
|
"mRightGlow" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var VIEW_PAGER_FIELD_EDGE_GLOW_LEFT: Field? = null
|
||||||
|
private var VIEW_PAGER_FIELD_EDGE_GLOW_RIGHT: Field? = null
|
||||||
|
|
||||||
|
private fun invalidateViewPagerFields() {
|
||||||
|
if (VIEW_PAGER_FIELD_EDGE_GLOW_LEFT != null && VIEW_PAGER_FIELD_EDGE_GLOW_RIGHT != null) {
|
||||||
|
VIEW_PAGER_FIELD_EDGE_GLOW_LEFT!!.isAccessible = true
|
||||||
|
VIEW_PAGER_FIELD_EDGE_GLOW_RIGHT!!.isAccessible = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cls = ATHUtil.inClassPath("android.support.v4.view.ViewPager")
|
||||||
|
for (f in cls.declaredFields) {
|
||||||
|
when (f.name) {
|
||||||
|
"mLeftEdge" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
VIEW_PAGER_FIELD_EDGE_GLOW_LEFT = f
|
||||||
|
}
|
||||||
|
"mRightEdge" -> {
|
||||||
|
f.isAccessible = true
|
||||||
|
VIEW_PAGER_FIELD_EDGE_GLOW_RIGHT = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter methods
|
||||||
|
|
||||||
|
fun setEdgeGlowColor(scrollView: ScrollView, @ColorInt color: Int) {
|
||||||
|
invalidateScrollViewFields()
|
||||||
|
try {
|
||||||
|
var ee: Any
|
||||||
|
ee = SCROLL_VIEW_FIELD_EDGE_GLOW_TOP!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEdgeGlowColor(scrollView: NestedScrollView, @ColorInt color: Int) {
|
||||||
|
invalidateNestedScrollViewFields()
|
||||||
|
try {
|
||||||
|
var ee: Any
|
||||||
|
ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEdgeGlowColor(listView: AbsListView, @ColorInt color: Int) {
|
||||||
|
invalidateListViewFields()
|
||||||
|
try {
|
||||||
|
var ee: Any
|
||||||
|
ee = LIST_VIEW_FIELD_EDGE_GLOW_TOP!!.get(listView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.get(listView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEdgeGlowColor(scrollView: RecyclerView, @ColorInt color: Int, scrollListener: RecyclerView.OnScrollListener?) {
|
||||||
|
var scrollListener = scrollListener
|
||||||
|
invalidateRecyclerViewFields()
|
||||||
|
invalidateRecyclerViewFields()
|
||||||
|
if (scrollListener == null) {
|
||||||
|
scrollListener = object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
EdgeGlowUtil.setEdgeGlowColor(recyclerView, color, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scrollView.addOnScrollListener(scrollListener)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var ee: Any
|
||||||
|
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT!!.get(scrollView)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEdgeGlowColor(pager: ViewPager, @ColorInt color: Int) {
|
||||||
|
invalidateViewPagerFields()
|
||||||
|
try {
|
||||||
|
var ee: Any
|
||||||
|
ee = VIEW_PAGER_FIELD_EDGE_GLOW_LEFT!!.get(pager)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
ee = VIEW_PAGER_FIELD_EDGE_GLOW_RIGHT!!.get(pager)
|
||||||
|
setEffectColor(ee, color)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private fun setEffectColor(edgeEffect: Any?, @ColorInt color: Int) {
|
||||||
|
var edgeEffect = edgeEffect
|
||||||
|
invalidateEdgeEffectFields()
|
||||||
|
if (edgeEffect is EdgeEffectCompat) {
|
||||||
|
// EdgeEffectCompat
|
||||||
|
try {
|
||||||
|
EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT!!.isAccessible = true
|
||||||
|
edgeEffect = EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT!!.get(edgeEffect)
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (edgeEffect == null)
|
||||||
|
return
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// EdgeGlow
|
||||||
|
try {
|
||||||
|
EDGE_GLOW_FIELD_EDGE!!.isAccessible = true
|
||||||
|
val mEdge = EDGE_GLOW_FIELD_EDGE!!.get(edgeEffect) as Drawable
|
||||||
|
EDGE_GLOW_FIELD_GLOW!!.isAccessible = true
|
||||||
|
val mGlow = EDGE_GLOW_FIELD_GLOW!!.get(edgeEffect) as Drawable
|
||||||
|
mEdge.setColorFilter(color, PorterDuff.Mode.SRC_IN)
|
||||||
|
mGlow.setColorFilter(color, PorterDuff.Mode.SRC_IN)
|
||||||
|
mEdge.callback = null // free up any references
|
||||||
|
mGlow.callback = null // free up any references
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// EdgeEffect
|
||||||
|
(edgeEffect as EdgeEffect).color = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.internal.ThemeSingleton
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
|
||||||
|
object MaterialDialogsUtil {
|
||||||
|
|
||||||
|
fun updateMaterialDialogsThemeSingleton(context: Context) {
|
||||||
|
val md = ThemeSingleton.get()
|
||||||
|
md.titleColor = ThemeStore.textColorPrimary(context)
|
||||||
|
md.contentColor = ThemeStore.textColorSecondary(context)
|
||||||
|
md.itemColor = md.titleColor
|
||||||
|
md.widgetColor = ThemeStore.accentColor(context)
|
||||||
|
md.linkColor = ColorStateList.valueOf(md.widgetColor)
|
||||||
|
md.positiveColor = ColorStateList.valueOf(md.widgetColor)
|
||||||
|
md.neutralColor = ColorStateList.valueOf(md.widgetColor)
|
||||||
|
md.negativeColor = ColorStateList.valueOf(md.widgetColor)
|
||||||
|
md.darkTheme = ATHUtil.isWindowBackgroundDark(context)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
|
||||||
|
object MaterialUtil {
|
||||||
|
|
||||||
|
fun setTint(button: MaterialButton) {
|
||||||
|
setTint(button, ThemeStore.accentColor(button.context))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTint(button: MaterialButton, accentColor: Int) {
|
||||||
|
val context = button.context
|
||||||
|
val textColor = ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(accentColor)))
|
||||||
|
button.setTextColor(textColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun setTint(button: MaterialButton, background: Boolean, color: Int = ThemeStore.accentColor(button.context)) {
|
||||||
|
//button.setPadding(48, 48, 48, 48);
|
||||||
|
button.isAllCaps = false
|
||||||
|
val context = button.context
|
||||||
|
val colorState = ColorStateList.valueOf(color)
|
||||||
|
val textColor = ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color)))
|
||||||
|
|
||||||
|
|
||||||
|
if (background) {
|
||||||
|
button.backgroundTintList = colorState
|
||||||
|
button.setTextColor(textColor)
|
||||||
|
button.iconTint = textColor
|
||||||
|
} else {
|
||||||
|
button.strokeColor = colorState
|
||||||
|
button.setTextColor(colorState)
|
||||||
|
button.iconTint = colorState
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTint(textInputLayout: TextInputLayout, background: Boolean) {
|
||||||
|
val context = textInputLayout.context
|
||||||
|
val accentColor = ThemeStore.accentColor(context)
|
||||||
|
val colorState = ColorStateList.valueOf(accentColor)
|
||||||
|
|
||||||
|
if (background) {
|
||||||
|
textInputLayout.backgroundTintList = colorState
|
||||||
|
textInputLayout.defaultHintTextColor = colorState
|
||||||
|
} else {
|
||||||
|
textInputLayout.boxStrokeColor = accentColor
|
||||||
|
textInputLayout.defaultHintTextColor = colorState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
import code.name.monkey.appthemehelper.R
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
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
|
||||||
|
val drawable = navigationView.itemBackground
|
||||||
|
navigationView.itemBackground = TintHelper.createTintedDrawable(drawable, ColorUtil.withAlpha(ThemeStore.accentColor(navigationView.context), 0.2f))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItemIconColors(bottomNavigationView: BottomNavigationView, @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))
|
||||||
|
bottomNavigationView.itemIconTintList = iconSl
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItemTextColors(bottomNavigationView: BottomNavigationView, @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))
|
||||||
|
bottomNavigationView.itemTextColor = textSl
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
|
||||||
|
|
||||||
|
object TabLayoutUtil {
|
||||||
|
|
||||||
|
fun setTabIconColors(tabLayout: TabLayout?, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
|
||||||
|
if (tabLayout == null)
|
||||||
|
return
|
||||||
|
|
||||||
|
val sl = ColorStateList(arrayOf(intArrayOf(-android.R.attr.state_selected), intArrayOf(android.R.attr.state_selected)),
|
||||||
|
intArrayOf(normalColor, selectedColor))
|
||||||
|
for (i in 0 until tabLayout.tabCount) {
|
||||||
|
val tab = tabLayout.getTabAt(i)
|
||||||
|
if (tab != null && tab.icon != null) {
|
||||||
|
tab.icon = TintHelper.createTintedDrawable(tab.icon, sl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
object TextInputLayoutUtil {
|
||||||
|
|
||||||
|
fun setHint(view: TextInputLayout, @ColorInt hintColor: Int) {
|
||||||
|
try {
|
||||||
|
val mDefaultTextColorField = TextInputLayout::class.java.getDeclaredField("mDefaultTextColor")
|
||||||
|
mDefaultTextColorField.isAccessible = true
|
||||||
|
mDefaultTextColorField.set(view, ColorStateList.valueOf(hintColor))
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
throw RuntimeException("Failed to set TextInputLayout hint (collapsed) color: " + t.localizedMessage, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAccent(view: TextInputLayout, @ColorInt accentColor: Int) {
|
||||||
|
try {
|
||||||
|
val mFocusedTextColorField = TextInputLayout::class.java.getDeclaredField("mFocusedTextColor")
|
||||||
|
mFocusedTextColorField.isAccessible = true
|
||||||
|
mFocusedTextColorField.set(view, ColorStateList.valueOf(accentColor))
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
throw RuntimeException("Failed to set TextInputLayout accent (expanded) color: " + t.localizedMessage, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import androidx.collection.SimpleArrayMap
|
||||||
|
|
||||||
|
/*
|
||||||
|
Each call to Typeface.createFromAsset will load a new instance of the typeface into memory,
|
||||||
|
and this memory is not consistently get garbage collected
|
||||||
|
http://code.google.com/p/android/issues/detail?id=9904
|
||||||
|
(It states released but even on Lollipop you can see the typefaces accumulate even after
|
||||||
|
multiple GC passes)
|
||||||
|
|
||||||
|
You can detect this by running:
|
||||||
|
adb shell dumpsys meminfo com.your.packagenage
|
||||||
|
|
||||||
|
You will see output like:
|
||||||
|
|
||||||
|
Asset Allocations
|
||||||
|
zip:/data/app/com.your.packagenage-1.apk:/assets/Roboto-Medium.ttf: 125K
|
||||||
|
zip:/data/app/com.your.packagenage-1.apk:/assets/Roboto-Medium.ttf: 125K
|
||||||
|
zip:/data/app/com.your.packagenage-1.apk:/assets/Roboto-Medium.ttf: 125K
|
||||||
|
zip:/data/app/com.your.packagenage-1.apk:/assets/Roboto-Regular.ttf: 123K
|
||||||
|
zip:/data/app/com.your.packagenage-1.apk:/assets/Roboto-Medium.ttf: 125K
|
||||||
|
|
||||||
|
*/
|
||||||
|
object TypefaceHelper {
|
||||||
|
|
||||||
|
private val cache = SimpleArrayMap<String, Typeface>()
|
||||||
|
|
||||||
|
operator fun get(c: Context, name: String): Typeface? {
|
||||||
|
synchronized(cache) {
|
||||||
|
if (!cache.containsKey(name)) {
|
||||||
|
try {
|
||||||
|
val t = Typeface.createFromAsset(c.assets, name)
|
||||||
|
cache.put(name, t)
|
||||||
|
return t
|
||||||
|
} catch (e: RuntimeException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return cache.get(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hemanth S (h4h13).
|
||||||
|
*/
|
||||||
|
|
||||||
|
object VersionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 19
|
||||||
|
*/
|
||||||
|
fun hasKitKat(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 20
|
||||||
|
*/
|
||||||
|
fun hasAndroidLPreview(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= 20
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 21
|
||||||
|
*/
|
||||||
|
fun hasLollipop(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= 21
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 23
|
||||||
|
*/
|
||||||
|
fun hasMarshmallow(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= 23
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 24
|
||||||
|
*/
|
||||||
|
fun hasNougat(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 24
|
||||||
|
*/
|
||||||
|
fun hasNougatMR(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if device is running API >= 26
|
||||||
|
*/
|
||||||
|
fun hasOreo(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package code.name.monkey.appthemehelper.util
|
||||||
|
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.graphics.drawable.TransitionDrawable
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewTreeObserver
|
||||||
|
|
||||||
|
|
||||||
|
object ViewUtil {
|
||||||
|
|
||||||
|
fun removeOnGlobalLayoutListener(v: View, listener: ViewTreeObserver.OnGlobalLayoutListener) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
v.viewTreeObserver.removeGlobalOnLayoutListener(listener)
|
||||||
|
} else {
|
||||||
|
v.viewTreeObserver.removeOnGlobalLayoutListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBackgroundCompat(view: View, drawable: Drawable?) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
view.background = drawable
|
||||||
|
else
|
||||||
|
view.setBackgroundDrawable(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 a new issue