diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 75d8172..d41ed8a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
+ android:value="Tencent 社交毒瘤一键省电模块。\n目前支持 QQ、TIM、微信\n开发者:酷安 @星夜不荟" />
(R.id.main_text_qq_noinstall).isGone = QQ_PACKAGE_NAME.isInstall
+ findViewById(R.id.main_text_tim_noinstall).isGone = TIM_PACKAGE_NAME.isInstall
+ findViewById(R.id.main_text_wechat_noinstall).isGone = WECHAT_PACKAGE_NAME.isInstall
/** 设置文本 */
findViewById(R.id.main_text_version).text = "当前版本:$moduleVersion"
findViewById(R.id.main_text_support_qq).apply {
@@ -154,12 +163,28 @@ class MainActivity : AppCompatActivity() {
if (!btn.isPressed) return@setOnCheckedChangeListener
putBoolean(HookMedium.ENABLE_RUN_INFO, b)
}
+ /** 恰饭! */
+ findViewById(R.id.link_with_follow_me).setOnClickListener {
+ try {
+ startActivity(Intent().apply {
+ setPackage("com.coolapk.market")
+ action = "android.intent.action.VIEW"
+ data = Uri.parse("https://www.coolapk.com/u/876977")
+ /** 防止顶栈一样重叠在自己的 APP 中 */
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ })
+ } catch (e: Exception) {
+ Toast.makeText(this, "你可能没有安装酷安", Toast.LENGTH_SHORT).show()
+ }
+ }
/** 项目地址点击事件 */
findViewById(R.id.link_with_project_address).setOnClickListener {
try {
startActivity(Intent().apply {
action = "android.intent.action.VIEW"
data = Uri.parse("https://github.com/fankes/TSBattery")
+ /** 防止顶栈一样重叠在自己的 APP 中 */
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
} catch (e: Exception) {
Toast.makeText(this, "无法启动系统默认浏览器", Toast.LENGTH_SHORT).show()
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/DialogBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/DialogBuilder.kt
index be33d94..f59b68d 100644
--- a/app/src/main/java/com/fankes/tsbattery/utils/DialogBuilder.kt
+++ b/app/src/main/java/com/fankes/tsbattery/utils/DialogBuilder.kt
@@ -24,6 +24,9 @@ package com.fankes.tsbattery.utils
import android.app.AlertDialog
import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+
/**
* 构造对话框
@@ -85,5 +88,14 @@ class DialogBuilder(private val context: Context) {
instance?.setNeutralButton(content) { _, _ -> it() }
/** 显示对话框 */
- internal fun show() = instance?.create()?.show()
+ internal fun show() = instance?.create()?.apply {
+ window?.setBackgroundDrawable(GradientDrawable(
+ GradientDrawable.Orientation.TOP_BOTTOM,
+ intArrayOf(Color.WHITE, Color.WHITE)
+ ).apply {
+ shape = GradientDrawable.RECTANGLE
+ gradientType = GradientDrawable.LINEAR_GRADIENT
+ cornerRadius = 15.dp(this@DialogBuilder.context)
+ })
+ }?.show()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/Utils.kt b/app/src/main/java/com/fankes/tsbattery/utils/Utils.kt
index 0e0978a..1b0ed4e 100644
--- a/app/src/main/java/com/fankes/tsbattery/utils/Utils.kt
+++ b/app/src/main/java/com/fankes/tsbattery/utils/Utils.kt
@@ -24,13 +24,37 @@ package com.fankes.tsbattery.utils
import android.content.Context
import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import com.fankes.tsbattery.application.TSApplication.Companion.appContext
/** 得到安装包信息 */
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo()
+/** 判断应用是否安装 */
+val String.isInstall
+ get() =
+ try {
+ appContext.packageManager.getPackageInfo(
+ this,
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ )
+ true
+ } catch (e: Exception) {
+ false
+ }
+
/** 得到版本信息 */
val Context.versionName get() = packageInfo.versionName ?: ""
/** 得到版本号 */
val Context.versionCode get() = packageInfo.versionCode
+/** dp 转换为 px */
+val Number.dp get() = (toFloat() * appContext.resources.displayMetrics.density).toInt()
+
+/**
+ * dp 转换为 px
+ * @param context 使用的实例
+ */
+fun Number.dp(context: Context) = toFloat() * context.resources.displayMetrics.density
+
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Compatible.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Compatible.kt
new file mode 100755
index 0000000..0a05393
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Compatible.kt
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+@file:Suppress("SameParameterValue")
+
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.annotation.SuppressLint
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.RippleDrawable
+import android.graphics.drawable.RotateDrawable
+import android.os.Build
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+
+private val gradientState = resolveGradientState()
+
+private fun resolveGradientState(): Class<*> {
+ val classes = GradientDrawable::class.java.declaredClasses
+ for (singleClass in classes) {
+ if (singleClass.simpleName == "GradientState") return singleClass
+ }
+ throw RuntimeException("GradientState could not be found in thisAny GradientDrawable implementation")
+}
+
+private val rotateState = resolveRotateState()
+
+private fun resolveRotateState(): Class<*> {
+ val classes = RotateDrawable::class.java.declaredClasses
+ for (singleClass in classes) {
+ if (singleClass.simpleName == "RotateState") return singleClass
+ }
+ throw RuntimeException("RotateState could not be found in thisAny RotateDrawable implementation")
+}
+
+@Throws(SecurityException::class, NoSuchFieldException::class)
+private fun resolveField(source: Class<*>, fieldName: String): Field {
+ val field = source.getDeclaredField(fieldName)
+ field.isAccessible = true
+ return field
+}
+
+@Throws(SecurityException::class, NoSuchMethodException::class)
+private fun resolveMethod(
+ source: Class<*>,
+ methodName: String,
+ vararg parameterTypes: Class<*>
+): Method {
+ val method = source.getDeclaredMethod(methodName, *parameterTypes)
+ method.isAccessible = true
+ return method
+}
+
+fun setInnerRadius(drawable: GradientDrawable, value: Int) {
+ try {
+ val innerRadius = resolveField(gradientState, "mInnerRadius")
+ innerRadius.setInt(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setInnerRadiusRatio(drawable: GradientDrawable, value: Float) {
+ try {
+ val innerRadius = resolveField(gradientState, "mInnerRadiusRatio")
+ innerRadius.setFloat(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setThickness(drawable: GradientDrawable, value: Int) {
+ try {
+ val innerRadius = resolveField(gradientState, "mThickness")
+ innerRadius.setInt(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setThicknessRatio(drawable: GradientDrawable, value: Float) {
+ try {
+ val innerRadius = resolveField(gradientState, "mThicknessRatio")
+ innerRadius.setFloat(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setUseLevelForShape(drawable: GradientDrawable, value: Boolean) {
+ try {
+ val useLevelForShape = resolveField(gradientState, "mUseLevelForShape")
+ useLevelForShape.setBoolean(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+@SuppressLint("ObsoleteSdkInt")
+fun setOrientation(drawable: GradientDrawable, value: GradientDrawable.Orientation) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ drawable.orientation = value
+ } else {
+ try {
+ val orientation = resolveField(gradientState, "mOrientation")
+ orientation.set(drawable.constantState, value)
+ val rectIdDirty = resolveField(GradientDrawable::class.java, "mRectIsDirty")
+ rectIdDirty.setBoolean(drawable, true)
+ drawable.invalidateSelf()
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+@SuppressLint("ObsoleteSdkInt")
+fun setColors(drawable: GradientDrawable, value: IntArray) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ drawable.colors = value
+ } else {
+ try {
+ val colors = resolveField(gradientState, "mColors")
+ colors.set(drawable.constantState, value)
+ drawable.invalidateSelf()
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setGradientRadiusType(drawable: GradientDrawable, value: Int) {
+ try {
+ val type = resolveField(gradientState, "mGradientRadiusType")
+ type.setInt(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setGradientRadius(drawable: GradientDrawable, value: Float) {
+ try {
+ val gradientRadius = resolveField(gradientState, "mGradientRadius")
+ gradientRadius.setFloat(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setStrokeColor(drawable: GradientDrawable, value: Int) {
+ try {
+ val type = resolveField(gradientState, "mStrokeColor")
+ type.setInt(drawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+}
+
+fun setDrawable(rotateDrawable: RotateDrawable, drawable: Drawable) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rotateDrawable.drawable = drawable
+ } else {
+ try {
+ val drawableField = resolveField(rotateState, "mDrawable")
+ val stateField = resolveField(RotateDrawable::class.java, "mState")
+ drawableField.set(stateField.get(rotateDrawable), drawable)
+ drawable.callback = rotateDrawable
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setPivotX(rotateDrawable: RotateDrawable, value: Float) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rotateDrawable.pivotX = value
+ } else {
+ try {
+ val pivotXField = resolveField(rotateState, "mPivotX")
+ pivotXField.setFloat(rotateDrawable.constantState, value)
+ val pivotXRelField = resolveField(rotateState, "mPivotXRel")
+ pivotXRelField.setBoolean(rotateDrawable.constantState, true)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setPivotY(rotateDrawable: RotateDrawable, value: Float) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rotateDrawable.pivotY = value
+ } else {
+ try {
+ val pivotYField = resolveField(rotateState, "mPivotY")
+ pivotYField.setFloat(rotateDrawable.constantState, value)
+ val pivotYRelField = resolveField(rotateState, "mPivotYRel")
+ pivotYRelField.setBoolean(rotateDrawable.constantState, true)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setFromDegrees(rotateDrawable: RotateDrawable, value: Float) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rotateDrawable.fromDegrees = value
+ } else {
+ try {
+ val fromDegreesField = resolveField(rotateState, "mFromDegrees")
+ fromDegreesField.setFloat(rotateDrawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setToDegrees(rotateDrawable: RotateDrawable, value: Float) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rotateDrawable.toDegrees = value
+ } else {
+ try {
+ val toDegreesField = resolveField(rotateState, "mToDegrees")
+ toDegreesField.setFloat(rotateDrawable.constantState, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
+
+fun setRadius(rippleDrawable: RippleDrawable, value: Int) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ rippleDrawable.radius = value
+ } else {
+ try {
+ val setRadiusMethod =
+ resolveMethod(RippleDrawable::class.java, "setMaxRadius", Int::class.java)
+ setRadiusMethod.invoke(rippleDrawable, value)
+ } catch (e: NoSuchFieldException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Constants.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Constants.kt
new file mode 100755
index 0000000..861cf9d
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Constants.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+class Constants {
+
+ companion object {
+ const val DEFAULT_COLOR = 0xFFBA68C8.toInt()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableBuilder.kt
new file mode 100755
index 0000000..41c2009
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableBuilder.kt
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+@file:Suppress("unused", "MemberVisibilityCanBePrivate")
+
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.content.res.ColorStateList
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.util.StateSet
+import java.util.*
+import java.util.concurrent.atomic.AtomicInteger
+
+class DrawableBuilder {
+
+ private var properties = DrawableProperties()
+ private var order: AtomicInteger = AtomicInteger(1)
+ private var transformsMap = TreeMap Drawable>()
+ private var baseDrawable: Drawable? = null
+
+ fun batch(properties: DrawableProperties) = apply { this.properties = properties.copy() }
+ fun baseDrawable(drawable: Drawable) = apply { baseDrawable = drawable }
+
+ //
+ fun shape(shape: Int) = apply { properties.shape = shape }
+
+ fun rectangle() = apply { shape(GradientDrawable.RECTANGLE) }
+ fun oval() = apply { shape(GradientDrawable.OVAL) }
+ fun line() = apply { shape(GradientDrawable.LINE) }
+ fun ring() = apply { shape(GradientDrawable.RING) }
+ fun innerRadius(innerRadius: Int) = apply { properties.innerRadius = innerRadius }
+ fun innerRadiusRatio(innerRadiusRatio: Float) =
+ apply { properties.innerRadiusRatio = innerRadiusRatio }
+
+ fun thickness(thickness: Int) = apply { properties.thickness = thickness }
+ fun thicknessRatio(thicknessRatio: Float) = apply { properties.thicknessRatio = thicknessRatio }
+
+ fun useLevelForRing(use: Boolean = true) = apply { properties.useLevelForRing = use }
+
+ //
+ fun cornerRadius(cornerRadius: Int) = apply { properties.cornerRadius = cornerRadius }
+
+ fun topLeftRadius(topLeftRadius: Int) = apply { properties.topLeftRadius = topLeftRadius }
+ fun topRightRadius(topRightRadius: Int) = apply { properties.topRightRadius = topRightRadius }
+ fun bottomRightRadius(bottomRightRadius: Int) =
+ apply { properties.bottomRightRadius = bottomRightRadius }
+
+ fun bottomLeftRadius(bottomLeftRadius: Int) =
+ apply { properties.bottomLeftRadius = bottomLeftRadius }
+
+ fun rounded() = apply { cornerRadius(Int.MAX_VALUE) }
+ fun cornerRadii(
+ topLeftRadius: Int,
+ topRightRadius: Int,
+ bottomRightRadius: Int,
+ bottomLeftRadius: Int
+ ) = apply {
+ topLeftRadius(topLeftRadius); topRightRadius(topRightRadius); bottomRightRadius(
+ bottomRightRadius
+ ); bottomLeftRadius(bottomLeftRadius)
+ }
+
+ //
+
+ fun gradient(useGradient: Boolean = true) = apply { properties.useGradient = useGradient }
+
+ fun gradientType(type: Int) = apply { properties.type = type }
+ fun linearGradient() = apply { gradientType(GradientDrawable.LINEAR_GRADIENT) }
+ fun radialGradient() = apply { gradientType(GradientDrawable.RADIAL_GRADIENT) }
+ fun sweepGradient() = apply { gradientType(GradientDrawable.SWEEP_GRADIENT) }
+ fun angle(angle: Int) = apply { properties.angle = angle }
+ fun centerX(centerX: Float) = apply { properties.centerX = centerX }
+ fun centerY(centerY: Float) = apply { properties.centerY = centerY }
+ fun center(centerX: Float, centerY: Float) = apply { centerX(centerX); centerY(centerY) }
+
+ fun useCenterColor(useCenterColor: Boolean = true) =
+ apply { properties.useCenterColor = useCenterColor }
+
+ fun startColor(startColor: Int) = apply { properties.startColor = startColor }
+ fun centerColor(centerColor: Int) = apply {
+ properties.centerColor = centerColor
+ useCenterColor(true)
+ }
+
+ fun endColor(endColor: Int) = apply { properties.endColor = endColor }
+ fun gradientColors(startColor: Int, endColor: Int, centerColor: Int?) = apply {
+ startColor(startColor); endColor(endColor)
+ useCenterColor(centerColor != null)
+ centerColor?.let {
+ centerColor(it)
+ }
+ }
+
+ fun gradientRadiusType(gradientRadiusType: Int) =
+ apply { properties.gradientRadiusType = gradientRadiusType }
+
+ fun gradientRadius(gradientRadius: Float) = apply { properties.gradientRadius = gradientRadius }
+ fun gradientRadius(radius: Float, type: Int) =
+ apply { gradientRadius(radius); gradientRadiusType(type) }
+
+ fun gradientRadiusInPixel(radius: Float) =
+ apply { gradientRadius(radius); gradientRadiusType(DrawableProperties.RADIUS_TYPE_PIXELS) }
+
+ fun gradientRadiusInFraction(radius: Float) =
+ apply { gradientRadius(radius); gradientRadiusType(DrawableProperties.RADIUS_TYPE_FRACTION) }
+
+ fun useLevelForGradient(use: Boolean) = apply { properties.useLevelForGradient = use }
+ fun useLevelForGradient() = apply { useLevelForGradient(true) }
+
+ //
+ fun width(width: Int) = apply { properties.width = width }
+
+ fun height(height: Int) = apply { properties.height = height }
+ fun size(width: Int, height: Int) = apply { width(width); height(height) }
+ fun size(size: Int) = apply { width(size).height(size) }
+
+ //
+ fun solidColor(solidColor: Int) = apply { properties.solidColor = solidColor }
+
+ private var solidColorPressed: Int? = null
+ fun solidColorPressed(color: Int?) = apply { solidColorPressed = color }
+ private var solidColorPressedWhenRippleUnsupported: Int? = null
+ fun solidColorPressedWhenRippleUnsupported(color: Int?) =
+ apply { solidColorPressedWhenRippleUnsupported = color }
+
+ private var solidColorDisabled: Int? = null
+ fun solidColorDisabled(color: Int?) = apply { solidColorDisabled = color }
+ private var solidColorSelected: Int? = null
+ fun solidColorSelected(color: Int?) = apply { solidColorSelected = color }
+ fun solidColorStateList(colorStateList: ColorStateList) =
+ apply { properties.solidColorStateList = colorStateList }
+
+ //
+ fun strokeWidth(strokeWidth: Int) = apply { properties.strokeWidth = strokeWidth }
+
+ fun strokeColor(strokeColor: Int) = apply { properties.strokeColor = strokeColor }
+ private var strokeColorPressed: Int? = null
+ fun strokeColorPressed(color: Int?) = apply { strokeColorPressed = color }
+ private var strokeColorDisabled: Int? = null
+ fun strokeColorDisabled(color: Int?) = apply { strokeColorDisabled = color }
+ private var strokeColorSelected: Int? = null
+ fun strokeColorSelected(color: Int?) = apply { strokeColorSelected = color }
+ fun strokeColorStateList(colorStateList: ColorStateList) =
+ apply { properties.strokeColorStateList = colorStateList }
+
+ fun dashWidth(dashWidth: Int) = apply { properties.dashWidth = dashWidth }
+ fun dashGap(dashGap: Int) = apply { properties.dashGap = dashGap }
+ fun hairlineBordered() = apply { strokeWidth(1) }
+ fun shortDashed() = apply { dashWidth(12).dashGap(12) }
+ fun mediumDashed() = apply { dashWidth(24).dashGap(24) }
+ fun longDashed() = apply { dashWidth(36).dashGap(36) }
+ fun dashed() = apply { mediumDashed() }
+
+ //
+ private var rotateOrder = 0
+
+
+ fun rotate(boolean: Boolean = true) = apply {
+ properties.useRotate = boolean
+ rotateOrder = if (boolean) {
+ order.getAndIncrement()
+ } else {
+ 0
+ }
+ }
+
+ fun pivotX(pivotX: Float) = apply { properties.pivotX = pivotX }
+ fun pivotY(pivotY: Float) = apply { properties.pivotY = pivotY }
+ fun pivot(pivotX: Float, pivotY: Float) = apply { pivotX(pivotX).pivotY(pivotY) }
+ fun fromDegrees(degrees: Float) = apply { properties.fromDegrees = degrees }
+ fun toDegrees(degrees: Float) = apply { properties.toDegrees = degrees }
+ fun degrees(fromDegrees: Float, toDegrees: Float) =
+ apply { fromDegrees(fromDegrees).toDegrees(toDegrees) }
+
+ fun degrees(degrees: Float) = apply { fromDegrees(degrees).toDegrees(degrees) }
+ fun rotate(fromDegrees: Float, toDegrees: Float) =
+ apply { rotate().fromDegrees(fromDegrees).toDegrees(toDegrees) }
+
+ fun rotate(degrees: Float) = apply { rotate().degrees(degrees) }
+
+ //
+ private var scaleOrder = 0
+
+
+ fun scale(boolean: Boolean = true) = apply {
+ properties.useScale = boolean
+ scaleOrder = if (boolean) {
+ order.getAndIncrement()
+ } else {
+ 0
+ }
+ }
+
+ fun scaleLevel(level: Int) = apply { properties.scaleLevel = level }
+ fun scaleGravity(gravity: Int) = apply { properties.scaleGravity = gravity }
+ fun scaleWidth(scale: Float) = apply { properties.scaleWidth = scale }
+ fun scaleHeight(scale: Float) = apply { properties.scaleHeight = scale }
+ fun scale(scale: Float) = apply { scale().scaleWidth(scale).scaleHeight(scale) }
+ fun scale(scaleWidth: Float, scaleHeight: Float) =
+ apply { scale().scaleWidth(scaleWidth).scaleHeight(scaleHeight) }
+
+ // flip
+
+ fun flip(boolean: Boolean = true) = apply { properties.useFlip = boolean }
+
+ fun orientation(orientation: Int) = apply { properties.orientation = orientation }
+ fun flipVertical() = apply { flip().orientation(FlipDrawable.ORIENTATION_VERTICAL) }
+
+ //
+
+ fun ripple(boolean: Boolean = true) = apply { properties.useRipple = boolean }
+
+ fun rippleColor(color: Int) = apply { properties.rippleColor = color }
+ fun rippleColorStateList(colorStateList: ColorStateList) =
+ apply { properties.rippleColorStateList = colorStateList }
+
+ fun rippleRadius(radius: Int) = apply { properties.rippleRadius = radius }
+
+ fun build(): Drawable {
+ if (baseDrawable != null) {
+ return wrap(baseDrawable!!)
+ }
+
+ var drawable: Drawable
+
+ // fall back when ripple is unavailable on devices with API < 21
+ if (shouldFallbackRipple()) {
+ if (solidColorPressedWhenRippleUnsupported != null) {
+ solidColorPressed(solidColorPressedWhenRippleUnsupported)
+ } else {
+ solidColorPressed(properties.rippleColor)
+ }
+ }
+
+ if (needStateListDrawable()) {
+ drawable = StateListDrawableBuilder()
+ .pressed(buildPressedDrawable())
+ .disabled(buildDisabledDrawable())
+ .selected(buildSelectedDrawable())
+ .normal(buildNormalDrawable())
+ .build()
+ } else {
+ drawable = GradientDrawable()
+ setupGradientDrawable(drawable)
+ }
+ drawable = wrap(drawable)
+ return drawable
+ }
+
+ private fun getSolidColorStateList(): ColorStateList {
+ if (properties.solidColorStateList != null) {
+ return properties.solidColorStateList!!
+ }
+
+ val states = mutableListOf()
+ val colors = mutableListOf()
+
+ solidColorPressed?.let {
+ states.add(intArrayOf(android.R.attr.state_pressed))
+ colors.add(it)
+ }
+ solidColorDisabled?.let {
+ states.add(intArrayOf(-android.R.attr.state_enabled))
+ colors.add(it)
+ }
+ solidColorSelected?.let {
+ states.add(intArrayOf(android.R.attr.state_selected))
+ colors.add(it)
+ }
+ states.add(StateSet.WILD_CARD)
+ colors.add(properties.solidColor)
+
+ return ColorStateList(states.toTypedArray(), colors.toIntArray())
+ }
+
+ private fun getStrokeColorStateList(): ColorStateList {
+ if (properties.strokeColorStateList != null) {
+ return properties.strokeColorStateList!!
+ }
+
+ val states = mutableListOf()
+ val colors = mutableListOf()
+
+ strokeColorPressed?.let {
+ states.add(intArrayOf(android.R.attr.state_pressed))
+ colors.add(it)
+ }
+ strokeColorDisabled?.let {
+ states.add(intArrayOf(-android.R.attr.state_enabled))
+ colors.add(it)
+ }
+ strokeColorSelected?.let {
+ states.add(intArrayOf(android.R.attr.state_selected))
+ colors.add(it)
+ }
+ states.add(StateSet.WILD_CARD)
+ colors.add(properties.strokeColor)
+
+ return ColorStateList(states.toTypedArray(), colors.toIntArray())
+ }
+
+ private fun buildPressedDrawable(): Drawable? {
+ if (solidColorPressed == null && strokeColorPressed == null) return null
+
+ val pressedDrawable = GradientDrawable()
+ setupGradientDrawable(pressedDrawable)
+ solidColorPressed?.let {
+ pressedDrawable.setColor(it)
+ }
+ strokeColorPressed?.let {
+ setStrokeColor(pressedDrawable, it)
+ }
+ return pressedDrawable
+ }
+
+ private fun buildDisabledDrawable(): Drawable? {
+ if (solidColorDisabled == null && strokeColorDisabled == null) return null
+
+ val disabledDrawable = GradientDrawable()
+ setupGradientDrawable(disabledDrawable)
+ solidColorDisabled?.let {
+ disabledDrawable.setColor(it)
+ }
+ strokeColorDisabled?.let {
+ setStrokeColor(disabledDrawable, it)
+ }
+ return disabledDrawable
+ }
+
+ private fun buildSelectedDrawable(): Drawable? {
+ if (solidColorSelected == null && strokeColorSelected == null) return null
+
+ val selectedDrawable = GradientDrawable()
+ setupGradientDrawable(selectedDrawable)
+ solidColorSelected?.let {
+ selectedDrawable.setColor(it)
+ }
+ strokeColorSelected?.let {
+ setStrokeColor(selectedDrawable, it)
+ }
+ return selectedDrawable
+ }
+
+ private fun buildNormalDrawable(): Drawable {
+ val pressedDrawable = GradientDrawable()
+ setupGradientDrawable(pressedDrawable)
+ return pressedDrawable
+ }
+
+ private fun setupGradientDrawable(drawable: GradientDrawable) {
+ properties.apply {
+ drawable.shape = shape
+ if (shape == GradientDrawable.RING) {
+ setInnerRadius(drawable, innerRadius)
+ setInnerRadiusRatio(drawable, innerRadiusRatio)
+ setThickness(drawable, thickness)
+ setThicknessRatio(drawable, thicknessRatio)
+ setUseLevelForShape(drawable, useLevelForRing)
+ }
+ drawable.cornerRadii = getCornerRadii()
+ if (useGradient) {
+ drawable.gradientType = type
+ setGradientRadiusType(drawable, gradientRadiusType)
+ setGradientRadius(drawable, gradientRadius)
+ drawable.setGradientCenter(centerX, centerY)
+ setOrientation(drawable, getOrientation())
+ setColors(drawable, getColors())
+ drawable.useLevel = useLevelForGradient
+ } else {
+ drawable.color = getSolidColorStateList()
+ }
+ drawable.setSize(width, height)
+ drawable.setStroke(
+ strokeWidth,
+ getStrokeColorStateList(),
+ dashWidth.toFloat(),
+ dashGap.toFloat()
+ )
+ }
+ }
+
+ private fun needStateListDrawable(): Boolean {
+ return (hasStrokeColorStateList() || (!properties.useGradient && hasSolidColorStateList()))
+ }
+
+ private fun needRotateDrawable(): Boolean {
+ return properties.useRotate &&
+ !(properties.pivotX == 0.5f && properties.pivotY == 0.5f
+ && properties.fromDegrees == 0f && properties.toDegrees == 0f)
+ }
+
+ private fun needScaleDrawable(): Boolean {
+ return properties.useScale
+ }
+
+ private fun wrap(drawable: Drawable): Drawable {
+ var wrappedDrawable = drawable
+
+ if (rotateOrder > 0) {
+ transformsMap[rotateOrder] = ::wrapRotateIfNeeded
+ }
+ if (scaleOrder > 0) {
+ transformsMap[scaleOrder] = ::wrapScaleIfNeeded
+ }
+
+ for (action in transformsMap.values) {
+ wrappedDrawable = action.invoke(wrappedDrawable)
+ }
+
+ if (properties.useFlip) {
+ wrappedDrawable = FlipDrawableBuilder()
+ .drawable(wrappedDrawable)
+ .orientation(properties.orientation)
+ .build()
+ }
+
+ if (isRippleSupported() && properties.useRipple) {
+ wrappedDrawable = RippleDrawableBuilder()
+ .drawable(wrappedDrawable)
+ .color(properties.rippleColor)
+ .colorStateList(properties.rippleColorStateList)
+ .radius(properties.rippleRadius)
+ .build()
+ }
+
+ return wrappedDrawable
+ }
+
+ private fun shouldFallbackRipple(): Boolean {
+ return properties.useRipple && !isRippleSupported()
+ }
+
+ private fun isRippleSupported() = true
+
+ private fun wrapRotateIfNeeded(drawable: Drawable): Drawable {
+ if (!needRotateDrawable()) return drawable
+
+ with(properties) {
+ return RotateDrawableBuilder()
+ .drawable(drawable)
+ .pivotX(pivotX)
+ .pivotY(pivotY)
+ .fromDegrees(fromDegrees)
+ .toDegrees(toDegrees)
+ .build()
+ }
+ }
+
+ private fun wrapScaleIfNeeded(drawable: Drawable): Drawable {
+ if (!needScaleDrawable()) return drawable
+
+ with(properties) {
+ return ScaleDrawableBuilder()
+ .drawable(drawable)
+ .level(scaleLevel)
+ .scaleGravity(scaleGravity)
+ .scaleWidth(scaleWidth)
+ .scaleHeight(scaleHeight)
+ .build()
+ }
+ }
+
+ private fun hasSolidColorStateList(): Boolean {
+ return solidColorPressed != null || solidColorDisabled != null || solidColorSelected != null
+ }
+
+ private fun hasStrokeColorStateList(): Boolean {
+ return strokeColorPressed != null || strokeColorDisabled != null || strokeColorSelected != null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableProperties.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableProperties.kt
new file mode 100755
index 0000000..a1515fe
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableProperties.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+@file:Suppress("SetterBackingFieldAssignment", "unused")
+
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.os.Parcel
+import android.os.Parcelable
+import android.view.Gravity
+import java.io.Serializable
+
+data class DrawableProperties(
+
+ //
+ @JvmField var shape: Int = GradientDrawable.RECTANGLE,
+ @JvmField var innerRadius: Int = -1,
+ @JvmField var innerRadiusRatio: Float = 9f,
+ @JvmField var thickness: Int = -1,
+ @JvmField var thicknessRatio: Float = 3f,
+ @JvmField var useLevelForRing: Boolean = false,
+
+ //
+ private var _cornerRadius: Int = 0,
+ @JvmField var topLeftRadius: Int = 0,
+ @JvmField var topRightRadius: Int = 0,
+ @JvmField var bottomRightRadius: Int = 0,
+ @JvmField var bottomLeftRadius: Int = 0,
+
+ //
+ @JvmField var useGradient: Boolean = false,
+ @JvmField var type: Int = GradientDrawable.RADIAL_GRADIENT,
+ @JvmField var angle: Int = 0,
+ @JvmField var centerX: Float = 0.5f,
+ @JvmField var centerY: Float = 0.5f,
+ @JvmField var useCenterColor: Boolean = false,
+ @JvmField var startColor: Int = Constants.DEFAULT_COLOR,
+ @JvmField var centerColor: Int? = null,
+ @JvmField var endColor: Int = 0x7FFFFFFF,
+ @JvmField var gradientRadiusType: Int = RADIUS_TYPE_FRACTION,
+ @JvmField var gradientRadius: Float = 0.5f,
+ @JvmField var useLevelForGradient: Boolean = false,
+
+ //
+ @JvmField var width: Int = -1,
+ @JvmField var height: Int = -1,
+
+ //
+ @JvmField var solidColor: Int = Color.TRANSPARENT,
+ @JvmField var solidColorStateList: ColorStateList? = null,
+
+ //
+ @JvmField var strokeWidth: Int = 0,
+ @JvmField var strokeColor: Int = Color.DKGRAY,
+ @JvmField var strokeColorStateList: ColorStateList? = null,
+ @JvmField var dashWidth: Int = 0,
+ @JvmField var dashGap: Int = 0,
+
+ //
+ @JvmField var useRotate: Boolean = false,
+ @JvmField var pivotX: Float = 0.5f,
+ @JvmField var pivotY: Float = 0.5f,
+ @JvmField var fromDegrees: Float = 0f,
+ @JvmField var toDegrees: Float = 0f,
+
+ //
+ @JvmField var useScale: Boolean = false,
+ @JvmField var scaleLevel: Int = 10000,
+ @JvmField var scaleGravity: Int = Gravity.CENTER,
+ @JvmField var scaleWidth: Float = 0f,
+ @JvmField var scaleHeight: Float = 0f,
+
+ // flip
+ @JvmField var useFlip: Boolean = false,
+ @JvmField var orientation: Int = FlipDrawable.ORIENTATION_HORIZONTAL,
+
+ // ripple
+ @JvmField var useRipple: Boolean = false,
+ @JvmField var rippleColor: Int = Constants.DEFAULT_COLOR,
+ @JvmField var rippleColorStateList: ColorStateList? = null,
+ @JvmField var rippleRadius: Int = -1
+) : Serializable {
+
+ companion object {
+ const val RADIUS_TYPE_PIXELS = 0
+ const val RADIUS_TYPE_FRACTION = 1
+
+ @JvmField
+ val CREATOR = object : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel): DrawableProperties {
+ return DrawableProperties(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+ var cornerRadius: Int = _cornerRadius
+ set(value) {
+ _cornerRadius = value
+ topLeftRadius = value
+ topRightRadius = value
+ bottomRightRadius = value
+ bottomLeftRadius = value
+ }
+
+ constructor(parcel: Parcel) : this(
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readValue(Int::class.java.classLoader) as? Int,
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readParcelable(ColorStateList::class.java.classLoader),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readParcelable(ColorStateList::class.java.classLoader),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readByte() != 0.toByte(),
+ parcel.readInt(),
+ parcel.readParcelable(ColorStateList::class.java.classLoader),
+ parcel.readInt()
+ )
+
+ fun copy(): DrawableProperties {
+ val parcel = Parcel.obtain()
+ parcel.setDataPosition(0)
+ val properties = CREATOR.createFromParcel(parcel)
+ parcel.recycle()
+ return properties
+ }
+
+ fun getCornerRadii(): FloatArray {
+ return floatArrayOf(
+ topLeftRadius.toFloat(), topLeftRadius.toFloat(),
+ topRightRadius.toFloat(), topRightRadius.toFloat(),
+ bottomRightRadius.toFloat(), bottomRightRadius.toFloat(),
+ bottomLeftRadius.toFloat(), bottomLeftRadius.toFloat()
+ )
+ }
+
+ fun getOrientation(): GradientDrawable.Orientation {
+ val orientation: GradientDrawable.Orientation = when (val angle = this.angle % 360) {
+ 0 -> GradientDrawable.Orientation.LEFT_RIGHT
+ 45 -> GradientDrawable.Orientation.BL_TR
+ 90 -> GradientDrawable.Orientation.BOTTOM_TOP
+ 135 -> GradientDrawable.Orientation.BR_TL
+ 180 -> GradientDrawable.Orientation.RIGHT_LEFT
+ 225 -> GradientDrawable.Orientation.TR_BL
+ 270 -> GradientDrawable.Orientation.TOP_BOTTOM
+ 315 -> GradientDrawable.Orientation.TL_BR
+ else -> throw IllegalArgumentException("Unsupported angle: $angle")
+ }
+ return orientation
+ }
+
+ fun getColors(): IntArray {
+ return if (useCenterColor && centerColor != null) {
+ intArrayOf(startColor, centerColor!!, endColor)
+ } else intArrayOf(startColor, endColor)
+ }
+
+ fun materialization(): Drawable = DrawableBuilder().batch(this).build()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableWrapperBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableWrapperBuilder.kt
new file mode 100755
index 0000000..c0215b4
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableWrapperBuilder.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.drawable.Drawable
+
+abstract class DrawableWrapperBuilder> {
+
+ protected var drawable: Drawable? = null
+
+ @Suppress("UNCHECKED_CAST")
+ fun drawable(drawable: Drawable): T = apply { this.drawable = drawable } as T
+
+ abstract fun build(): Drawable
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawable.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawable.kt
new file mode 100755
index 0000000..a112441
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawable.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+@file:Suppress("DEPRECATION", "CanvasSize")
+
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+
+class FlipDrawable(
+ private var drawable: Drawable,
+ private var orientation: Int = ORIENTATION_HORIZONTAL
+) : Drawable() {
+
+ companion object {
+ const val ORIENTATION_HORIZONTAL = 0
+ const val ORIENTATION_VERTICAL = 1
+ }
+
+ override fun draw(canvas: Canvas) {
+ val saveCount = canvas.save()
+ if (orientation == ORIENTATION_VERTICAL) {
+ canvas.scale(1f, -1f, (canvas.width / 2).toFloat(), (canvas.height / 2).toFloat())
+ } else {
+ canvas.scale(-1f, 1f, (canvas.width / 2).toFloat(), (canvas.height / 2).toFloat())
+ }
+ drawable.bounds = Rect(0, 0, canvas.width, canvas.height)
+ drawable.draw(canvas)
+ canvas.restoreToCount(saveCount)
+ }
+
+ override fun onLevelChange(level: Int): Boolean {
+ drawable.level = level
+ invalidateSelf()
+ return true
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return drawable.intrinsicWidth
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ return drawable.intrinsicHeight
+ }
+
+ override fun setAlpha(alpha: Int) {
+ drawable.alpha = alpha
+ }
+
+ override fun getOpacity(): Int {
+ return drawable.opacity
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ drawable.colorFilter = colorFilter
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawableBuilder.kt
new file mode 100755
index 0000000..8a264e2
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawableBuilder.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.drawable.Drawable
+
+class FlipDrawableBuilder : DrawableWrapperBuilder() {
+
+ private var orientation: Int = FlipDrawable.ORIENTATION_HORIZONTAL
+
+ fun orientation(orientation: Int) = apply { this.orientation = orientation }
+
+ override fun build(): Drawable {
+ return FlipDrawable(drawable!!, orientation)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/LayerDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/LayerDrawableBuilder.kt
new file mode 100755
index 0000000..519b1ae
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/LayerDrawableBuilder.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.os.Build
+import android.view.Gravity
+import androidx.annotation.RequiresApi
+import java.util.*
+
+class LayerDrawableBuilder {
+
+ companion object {
+ const val DIMEN_UNDEFINED = Int.MIN_VALUE
+ }
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ private var paddingMode = LayerDrawable.PADDING_MODE_NEST
+ private var paddingLeft = 0
+ private var paddingTop = 0
+ private var paddingRight = 0
+ private var paddingBottom = 0
+ private var paddingStart = 0
+ private var paddingEnd = 0
+ private val layers = ArrayList()
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ fun paddingMode(mode: Int) = apply { paddingMode = mode }
+ fun paddingLeft(padding: Int) = apply { paddingLeft = padding }
+ fun paddingTop(padding: Int) = apply { paddingTop = padding }
+ fun paddingRight(padding: Int) = apply { paddingRight = padding }
+ fun paddingBottom(padding: Int) = apply { paddingBottom = padding }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun paddingStart(padding: Int) = apply { paddingStart = padding }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun paddingEnd(padding: Int) = apply { paddingEnd = padding }
+ fun padding(padding: Int) = apply {
+ paddingLeft(padding).paddingTop(padding).paddingRight(padding).paddingBottom(padding)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun paddingRelative(padding: Int) = apply {
+ paddingStart(padding).paddingTop(padding).paddingEnd(padding).paddingBottom(padding)
+ }
+
+ fun add(drawable: Drawable) = apply { layers.add(Layer(drawable)) }
+
+ fun width(width: Int) = apply { layers.last().width = width }
+ fun height(height: Int) = apply { layers.last().height = height }
+
+ fun insetLeft(inset: Int) = apply { layers.last().insetLeft = inset }
+ fun insetTop(inset: Int) = apply { layers.last().insetTop = inset }
+ fun insetRight(inset: Int) = apply { layers.last().insetRight = inset }
+ fun insetBottom(inset: Int) = apply { layers.last().insetBottom = inset }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun insetStart(inset: Int) = apply { layers.last().insetStart = inset }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun insetEnd(inset: Int) = apply { layers.last().insetEnd = inset }
+ fun inset(inset: Int) =
+ apply { insetLeft(inset).insetTop(inset).insetRight(inset).insetBottom(inset) }
+
+ fun inset(insetLeft: Int, insetTop: Int, insetRight: Int, insetBottom: Int) = apply {
+ insetLeft(insetLeft).insetTop(insetTop).insetRight(insetRight).insetBottom(insetBottom)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun insetRelative(inset: Int) =
+ apply { insetStart(inset).insetTop(inset).insetEnd(inset).insetBottom(inset) }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun insetRelative(insetStart: Int, insetTop: Int, insetEnd: Int, insetBottom: Int) = apply {
+ insetStart(insetStart).insetTop(insetTop).insetEnd(insetEnd).insetBottom(insetBottom)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun gravity(gravity: Int) = apply { layers.last().gravity = gravity }
+
+ fun modify(
+ index: Int, drawable: Drawable,
+ width: Int = DIMEN_UNDEFINED,
+ height: Int = DIMEN_UNDEFINED,
+ insetLeft: Int = DIMEN_UNDEFINED,
+ insetTop: Int = DIMEN_UNDEFINED,
+ insetRight: Int = DIMEN_UNDEFINED,
+ insetBottom: Int = DIMEN_UNDEFINED,
+ insetStart: Int = DIMEN_UNDEFINED,
+ insetEnd: Int = DIMEN_UNDEFINED
+ ) =
+ apply {
+ val layer = layers[index]
+ layer.drawable = drawable
+ if (width != DIMEN_UNDEFINED) layer.width = width
+ if (height != DIMEN_UNDEFINED) layer.height = height
+ if (insetLeft != DIMEN_UNDEFINED) layer.insetLeft = insetLeft
+ if (insetTop != DIMEN_UNDEFINED) layer.insetTop = insetTop
+ if (insetRight != DIMEN_UNDEFINED) layer.insetRight = insetRight
+ if (insetBottom != DIMEN_UNDEFINED) layer.insetBottom = insetBottom
+ if (insetStart != DIMEN_UNDEFINED) layer.insetStart = insetStart
+ if (insetEnd != DIMEN_UNDEFINED) layer.insetEnd = insetEnd
+ }
+
+ fun build(): LayerDrawable {
+ val layerDrawable = LayerDrawable(layers.map { it -> it.drawable }.toTypedArray())
+ for (i in 0 until layers.size) {
+ val layer = layers[i]
+ layerDrawable.setLayerInset(
+ i,
+ layer.insetLeft,
+ layer.insetTop,
+ layer.insetRight,
+ layer.insetBottom
+ )
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (layer.insetStart != DIMEN_UNDEFINED || layer.insetEnd != DIMEN_UNDEFINED) {
+ layerDrawable.setLayerInsetRelative(
+ i,
+ layer.insetStart,
+ layer.insetTop,
+ layer.insetEnd,
+ layer.insetBottom
+ )
+ }
+ }
+ layerDrawable.setId(i, i)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ layerDrawable.setLayerGravity(i, layer.gravity)
+ layerDrawable.setLayerInsetStart(i, layer.insetStart)
+ layerDrawable.setLayerInsetEnd(i, layer.insetEnd)
+ }
+ }
+ layerDrawable.paddingMode = paddingMode
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ layerDrawable.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
+ if (paddingStart != DIMEN_UNDEFINED || paddingEnd != DIMEN_UNDEFINED) {
+ layerDrawable.setPaddingRelative(
+ paddingStart,
+ paddingTop,
+ paddingEnd,
+ paddingBottom
+ )
+ }
+ }
+
+ return layerDrawable
+ }
+
+ internal class Layer(var drawable: Drawable) {
+ var gravity: Int = Gravity.NO_GRAVITY
+ var width: Int = -1
+ var height: Int = -1
+ var insetLeft: Int = 0
+ var insetTop: Int = 0
+ var insetRight: Int = 0
+ var insetBottom: Int = 0
+ var insetStart: Int = DIMEN_UNDEFINED
+ var insetEnd: Int = DIMEN_UNDEFINED
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/PathShapeDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/PathShapeDrawableBuilder.kt
new file mode 100755
index 0000000..e798e39
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/PathShapeDrawableBuilder.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.Path
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.PathShape
+
+class PathShapeDrawableBuilder {
+
+ private var path: Path? = null
+ private var pathStandardWidth: Float = 100f
+ private var pathStandardHeight: Float = 100f
+ private var width: Int = -1
+ private var height: Int = -1
+
+ fun path(path: Path, pathStandardWidth: Float, pathStandardHeight: Float) = apply {
+ this.path = path
+ this.pathStandardWidth = pathStandardWidth
+ this.pathStandardHeight = pathStandardHeight
+ }
+
+ fun width(width: Int) = apply { this.width = width }
+ fun height(height: Int) = apply { this.height = height }
+ fun size(size: Int) = apply { width(size).height(size) }
+
+ fun build(custom: ((shapeDrawable: ShapeDrawable) -> Unit)? = null): ShapeDrawable {
+ val shapeDrawable = ShapeDrawable()
+ if (path == null || width <= 0 || height <= 0) {
+ return shapeDrawable
+ }
+ val pathShape = PathShape(path!!, pathStandardWidth, pathStandardHeight)
+
+ shapeDrawable.shape = pathShape
+ shapeDrawable.intrinsicWidth = width
+ shapeDrawable.intrinsicHeight = height
+ if (custom != null) {
+ custom(shapeDrawable)
+ }
+ return shapeDrawable
+ }
+}
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RippleDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RippleDrawableBuilder.kt
new file mode 100755
index 0000000..636fd9c
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RippleDrawableBuilder.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.graphics.drawable.*
+import android.util.StateSet
+
+class RippleDrawableBuilder : DrawableWrapperBuilder() {
+
+ private var color: Int = Constants.DEFAULT_COLOR
+ private var colorStateList: ColorStateList? = null
+ private var radius: Int = -1
+
+ fun color(color: Int) = apply { this.color = color }
+ fun colorStateList(colorStateList: ColorStateList?) =
+ apply { this.colorStateList = colorStateList }
+
+ fun radius(radius: Int) = apply { this.radius = radius }
+
+ override fun build(): Drawable {
+ var drawable = this.drawable!!
+ val colorStateList = this.colorStateList ?: ColorStateList(
+ arrayOf(StateSet.WILD_CARD),
+ intArrayOf(color)
+ )
+
+ var mask = if (drawable is DrawableContainer) drawable.getCurrent() else drawable
+ if (mask is ShapeDrawable) {
+ val state = mask.getConstantState()
+ if (state != null) {
+ val temp = state.newDrawable().mutate() as ShapeDrawable
+ temp.paint.color = Color.BLACK
+ mask = temp
+ }
+ } else if (mask is GradientDrawable) {
+ val state = mask.getConstantState()
+ if (state != null) {
+ val temp = state.newDrawable().mutate() as GradientDrawable
+ temp.setColor(Color.BLACK)
+ mask = temp
+ }
+ } else {
+ mask = ColorDrawable(Color.BLACK)
+ }
+
+ val rippleDrawable = RippleDrawable(colorStateList, drawable, mask)
+ setRadius(rippleDrawable, radius)
+ rippleDrawable.invalidateSelf()
+ drawable = rippleDrawable
+ return drawable
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RotateDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RotateDrawableBuilder.kt
new file mode 100755
index 0000000..3f3b872
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RotateDrawableBuilder.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.RotateDrawable
+
+class RotateDrawableBuilder : DrawableWrapperBuilder() {
+
+ private var pivotX: Float = 0.5f
+ private var pivotY: Float = 0.5f
+ private var fromDegrees: Float = 0f
+ private var toDegrees: Float = 360f
+
+ fun pivotX(x: Float) = apply { pivotX = x }
+ fun pivotY(y: Float) = apply { pivotY = y }
+ fun fromDegrees(degree: Float) = apply { fromDegrees = degree }
+ fun toDegrees(degree: Float) = apply { toDegrees = degree }
+
+ override fun build(): Drawable {
+ val rotateDrawable = RotateDrawable()
+ drawable?.let {
+ setDrawable(rotateDrawable, it)
+ apply {
+ setPivotX(rotateDrawable, pivotX)
+ setPivotY(rotateDrawable, pivotY)
+ setFromDegrees(rotateDrawable, fromDegrees)
+ setToDegrees(rotateDrawable, toDegrees)
+ }
+ }
+ return rotateDrawable
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/ScaleDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/ScaleDrawableBuilder.kt
new file mode 100755
index 0000000..06a7c66
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/ScaleDrawableBuilder.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.ScaleDrawable
+import android.view.Gravity
+
+class ScaleDrawableBuilder : DrawableWrapperBuilder() {
+
+ private var level: Int = 10000
+ private var scaleGravity = Gravity.CENTER
+ private var scaleWidth: Float = 0f
+ private var scaleHeight: Float = 0f
+
+ fun level(level: Int) = apply { this.level = level }
+ fun scaleGravity(gravity: Int) = apply { this.scaleGravity = gravity }
+ fun scaleWidth(scale: Float) = apply { this.scaleWidth = scale }
+ fun scaleHeight(scale: Float) = apply { this.scaleHeight = scale }
+
+ override fun build(): Drawable {
+ val scaleDrawable = ScaleDrawable(drawable, scaleGravity, scaleWidth, scaleHeight)
+ scaleDrawable.level = level
+ return scaleDrawable
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/StateListDrawableBuilder.kt b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/StateListDrawableBuilder.kt
new file mode 100755
index 0000000..a2fde42
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/StateListDrawableBuilder.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+package com.fankes.tsbattery.utils.drawable.drawabletoolbox
+
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.StateListDrawable
+import android.util.StateSet
+
+class StateListDrawableBuilder {
+
+ private var pressed: Drawable? = null
+ private var disabled: Drawable? = null
+ private var selected: Drawable? = null
+ private var normal: Drawable = ColorDrawable(Color.TRANSPARENT)
+
+ fun pressed(pressed: Drawable?) = apply { this.pressed = pressed }
+ fun disabled(disabled: Drawable?) = apply { this.disabled = disabled }
+ fun selected(selected: Drawable?) = apply { this.selected = selected }
+ fun normal(normal: Drawable) = apply { this.normal = normal }
+
+ fun build(): StateListDrawable {
+ val stateListDrawable = StateListDrawable()
+ setupStateListDrawable(stateListDrawable)
+ return stateListDrawable
+ }
+
+ private fun setupStateListDrawable(stateListDrawable: StateListDrawable) {
+ pressed?.let {
+ stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), it)
+ }
+ disabled?.let {
+ stateListDrawable.addState(intArrayOf(-android.R.attr.state_enabled), it)
+ }
+ selected?.let {
+ stateListDrawable.addState(intArrayOf(android.R.attr.state_selected), it)
+ }
+ stateListDrawable.addState(StateSet.WILD_CARD, normal)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/tsbattery/view/MaterialSwitch.kt b/app/src/main/java/com/fankes/tsbattery/view/MaterialSwitch.kt
new file mode 100644
index 0000000..8737a4c
--- /dev/null
+++ b/app/src/main/java/com/fankes/tsbattery/view/MaterialSwitch.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
+ *
+ * This file is part of TSBattery.
+ *
+ * TSBattery is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * TSBattery is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * This file is Created by fankes on 2022/1/8.
+ */
+
+@file:Suppress("SameParameterValue")
+
+package com.fankes.tsbattery.view
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.util.AttributeSet
+import androidx.appcompat.widget.SwitchCompat
+import com.fankes.tsbattery.utils.dp
+import com.fankes.tsbattery.utils.drawable.drawabletoolbox.DrawableBuilder
+
+class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
+
+ private fun toColors(selected: Int, pressed: Int, normal: Int): ColorStateList {
+ val colors = intArrayOf(selected, pressed, normal)
+ val states = arrayOfNulls(3)
+ states[0] = intArrayOf(android.R.attr.state_checked)
+ states[1] = intArrayOf(android.R.attr.state_pressed)
+ states[2] = intArrayOf()
+ return ColorStateList(states, colors)
+ }
+
+ init {
+ trackDrawable = DrawableBuilder()
+ .rectangle()
+ .rounded()
+ .solidColor(0xFF656565.toInt())
+ .height(20.dp)
+ .cornerRadius(15.dp)
+ .build()
+ thumbDrawable = DrawableBuilder()
+ .rectangle()
+ .rounded()
+ .solidColor(Color.WHITE)
+ .size(20.dp, 20.dp)
+ .cornerRadius(20.dp)
+ .strokeWidth(2.dp)
+ .strokeColor(Color.TRANSPARENT)
+ .build()
+ trackTintList = toColors(
+ 0xFF656565.toInt(),
+ 0xFFCCCCCC.toInt(),
+ 0xFFCCCCCC.toInt()
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index a3d2ef5..cd87851 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,5 +1,6 @@
+ android:paddingBottom="5dp">
+ android:padding="15dp">
@@ -285,7 +285,7 @@
android:paddingLeft="15dp"
android:paddingRight="15dp">
-
-
-
+ android:padding="15dp">
@@ -462,6 +460,15 @@
android:layout_marginBottom="10dp"
android:alpha="0.8"
android:lineSpacingExtra="6dp"
+ android:text="Q.如何对单独的 APP 生效模块?\nA.请在 LsPosed 中勾选对应定义域即可,我们不建议使用 EdXposed。"
+ android:textColor="#777777"
+ android:textSize="12sp" />
+
+
@@ -478,13 +485,11 @@
android:elevation="0dp"
android:gravity="center"
android:orientation="vertical"
- android:paddingLeft="15dp"
- android:paddingRight="15dp">
+ android:padding="15dp">
@@ -509,7 +514,6 @@
-
+ app:cardCornerRadius="15dp"
+ app:cardElevation="0dp">
+
+
+