From 8841ad7f5966f8d547be285755fb02a50bb6c387 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Sat, 8 Jan 2022 01:12:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=85=A8=E6=96=B0=20Material=20You=20?= =?UTF-8?q?=E9=A3=8E=E6=A0=BC=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 +- .../tsbattery/application/TSApplication.kt | 11 + .../com/fankes/tsbattery/ui/MainActivity.kt | 25 + .../fankes/tsbattery/utils/DialogBuilder.kt | 14 +- .../java/com/fankes/tsbattery/utils/Utils.kt | 24 + .../drawable/drawabletoolbox/Compatible.kt | 291 +++++++++++ .../drawable/drawabletoolbox/Constants.kt | 29 ++ .../drawabletoolbox/DrawableBuilder.kt | 488 ++++++++++++++++++ .../drawabletoolbox/DrawableProperties.kt | 220 ++++++++ .../drawabletoolbox/DrawableWrapperBuilder.kt | 33 ++ .../drawable/drawabletoolbox/FlipDrawable.kt | 77 +++ .../drawabletoolbox/FlipDrawableBuilder.kt | 34 ++ .../drawabletoolbox/LayerDrawableBuilder.kt | 181 +++++++ .../PathShapeDrawableBuilder.kt | 60 +++ .../drawabletoolbox/RippleDrawableBuilder.kt | 72 +++ .../drawabletoolbox/RotateDrawableBuilder.kt | 51 ++ .../drawabletoolbox/ScaleDrawableBuilder.kt | 44 ++ .../StateListDrawableBuilder.kt | 59 +++ .../fankes/tsbattery/view/MaterialSwitch.kt | 68 +++ app/src/main/res/layout/activity_main.xml | 54 +- 20 files changed, 1814 insertions(+), 23 deletions(-) create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Compatible.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/Constants.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableProperties.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/DrawableWrapperBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawable.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/FlipDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/LayerDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/PathShapeDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RippleDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/RotateDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/ScaleDrawableBuilder.kt create mode 100755 app/src/main/java/com/fankes/tsbattery/utils/drawable/drawabletoolbox/StateListDrawableBuilder.kt create mode 100644 app/src/main/java/com/fankes/tsbattery/view/MaterialSwitch.kt 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"> + + +