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