6 Commits
2.75 ... 2.8

Author SHA1 Message Date
eb75c1c511 Update version to 2.8 2022-06-26 23:53:19 +08:00
efc192b0ee Fix MIUI 12、12.5 (Android 10) not work bug 2022-06-26 23:49:48 +08:00
7b083daa3d Update Gradle & Kotlin & PlatformSDK
- Update Kotlin version to 1.7.0
- Update Gradle dependencies
- Merge legacy code
2022-06-10 17:21:33 +08:00
6b18128a57 Merge code 2022-06-08 19:12:10 +08:00
553098f6bf Make UI to Primary Theme 2022-06-08 15:11:33 +08:00
9499727087 Merge DialogBuilderFactory with new code style 2022-06-07 16:55:51 +08:00
19 changed files with 173 additions and 167 deletions

View File

@@ -2,7 +2,7 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/MIUINativeNotifyIcon) [![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/MIUINativeNotifyIcon)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE) [![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v2.75-green)](https://github.com/fankes/MIUINativeNotifyIcon/releases) [![Blank](https://img.shields.io/badge/version-v2.8-green)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/MIUINativeNotifyIcon/total?label=Release)](https://github.com/fankes/MIUINativeNotifyIcon/releases) [![Blank](https://img.shields.io/github/downloads/fankes/MIUINativeNotifyIcon/total?label=Release)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.miui.notify/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases) [![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.miui.notify/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet) [![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)

View File

@@ -1,11 +1,11 @@
plugins { plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android' id 'kotlin-android'
id 'com.google.devtools.ksp' version '1.6.21-1.0.5' id 'com.google.devtools.ksp' version '1.7.0-1.0.6'
} }
android { android {
compileSdk 31 compileSdk 32
signingConfigs { signingConfigs {
debug { debug {
@@ -21,7 +21,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.fankes.miui.notify" applicationId "com.fankes.miui.notify"
minSdk 28 minSdk 28
targetSdk 31 targetSdk 32
versionCode rootProject.ext.appVersionCode versionCode rootProject.ext.appVersionCode
versionName rootProject.ext.appVersionName versionName rootProject.ext.appVersionName
@@ -63,10 +63,10 @@ dependencies {
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.92' ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.92'
implementation "com.github.topjohnwu.libsu:core:3.1.2" implementation "com.github.topjohnwu.libsu:core:3.1.2"
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.3.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.0' implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.3'

View File

@@ -103,7 +103,8 @@ object SystemUIHooker : YukiBaseHooker() {
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
private val MiuiClockClass = VariousClass( private val MiuiClockClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.views.MiuiClock", "$SYSTEMUI_PACKAGE_NAME.statusbar.views.MiuiClock",
"$SYSTEMUI_PACKAGE_NAME.statusbar.policy.MiuiClock" "$SYSTEMUI_PACKAGE_NAME.statusbar.policy.MiuiClock",
"$SYSTEMUI_PACKAGE_NAME.statusbar.policy.Clock"
) )
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
@@ -198,18 +199,6 @@ object SystemUIHooker : YukiBaseHooker() {
private val hasHandleHeaderViews private val hasHandleHeaderViews
get() = safeOfFalse { NotificationHeaderViewWrapperClass.clazz.hasMethod { name = "handleHeaderViews" } } get() = safeOfFalse { NotificationHeaderViewWrapperClass.clazz.hasMethod { name = "handleHeaderViews" } }
/**
* 获取是否存在忽略图标色彩处理的方法
* @return [Boolean]
*/
private val hasIgnoreStatusBarIconColor
get() = safeOfFalse {
NotificationUtilClass.clazz.hasMethod {
name = "ignoreStatusBarIconColor"
param(ExpandedNotificationClass)
}
}
/** /**
* 处理为圆角图标 * 处理为圆角图标
* @return [Drawable] * @return [Drawable]
@@ -289,6 +278,18 @@ object SystemUIHooker : YukiBaseHooker() {
return xmsfPkg.ifBlank { targetPkg.ifBlank { packageName } } return xmsfPkg.ifBlank { targetPkg.ifBlank { packageName } }
} }
/**
* 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false
* @return [Boolean]
*/
private val isShowMiuiStyle get() = NotificationUtilClass.clazz.method { name = "showMiuiStyle" }.ignoredError().get().boolean()
/**
* 是否没有单独的 MIUI 通知栏样式
* @return [Boolean]
*/
private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass.not()
/** /**
* 获取全局上下文 * 获取全局上下文
* @return [Context] or null * @return [Context] or null
@@ -584,11 +585,10 @@ object SystemUIHooker : YukiBaseHooker() {
.get(this).call()?.let { .get(this).call()?.let {
it.javaClass.method { it.javaClass.method {
name = "getSbn" name = "getSbn"
}.get(it).invoke<StatusBarNotification>() }.ignoredError().get(it).invoke<StatusBarNotification>()
} ?: ExpandableNotificationRowClass.clazz } ?: ExpandableNotificationRowClass.clazz
.method { name = "getStatusBarNotification" } .method { name = "getStatusBarNotification" }
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(this).self) .get(this).invoke<StatusBarNotification>()
.invoke<StatusBarNotification>()
/** /**
* 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView] * 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView]
@@ -714,10 +714,8 @@ object SystemUIHooker : YukiBaseHooker() {
* MIUI 12 进行单独判断 * MIUI 12 进行单独判断
*/ */
field { name = "mCurrentSetColor" }.get(instance).int().also { color -> field { name = "mCurrentSetColor" }.get(instance).int().also { color ->
if (hasIgnoreStatusBarIconColor) { alpha = if (color.isWhite) 0.95f else 0.8f
alpha = if (color.isWhite) 0.95f else 0.8f setColorFilter(if (color.isWhite) color else Color.BLACK)
setColorFilter(if (color.isWhite) color else Color.BLACK)
} else setColorFilter(color)
} }
} }
} }
@@ -796,6 +794,9 @@ object SystemUIHooker : YukiBaseHooker() {
method { name = "handleHeaderViews" } method { name = "handleHeaderViews" }
else method { name = "resolveHeaderViews" } else method { name = "resolveHeaderViews" }
afterHook { afterHook {
/** 忽略较旧版本 - 在没有 MIUI 通知栏样式的时候可能出现奇怪的问题 */
if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return@afterHook
/** 获取小图标 */ /** 获取小图标 */
val iconImageView = val iconImageView =
NotificationHeaderViewWrapperClass.clazz NotificationHeaderViewWrapperClass.clazz
@@ -907,11 +908,11 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
} }
} }.ignoredHookClassNotFoundFailure()
/** 自动检查通知图标优化更新的注入监听 */ /** 自动检查通知图标优化更新的注入监听 */
MiuiClockClass.hook { MiuiClockClass.hook {
injectMember { injectMember {
method { name = "updateTime" } method { name = "updateTime" }.remedys { method { name = "updateClock" } }
afterHook { afterHook {
instance<View>().context.also { instance<View>().context.also {
/** 注册定时监听 */ /** 注册定时监听 */
@@ -923,6 +924,6 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
} }
}.ignoredHookClassNotFoundFailure() }
} }
} }

View File

@@ -81,9 +81,9 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
} }
/** 设置过滤按钮点击事件 */ /** 设置过滤按钮点击事件 */
binding.configTitleFilter.setOnClickListener { binding.configTitleFilter.setOnClickListener {
showDialog { showDialog<DiaIconFilterBinding> {
title = "按条件过滤" title = "按条件过滤"
val editText = bind<DiaIconFilterBinding>().diaIconFilterInputEdit.apply { binding.iconFiltersEdit.apply {
requestFocus() requestFocus()
invalidate() invalidate()
if (filterText.isNotBlank()) { if (filterText.isNotBlank()) {
@@ -92,8 +92,8 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
} }
} }
confirmButton { confirmButton {
if (editText.text.toString().isNotBlank()) { if (binding.iconFiltersEdit.text.toString().isNotBlank()) {
filterText = editText.text.toString().trim() filterText = binding.iconFiltersEdit.text.toString().trim()
refreshAdapterResult() refreshAdapterResult()
} else { } else {
toast(msg = "条件不能为空") toast(msg = "条件不能为空")

View File

@@ -149,13 +149,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
var statusBarIconCount = modulePrefs.get(DataConst.HOOK_STATUS_ICON_COUNT) var statusBarIconCount = modulePrefs.get(DataConst.HOOK_STATUS_ICON_COUNT)
var notifyIconAutoSyncTime = modulePrefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME) var notifyIconAutoSyncTime = modulePrefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
binding.colorIconHookItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE) binding.colorIconHookItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
binding.statusIconCountItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE) binding.statusIconCountItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE) && isLowerAndroidR.not()
binding.notifyIconConfigItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE) binding.notifyIconConfigItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
binding.notifyIconFixButton.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) binding.notifyIconFixButton.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconCustomCornerItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) && binding.notifyIconCustomCornerItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) &&
modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not() modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not() && isLowerAndroidR.not()
binding.notifyIconForceAppIconItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) binding.notifyIconForceAppIconItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconFixNotifyItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) binding.notifyIconFixNotifyItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) && isLowerAndroidR.not()
binding.notifyIconAutoSyncItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) binding.notifyIconAutoSyncItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.statusIconCountSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT) binding.statusIconCountSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT)
binding.statusIconCountChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT) binding.statusIconCountChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT)
@@ -177,7 +177,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
modulePrefs.put(DataConst.ENABLE_MODULE, b) modulePrefs.put(DataConst.ENABLE_MODULE, b)
binding.moduleEnableLogSwitch.isVisible = b binding.moduleEnableLogSwitch.isVisible = b
binding.colorIconHookItem.isVisible = b binding.colorIconHookItem.isVisible = b
binding.statusIconCountItem.isVisible = b binding.statusIconCountItem.isVisible = b && isLowerAndroidR.not()
binding.notifyIconConfigItem.isVisible = b binding.notifyIconConfigItem.isVisible = b
SystemUITool.showNeedRestartSnake(context = this) SystemUITool.showNeedRestartSnake(context = this)
} }
@@ -210,16 +210,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (btn.isPressed.not()) return@setOnCheckedChangeListener if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, b) modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, b)
binding.notifyIconFixButton.isVisible = b binding.notifyIconFixButton.isVisible = b
binding.notifyIconCustomCornerItem.isVisible = b && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not() binding.notifyIconCustomCornerItem.isVisible = b &&
modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not() && isLowerAndroidR.not()
binding.notifyIconForceAppIconItem.isVisible = b binding.notifyIconForceAppIconItem.isVisible = b
binding.notifyIconFixNotifyItem.isVisible = b binding.notifyIconFixNotifyItem.isVisible = b && isLowerAndroidR.not()
binding.notifyIconAutoSyncItem.isVisible = b binding.notifyIconAutoSyncItem.isVisible = b
SystemUITool.refreshSystemUI(context = this) SystemUITool.refreshSystemUI(context = this)
} }
binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b -> binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener if (btn.isPressed.not()) return@setOnCheckedChangeListener
fun saveState() { fun saveState() {
binding.notifyIconCustomCornerItem.isVisible = b.not() binding.notifyIconCustomCornerItem.isVisible = b.not() && isLowerAndroidR.not()
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b) modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
SystemUITool.refreshSystemUI(context = this) SystemUITool.refreshSystemUI(context = this)
} }
@@ -262,9 +263,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5 binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
/** 修改状态栏通知图标个数按钮点击事件 */ /** 修改状态栏通知图标个数按钮点击事件 */
binding.statusIconCountButton.setOnClickListener { binding.statusIconCountButton.setOnClickListener {
showDialog { showDialog<DiaStatusIconCountBinding> {
title = "设置最多显示的图标个数" title = "设置最多显示的图标个数"
val editText = bind<DiaStatusIconCountBinding>().diaStatusIconCountInputEdit.apply { binding.iconCountEdit.apply {
requestFocus() requestFocus()
invalidate() invalidate()
setText(statusBarIconCount.toString()) setText(statusBarIconCount.toString())
@@ -272,12 +273,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
confirmButton { confirmButton {
when { when {
(runCatching { editText.text.toString().toInt() }.getOrNull() ?: -1) (runCatching { binding.iconCountEdit.text.toString().toInt() }.getOrNull() ?: -1)
!in 0..100 -> snake(msg = "请输入有效数值") !in 0..100 -> snake(msg = "请输入有效数值")
editText.text.toString().isNotBlank() -> runCatching { binding.iconCountEdit.text.toString().isNotBlank() -> runCatching {
statusBarIconCount = editText.text.toString().trim().toInt() statusBarIconCount = binding.iconCountEdit.text.toString().trim().toInt()
modulePrefs.put(DataConst.HOOK_STATUS_ICON_COUNT, statusBarIconCount) modulePrefs.put(DataConst.HOOK_STATUS_ICON_COUNT, statusBarIconCount)
binding.statusIconCountText.text = statusBarIconCount.toString() this@MainActivity.binding.statusIconCountText.text = statusBarIconCount.toString()
SystemUITool.showNeedRestartSnake(context) SystemUITool.showNeedRestartSnake(context)
}.onFailure { snake(msg = "数值格式无效") } }.onFailure { snake(msg = "数值格式无效") }
else -> snake(msg = "请输入有效数值") else -> snake(msg = "请输入有效数值")
@@ -299,7 +300,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。" "模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
confirmButton(text = "保存设置") { confirmButton(text = "保存设置") {
notifyIconAutoSyncTime = it notifyIconAutoSyncTime = it
binding.notifyIconAutoSyncText.text = it this@MainActivity.binding.notifyIconAutoSyncText.text = it
modulePrefs.put(DataConst.NOTIFY_ICON_FIX_AUTO_TIME, it) modulePrefs.put(DataConst.NOTIFY_ICON_FIX_AUTO_TIME, it)
SystemUITool.refreshSystemUI(context, isRefreshCacheOnly = true) SystemUITool.refreshSystemUI(context, isRefreshCacheOnly = true)
} }

View File

@@ -27,7 +27,7 @@ package com.fankes.miui.notify.ui.activity.base
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.fankes.miui.notify.R import com.fankes.miui.notify.R
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
@@ -61,7 +61,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
/** 隐藏系统的标题栏 */ /** 隐藏系统的标题栏 */
supportActionBar?.hide() supportActionBar?.hide()
/** 初始化沉浸状态栏 */ /** 初始化沉浸状态栏 */
ViewCompat.getWindowInsetsController(window.decorView)?.apply { WindowCompat.getInsetsController(window, window.decorView).apply {
isAppearanceLightStatusBars = isNotSystemInDarkMode isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode isAppearanceLightNavigationBars = isNotSystemInDarkMode
} }

View File

@@ -20,7 +20,7 @@
* *
* This file is Created by fankes on 2022/1/8. * This file is Created by fankes on 2022/1/8.
*/ */
@file:Suppress("DEPRECATION", "CanvasSize") @file:Suppress("DEPRECATION", "CanvasSize", "OVERRIDE_DEPRECATION")
package com.fankes.miui.notify.utils.drawable.drawabletoolbox package com.fankes.miui.notify.utils.drawable.drawabletoolbox

View File

@@ -43,14 +43,6 @@ import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
/**
* 构造对话框
* @param isUseBlackTheme 是否使用深色主题
* @param initiate 对话框方法体
*/
fun Context.showDialog(isUseBlackTheme: Boolean = false, initiate: DialogBuilder.() -> Unit) =
DialogBuilder(context = this, isUseBlackTheme).apply(initiate).show()
/** /**
* 显示时间选择对话框 * 显示时间选择对话框
* @param timeSet 当前时间 - 不写将使用当前时间格式HH:mm * @param timeSet 当前时间 - 不写将使用当前时间格式HH:mm
@@ -59,20 +51,45 @@ fun Context.showDialog(isUseBlackTheme: Boolean = false, initiate: DialogBuilder
fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) = fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) =
TimePickerDialog(this, { _, h, m -> result("${h.autoZero}:${m.autoZero}") }, timeSet.hour, timeSet.minute, true).show() TimePickerDialog(this, { _, h, m -> result("${h.autoZero}:${m.autoZero}") }, timeSet.hour, timeSet.minute, true).show()
/**
* 构造 [VB] 自定义 View 对话框
* @param initiate 对话框方法体
*/
@JvmName(name = "showDialog-VB")
inline fun <reified VB : ViewBinding> Context.showDialog(initiate: DialogBuilder<VB>.() -> Unit) =
DialogBuilder<VB>(context = this, VB::class.java).apply(initiate).show()
/**
* 构造对话框
* @param initiate 对话框方法体
*/
inline fun Context.showDialog(initiate: DialogBuilder<*>.() -> Unit) = DialogBuilder<ViewBinding>(context = this).apply(initiate).show()
/** /**
* 对话框构造器 * 对话框构造器
* @param context 实例 * @param context 实例
* @param isUseBlackTheme 是否使用深色主题 - 对 AndroidX 风格无效 * @param bindingClass [ViewBinding] 的 [Class] 实例 or null
*/ */
class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean) { class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingClass: Class<*>? = null) {
private var instanceAndroidX: androidx.appcompat.app.AlertDialog.Builder? = null // 实例对象 private var instanceAndroidX: androidx.appcompat.app.AlertDialog.Builder? = null // 实例对象
private var instanceAndroid: android.app.AlertDialog.Builder? = null // 实例对象 private var instanceAndroid: android.app.AlertDialog.Builder? = null // 实例对象
private var dialogInstance: Dialog? = null // 对话框实例 private var dialogInstance: Dialog? = null // 对话框实例
private var customLayoutView: View? = null // 自定义布局
@CauseProblemsApi /**
var customLayoutView: View? = null // 自定义布局 * 获取 [DialogBuilder] 绑定布局对象
* @return [VB]
*/
val binding by lazy {
bindingClass?.method {
name = "inflate"
param(LayoutInflaterClass)
}?.get()?.invoke<VB>(LayoutInflater.from(context))?.apply {
customLayoutView = root
} ?: error("This dialog maybe not a custom view dialog")
}
/** /**
* 是否需要使用 AndroidX 风格对话框 * 是否需要使用 AndroidX 风格对话框
@@ -83,12 +100,7 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
init { init {
if (isUsingAndroidX) if (isUsingAndroidX)
runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) } runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) }
else runInSafe { else runInSafe { instanceAndroid = android.app.AlertDialog.Builder(context, android.R.style.Theme_Material_Light_Dialog) }
instanceAndroid = android.app.AlertDialog.Builder(
context,
if (isUseBlackTheme) android.R.style.Theme_Material_Dialog else android.R.style.Theme_Material_Light_Dialog
)
}
} }
/** 设置对话框不可关闭 */ /** 设置对话框不可关闭 */
@@ -135,18 +147,6 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
else customLayoutView?.findViewWithTag<TextView>("progressContent")?.text = value else customLayoutView?.findViewWithTag<TextView>("progressContent")?.text = value
} }
/**
* 设置对话框自定义布局
* @return [ViewBinding]
*/
inline fun <reified T : ViewBinding> bind() =
T::class.java.method {
name = "inflate"
param(LayoutInflaterClass)
}.get().invoke<T>(LayoutInflater.from(context))?.apply {
customLayoutView = root
} ?: error("binding failed")
/** /**
* 设置对话框确定按钮 * 设置对话框确定按钮
* @param text 按钮文本内容 * @param text 按钮文本内容
@@ -184,7 +184,10 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
fun cancel() = dialogInstance?.cancel() fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */ /** 显示对话框 */
internal fun show() = @CauseProblemsApi
fun show() {
/** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */
if (bindingClass != null) binding
if (isUsingAndroidX) runInSafe { if (isUsingAndroidX) runInSafe {
instanceAndroidX?.create()?.apply { instanceAndroidX?.create()?.apply {
customLayoutView?.let { setView(it) } customLayoutView?.let { setView(it) }
@@ -196,8 +199,7 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
window?.setBackgroundDrawable( window?.setBackgroundDrawable(
GradientDrawable( GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, GradientDrawable.Orientation.TOP_BOTTOM,
if (isUseBlackTheme) intArrayOf(0xFF2D2D2D.toInt(), 0xFF2D2D2D.toInt()) intArrayOf(Color.WHITE, Color.WHITE)
else intArrayOf(Color.WHITE, Color.WHITE)
).apply { ).apply {
shape = GradientDrawable.RECTANGLE shape = GradientDrawable.RECTANGLE
gradientType = GradientDrawable.LINEAR_GRADIENT gradientType = GradientDrawable.LINEAR_GRADIENT
@@ -206,4 +208,5 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
dialogInstance = this dialogInstance = this
}?.show() }?.show()
} }
}
} }

View File

@@ -61,7 +61,7 @@ object GithubReleaseTool {
override fun onFailure(call: Call, e: IOException) {} override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) = runInSafe { override fun onResponse(call: Call, response: Response) = runInSafe {
JSONObject(response.body?.string() ?: "").apply { JSONObject(response.body.string()).apply {
GithubReleaseBean( GithubReleaseBean(
name = getString("name"), name = getString("name"),
htmlUrl = getString("html_url"), htmlUrl = getString("html_url"),

View File

@@ -78,40 +78,32 @@ object IconRuleManagerTool {
* @param callback 成功后回调 * @param callback 成功后回调
*/ */
fun syncByHand(context: Context, callback: () -> Unit) = fun syncByHand(context: Context, callback: () -> Unit) =
context.showDialog { context.showDialog<DiaSourceFromBinding> {
title = "同步列表" title = "同步列表"
var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY) var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY)
var customUrl = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL) var customUrl = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL)
bind<DiaSourceFromBinding>().apply { binding.sourceUrlEdit.apply {
diaSfText.apply { if (customUrl.isNotBlank()) {
if (customUrl.isNotBlank()) { setText(customUrl)
setText(customUrl) setSelection(customUrl.length)
setSelection(customUrl.length)
}
doOnTextChanged { text, _, _, _ -> customUrl = text.toString() }
}
diaSfTextLin.isVisible = sourceType == TYPE_SOURCE_SYNC_WAY_3
diaSfRd1.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_1
diaSfRd2.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_2
diaSfRd3.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_3
diaSfRd1.setOnClickListener {
diaSfRd2.isChecked = false
diaSfRd3.isChecked = false
diaSfTextLin.isVisible = false
sourceType = TYPE_SOURCE_SYNC_WAY_1
}
diaSfRd2.setOnClickListener {
diaSfRd1.isChecked = false
diaSfRd3.isChecked = false
diaSfTextLin.isVisible = false
sourceType = TYPE_SOURCE_SYNC_WAY_2
}
diaSfRd3.setOnClickListener {
diaSfRd1.isChecked = false
diaSfRd2.isChecked = false
diaSfTextLin.isVisible = true
sourceType = TYPE_SOURCE_SYNC_WAY_3
} }
doOnTextChanged { text, _, _, _ -> customUrl = text.toString() }
}
binding.sourceFromTextLin.isVisible = sourceType == TYPE_SOURCE_SYNC_WAY_3
binding.sourceRadio1.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_1
binding.sourceRadio2.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_2
binding.sourceRadio3.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_3
binding.sourceRadio1.setOnClickListener {
binding.sourceFromTextLin.isVisible = false
sourceType = TYPE_SOURCE_SYNC_WAY_1
}
binding.sourceRadio2.setOnClickListener {
binding.sourceFromTextLin.isVisible = false
sourceType = TYPE_SOURCE_SYNC_WAY_2
}
binding.sourceRadio3.setOnClickListener {
binding.sourceFromTextLin.isVisible = true
sourceType = TYPE_SOURCE_SYNC_WAY_3
} }
confirmButton { confirmButton {
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType) context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType)
@@ -120,15 +112,15 @@ object IconRuleManagerTool {
} }
cancelButton() cancelButton()
neutralButton(text = "自定义规则") { neutralButton(text = "自定义规则") {
context.showDialog { context.showDialog<DiaSourceFromStringBinding> {
title = "自定义规则(调试)" title = "自定义规则(调试)"
val editText = bind<DiaSourceFromStringBinding>().diaSfsInputEdit.apply { binding.jsonRuleEdit.apply {
requestFocus() requestFocus()
invalidate() invalidate()
} }
IconPackParams(context).also { params -> IconPackParams(context).also { params ->
confirmButton(text = "合并") { confirmButton(text = "合并") {
editText.text.toString().also { jsonString -> binding.jsonRuleEdit.text.toString().also { jsonString ->
when { when {
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据") jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
jsonString.isNotBlank() -> { jsonString.isNotBlank() -> {
@@ -146,7 +138,7 @@ object IconRuleManagerTool {
} }
} }
cancelButton(text = "覆盖") { cancelButton(text = "覆盖") {
editText.text.toString().also { jsonString -> binding.jsonRuleEdit.text.toString().also { jsonString ->
when { when {
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据") jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
jsonString.isNotBlank() -> { jsonString.isNotBlank() -> {
@@ -351,7 +343,7 @@ object IconRuleManagerTool {
} }
override fun onResponse(call: Call, response: Response) { override fun onResponse(call: Call, response: Response) {
val bodyString = response.body?.string() ?: "" val bodyString = response.body.string()
(context as? Activity?)?.runOnUiThread { result(true, bodyString) } ?: result(true, bodyString) (context as? Activity?)?.runOnUiThread { result(true, bodyString) } ?: result(true, bodyString)
} }
}) })

View File

@@ -14,7 +14,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/dia_icon_filter_input_edit" android:id="@+id/icon_filters_edit"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -19,32 +20,40 @@
android:text="在线规则将不定期更新,建议定期同步列表以适配更多 APP若无法同步请自行寻找解决方法或魔法上网。" android:text="在线规则将不定期更新,建议定期同步列表以适配更多 APP若无法同步请自行寻找解决方法或魔法上网。"
android:textSize="14sp" /> android:textSize="14sp" />
<com.google.android.material.radiobutton.MaterialRadioButton <RadioGroup
android:id="@+id/dia_sf_rd1" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:text="从 FastGit 获取" />
<com.google.android.material.radiobutton.MaterialRadioButton <com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/dia_sf_rd2" android:id="@+id/source_radio_1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="从 Github Raw 获取" /> android:text="从 FastGit 获取"
app:buttonTint="@color/colorPrimaryAccent" />
<com.google.android.material.radiobutton.MaterialRadioButton <com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/dia_sf_rd3" android:id="@+id/source_radio_2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="从自定义地址获取" /> android:text="从 Github Raw 获取"
app:buttonTint="@color/colorPrimaryAccent" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/source_radio_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="从自定义地址获取"
app:buttonTint="@color/colorPrimaryAccent" />
</RadioGroup>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/dia_sf_text_lin" android:id="@+id/source_from_text_lin"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"> android:visibility="gone">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/dia_sf_text" android:id="@+id/source_url_edit"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"

View File

@@ -25,7 +25,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/dia_sfs_input_edit" android:id="@+id/json_rule_edit"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="150dp" android:layout_height="150dp"
android:ellipsize="end" android:ellipsize="end"

View File

@@ -14,7 +14,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/dia_status_icon_count_input_edit" android:id="@+id/icon_count_edit"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:digits="0123456789" android:digits="0123456789"

View File

@@ -2,15 +2,16 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight"> <style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item> <item name="colorPrimary">@color/colorPrimaryAccent</item>
<item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
<item name="colorOnPrimary">@color/black</item> <item name="colorOnPrimary">@color/colorPrimaryAccent</item>
<!-- Secondary brand color. --> <!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item> <item name="colorSecondary">@color/colorPrimaryAccent</item>
<item name="colorSecondaryVariant">@color/teal_200</item> <item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/colorPrimaryAccent</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor">@color/black</item>
<item name="android:windowLightStatusBar">false</item>
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
</style> </style>
</resources> </resources>

View File

@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="purple_200">#656565</color> <color name="colorPrimaryAccent">#656565</color>
<color name="purple_500">#656565</color>
<color name="purple_700">#656565</color>
<color name="teal_200">#656565</color>
<color name="teal_700">#656565</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="trans">#00000000</color> <color name="trans">#00000000</color>

View File

@@ -2,15 +2,16 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight"> <style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item> <item name="colorPrimary">@color/colorPrimaryAccent</item>
<item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
<item name="colorOnPrimary">@color/teal_700</item> <item name="colorOnPrimary">@color/colorPrimaryAccent</item>
<!-- Secondary brand color. --> <!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item> <item name="colorSecondary">@color/colorPrimaryAccent</item>
<item name="colorSecondaryVariant">@color/teal_700</item> <item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/colorPrimaryAccent</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor">@color/white</item>
<item name="android:windowLightStatusBar">true</item>
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
</style> </style>
</resources> </resources>

View File

@@ -1,12 +1,12 @@
plugins { plugins {
id 'com.android.application' version '7.2.0' apply false id 'com.android.application' version '7.2.1' apply false
id 'com.android.library' version '7.2.0' apply false id 'com.android.library' version '7.2.1' apply false
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
} }
ext { ext {
appVersionName = "2.75" appVersionName = "2.8"
appVersionCode = 33 appVersionCode = 34
enableR8 = true enableR8 = true
} }

View File

@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 org.gradle.jvmargs=-XX:+UseParallelGC
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
@@ -19,3 +19,5 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
# Incremental
kotlin.incremental.useClasspathSnapshot=true