12 Commits
2.7 ... 2.8

22 changed files with 327 additions and 210 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.7-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

@@ -43,6 +43,7 @@ import android.view.ViewOutlineProvider
import android.widget.ImageView import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.isVisible
import com.fankes.miui.notify.bean.IconDataBean import com.fankes.miui.notify.bean.IconDataBean
import com.fankes.miui.notify.data.DataConst import com.fankes.miui.notify.data.DataConst
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
@@ -102,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"
) )
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
@@ -197,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]
@@ -288,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
@@ -583,11 +585,34 @@ 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]
* @param initiate 新的 [ImageView] 方法体 - 失败会返回当前 [ImageView]
*/
private fun ImageView.clone(initiate: ImageView.() -> Unit) {
(parent as? ViewGroup?)?.also { parent ->
/** 将之前的 [ImageView] 调为全透明且隐藏 */
alpha = 0f
isVisible = false
/** 将内容清空 */
setImageDrawable(null)
setBackgroundColor(Color.TRANSPARENT)
/** 创建一个傀儡 */
parent.findViewWithTag<ImageView?>("new_view").also { base ->
if (base == null) parent.addView(ImageView(context).also { new ->
new.tag = "new_view"
/** 克隆它的 [ViewGroup.LayoutParams] */
new.layoutParams = layoutParams
initiate(new)
}) else initiate(base)
}
} ?: initiate(this)
}
/** 注册 */ /** 注册 */
private fun register() { private fun register() {
@@ -689,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)
} }
} }
} }
@@ -771,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
@@ -802,7 +828,7 @@ object SystemUIHooker : YukiBaseHooker() {
injectMember { injectMember {
method { name = "handleAppIcon" } method { name = "handleAppIcon" }
replaceUnit { replaceUnit {
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply { field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.clone {
compatNotifyIcon( compatNotifyIcon(
context = context, context = context,
expandedNf = instance.getRowPair().second.getSbn(), expandedNf = instance.getRowPair().second.getSbn(),
@@ -882,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 {
/** 注册定时监听 */ /** 注册定时监听 */
@@ -898,6 +924,6 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
} }
}.ignoredHookClassNotFoundFailure() }
} }
} }

View File

@@ -24,10 +24,6 @@
package com.fankes.miui.notify.ui.activity package com.fankes.miui.notify.ui.activity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.fankes.miui.notify.R import com.fankes.miui.notify.R
import com.fankes.miui.notify.bean.IconDataBean import com.fankes.miui.notify.bean.IconDataBean
@@ -85,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()) {
@@ -96,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 = "条件不能为空")
@@ -116,46 +112,33 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
binding.configTitleSync.setOnClickListener { onStartRefresh() } binding.configTitleSync.setOnClickListener { onStartRefresh() }
/** 设置列表元素和 Adapter */ /** 设置列表元素和 Adapter */
binding.configListView.apply { binding.configListView.apply {
adapter = object : BaseAdapter() { bindAdapter {
onBindDatas { iconDatas }
override fun getCount() = iconDatas.size onBindViews<AdapterConfigBinding> { binding, position ->
iconDatas[position].also { bean ->
override fun getItem(position: Int) = iconDatas[position] binding.adpAppIcon.setImageBitmap(bean.iconBitmap)
(if (bean.iconColor != 0) bean.iconColor else resources.getColor(R.color.colorTextGray)).also { color ->
override fun getItemId(position: Int) = position.toLong() binding.adpAppIcon.setColorFilter(color)
binding.adpAppName.setTextColor(color)
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var cView = convertView
val holder: AdapterConfigBinding
if (convertView == null) {
holder = AdapterConfigBinding.inflate(LayoutInflater.from(context))
cView = holder.root
cView.tag = holder
} else holder = convertView.tag as AdapterConfigBinding
getItem(position).also {
holder.adpAppIcon.setImageBitmap(it.iconBitmap)
(if (it.iconColor != 0) it.iconColor else resources.getColor(R.color.colorTextGray)).also { color ->
holder.adpAppIcon.setColorFilter(color)
holder.adpAppName.setTextColor(color)
} }
holder.adpAppName.text = it.appName binding.adpAppName.text = bean.appName
holder.adpAppPkgName.text = it.packageName binding.adpAppPkgName.text = bean.packageName
holder.adpCbrName.text = "贡献者:" + it.contributorName binding.adpCbrName.text = "贡献者:" + bean.contributorName
isAppNotifyHookOf(it).also { e -> isAppNotifyHookOf(bean).also { e ->
holder.adpAppOpenSwitch.isChecked = e binding.adpAppOpenSwitch.isChecked = e
holder.adpAppAllSwitch.isEnabled = e binding.adpAppAllSwitch.isEnabled = e
} }
holder.adpAppOpenSwitch.setOnCheckedChangeListener { btn, b -> binding.adpAppOpenSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener if (btn.isPressed.not()) return@setOnCheckedChangeListener
putAppNotifyHookOf(it, b) putAppNotifyHookOf(bean, b)
holder.adpAppAllSwitch.isEnabled = b binding.adpAppAllSwitch.isEnabled = b
SystemUITool.refreshSystemUI(context = this@ConfigureActivity) SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
} }
holder.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(it) binding.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(bean)
holder.adpAppAllSwitch.setOnCheckedChangeListener { btn, b -> binding.adpAppAllSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener if (btn.isPressed.not()) return@setOnCheckedChangeListener
fun saveState() { fun saveState() {
putAppNotifyHookAllOf(it, b) putAppNotifyHookAllOf(bean, b)
SystemUITool.refreshSystemUI(context = this@ConfigureActivity) SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
} }
if (b) showDialog { if (b) showDialog {
@@ -169,7 +152,6 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
} else saveState() } else saveState()
} }
} }
return cView!!
} }
}.apply { }.apply {
setOnItemLongClickListener { _, _, p, _ -> setOnItemLongClickListener { _, _, p, _ ->

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

@@ -0,0 +1,87 @@
/*
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/MIUINativeNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/6/3.
*/
package com.fankes.miui.notify.utils.factory
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import androidx.viewbinding.ViewBinding
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
/**
* 绑定 [BaseAdapter] 到 [ListView]
* @param initiate 方法体
* @return [BaseAdapter]
*/
inline fun ListView.bindAdapter(initiate: BaseAdapterCreater.() -> Unit) =
BaseAdapterCreater(context).apply(initiate).baseAdapter?.apply { adapter = this } ?: error("BaseAdapter not binded")
/**
* [BaseAdapter] 创建类
* @param context 实例
*/
class BaseAdapterCreater(val context: Context) {
/** 当前 [List] 回调 */
var listDataCallback: (() -> List<*>)? = null
/** 当前 [BaseAdapter] */
var baseAdapter: BaseAdapter? = null
/**
* 绑定 [List] 到 [ListView]
* @param result 回调数据
*/
fun onBindDatas(result: (() -> List<*>)) {
listDataCallback = result
}
/**
* 绑定 [BaseAdapter] 到 [ListView]
* @param bindViews 回调 - ([VB] 每项,[Int] 下标)
*/
inline fun <reified VB : ViewBinding> onBindViews(crossinline bindViews: (binding: VB, position: Int) -> Unit) {
baseAdapter = object : BaseAdapter() {
override fun getCount() = listDataCallback?.let { it() }?.size ?: 0
override fun getItem(position: Int) = listDataCallback?.let { it() }?.get(position)
override fun getItemId(position: Int) = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var holderView = convertView
val holder: VB
if (convertView == null) {
holder = VB::class.java.method {
name = "inflate"
param(LayoutInflaterClass)
}.get().invoke<VB>(LayoutInflater.from(context)) ?: error("ViewHolder binding failed")
holderView = holder.root.apply { tag = holder }
} else holder = convertView.tag as VB
bindViews(holder, position)
return holderView ?: error("ViewHolder binding failed")
}
}
}
}

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

@@ -24,11 +24,15 @@ package com.fankes.miui.notify.utils.tool
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import android.icu.util.TimeZone
import com.fankes.miui.notify.utils.factory.* import com.fankes.miui.notify.utils.factory.*
import okhttp3.* import okhttp3.*
import org.json.JSONObject import org.json.JSONObject
import java.io.IOException import java.io.IOException
import java.io.Serializable import java.io.Serializable
import java.util.*
/** /**
* 获取 Github Release 最新版本工具类 * 获取 Github Release 最新版本工具类
@@ -57,12 +61,12 @@ 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"),
content = getString("body"), content = getString("body"),
date = getString("published_at").replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "") date = getString("published_at").localTime()
).apply { ).apply {
fun showUpdate() = context.showDialog { fun showUpdate() = context.showDialog {
title = "最新版本 $name" title = "最新版本 $name"
@@ -112,6 +116,18 @@ object GithubReleaseTool {
}) })
} }
/**
* 格式化时间为本地时区
* @return [String] 本地时区时间
*/
private fun String.localTime() = replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "").let {
runCatching {
val local = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT).apply { timeZone = Calendar.getInstance().timeZone }
val current = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT).apply { timeZone = TimeZone.getTimeZone("GMT") }
local.format(current.parse(it))
}.getOrNull() ?: it
}
/** /**
* Github Release bean * Github Release bean
* @param name 版本名称 * @param name 版本名称

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

@@ -23,6 +23,7 @@
package com.fankes.miui.notify.utils.tool package com.fankes.miui.notify.utils.tool
import android.content.Context import android.content.Context
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.utils.factory.openBrowser import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.showDialog import com.fankes.miui.notify.utils.factory.showDialog
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
@@ -35,7 +36,7 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
object YukiPromoteTool { object YukiPromoteTool {
/** 推广已读存储键值 */ /** 推广已读存储键值 */
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed", false) private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed_${BuildConfig.VERSION_NAME}", false)
/** /**
* 显示推广对话框 * 显示推广对话框

View File

@@ -316,7 +316,7 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:alpha="0.6" android:alpha="0.6"
android:lineSpacingExtra="6dp" android:lineSpacingExtra="6dp"
android:text="此选项默认开启MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。" android:text="此选项默认开启MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。\n请注意可能无法兼容中置挖孔屏的设备。"
android:textColor="@color/colorTextDark" android:textColor="@color/colorTextDark"
android:textSize="12sp" /> android:textSize="12sp" />
@@ -885,7 +885,7 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:alpha="0.8" android:alpha="0.8"
android:lineSpacingExtra="10dp" android:lineSpacingExtra="10dp"
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 自身就存在的问题,后期只能等官方修复。\n(2) 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化。\n(3) 建议最低从 MIUI 12.5 “2021-5-18” 开发版以后开始使用,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块问题,将不再进行适配。" android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 强行设置 APP 图标的问题,暂时没有找到解决方案,强行破坏修复方式会导致原生动画出现问题,后期有解决方案再研究。\n(2) 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化。\n(3) 建议最低从 MIUI 12.5 “2021-5-18” 开发版以后开始使用,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块问题,将不再进行适配。"
android:textColor="@color/colorTextDark" android:textColor="@color/colorTextDark"
android:textSize="12sp" /> android:textSize="12sp" />

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.7" appVersionName = "2.8"
appVersionCode = 32 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
@@ -18,4 +18,6 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
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