mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-06 10:45:20 +08:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
eb75c1c511
|
|||
efc192b0ee
|
|||
7b083daa3d
|
|||
6b18128a57
|
|||
553098f6bf
|
|||
9499727087
|
|||
0036ba0090
|
|||
2e62939181
|
|||
30acbff3d5
|
|||
093529baea
|
|||
d9d40ac08e
|
|||
99bd924c66
|
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
[](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
|
||||
[](https://t.me/XiaofangInternet)
|
||||
|
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
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 {
|
||||
compileSdk 31
|
||||
compileSdk 32
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
@@ -21,7 +21,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "com.fankes.miui.notify"
|
||||
minSdk 28
|
||||
targetSdk 31
|
||||
targetSdk 32
|
||||
versionCode rootProject.ext.appVersionCode
|
||||
versionName rootProject.ext.appVersionName
|
||||
|
||||
@@ -63,10 +63,10 @@ dependencies {
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.92'
|
||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'com.google.android.material:material:1.6.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
|
||||
implementation 'androidx.core:core-ktx:1.8.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.2'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
|
@@ -43,6 +43,7 @@ import android.view.ViewOutlineProvider
|
||||
import android.widget.ImageView
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
@@ -102,7 +103,8 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val MiuiClockClass = VariousClass(
|
||||
"$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
|
||||
get() = safeOfFalse { NotificationHeaderViewWrapperClass.clazz.hasMethod { name = "handleHeaderViews" } }
|
||||
|
||||
/**
|
||||
* 获取是否存在忽略图标色彩处理的方法
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val hasIgnoreStatusBarIconColor
|
||||
get() = safeOfFalse {
|
||||
NotificationUtilClass.clazz.hasMethod {
|
||||
name = "ignoreStatusBarIconColor"
|
||||
param(ExpandedNotificationClass)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理为圆角图标
|
||||
* @return [Drawable]
|
||||
@@ -288,6 +278,18 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
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
|
||||
@@ -583,11 +585,34 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
.get(this).call()?.let {
|
||||
it.javaClass.method {
|
||||
name = "getSbn"
|
||||
}.get(it).invoke<StatusBarNotification>()
|
||||
}.ignoredError().get(it).invoke<StatusBarNotification>()
|
||||
} ?: ExpandableNotificationRowClass.clazz
|
||||
.method { name = "getStatusBarNotification" }
|
||||
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(this).self)
|
||||
.invoke<StatusBarNotification>()
|
||||
.get(this).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() {
|
||||
@@ -689,10 +714,8 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
* MIUI 12 进行单独判断
|
||||
*/
|
||||
field { name = "mCurrentSetColor" }.get(instance).int().also { color ->
|
||||
if (hasIgnoreStatusBarIconColor) {
|
||||
alpha = if (color.isWhite) 0.95f else 0.8f
|
||||
setColorFilter(if (color.isWhite) color else Color.BLACK)
|
||||
} else setColorFilter(color)
|
||||
alpha = if (color.isWhite) 0.95f else 0.8f
|
||||
setColorFilter(if (color.isWhite) color else Color.BLACK)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -771,6 +794,9 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
method { name = "handleHeaderViews" }
|
||||
else method { name = "resolveHeaderViews" }
|
||||
afterHook {
|
||||
/** 忽略较旧版本 - 在没有 MIUI 通知栏样式的时候可能出现奇怪的问题 */
|
||||
if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return@afterHook
|
||||
|
||||
/** 获取小图标 */
|
||||
val iconImageView =
|
||||
NotificationHeaderViewWrapperClass.clazz
|
||||
@@ -802,7 +828,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
injectMember {
|
||||
method { name = "handleAppIcon" }
|
||||
replaceUnit {
|
||||
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
|
||||
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.clone {
|
||||
compatNotifyIcon(
|
||||
context = context,
|
||||
expandedNf = instance.getRowPair().second.getSbn(),
|
||||
@@ -882,11 +908,11 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
/** 自动检查通知图标优化更新的注入监听 */
|
||||
MiuiClockClass.hook {
|
||||
injectMember {
|
||||
method { name = "updateTime" }
|
||||
method { name = "updateTime" }.remedys { method { name = "updateClock" } }
|
||||
afterHook {
|
||||
instance<View>().context.also {
|
||||
/** 注册定时监听 */
|
||||
@@ -898,6 +924,6 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,10 +24,6 @@
|
||||
|
||||
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 com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
@@ -85,9 +81,9 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
}
|
||||
/** 设置过滤按钮点击事件 */
|
||||
binding.configTitleFilter.setOnClickListener {
|
||||
showDialog {
|
||||
showDialog<DiaIconFilterBinding> {
|
||||
title = "按条件过滤"
|
||||
val editText = bind<DiaIconFilterBinding>().diaIconFilterInputEdit.apply {
|
||||
binding.iconFiltersEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
if (filterText.isNotBlank()) {
|
||||
@@ -96,8 +92,8 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
}
|
||||
}
|
||||
confirmButton {
|
||||
if (editText.text.toString().isNotBlank()) {
|
||||
filterText = editText.text.toString().trim()
|
||||
if (binding.iconFiltersEdit.text.toString().isNotBlank()) {
|
||||
filterText = binding.iconFiltersEdit.text.toString().trim()
|
||||
refreshAdapterResult()
|
||||
} else {
|
||||
toast(msg = "条件不能为空")
|
||||
@@ -116,46 +112,33 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
binding.configTitleSync.setOnClickListener { onStartRefresh() }
|
||||
/** 设置列表元素和 Adapter */
|
||||
binding.configListView.apply {
|
||||
adapter = object : BaseAdapter() {
|
||||
|
||||
override fun getCount() = iconDatas.size
|
||||
|
||||
override fun getItem(position: Int) = iconDatas[position]
|
||||
|
||||
override fun getItemId(position: Int) = position.toLong()
|
||||
|
||||
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)
|
||||
bindAdapter {
|
||||
onBindDatas { iconDatas }
|
||||
onBindViews<AdapterConfigBinding> { binding, position ->
|
||||
iconDatas[position].also { bean ->
|
||||
binding.adpAppIcon.setImageBitmap(bean.iconBitmap)
|
||||
(if (bean.iconColor != 0) bean.iconColor else resources.getColor(R.color.colorTextGray)).also { color ->
|
||||
binding.adpAppIcon.setColorFilter(color)
|
||||
binding.adpAppName.setTextColor(color)
|
||||
}
|
||||
holder.adpAppName.text = it.appName
|
||||
holder.adpAppPkgName.text = it.packageName
|
||||
holder.adpCbrName.text = "贡献者:" + it.contributorName
|
||||
isAppNotifyHookOf(it).also { e ->
|
||||
holder.adpAppOpenSwitch.isChecked = e
|
||||
holder.adpAppAllSwitch.isEnabled = e
|
||||
binding.adpAppName.text = bean.appName
|
||||
binding.adpAppPkgName.text = bean.packageName
|
||||
binding.adpCbrName.text = "贡献者:" + bean.contributorName
|
||||
isAppNotifyHookOf(bean).also { e ->
|
||||
binding.adpAppOpenSwitch.isChecked = e
|
||||
binding.adpAppAllSwitch.isEnabled = e
|
||||
}
|
||||
holder.adpAppOpenSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
binding.adpAppOpenSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
putAppNotifyHookOf(it, b)
|
||||
holder.adpAppAllSwitch.isEnabled = b
|
||||
putAppNotifyHookOf(bean, b)
|
||||
binding.adpAppAllSwitch.isEnabled = b
|
||||
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
|
||||
}
|
||||
holder.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(it)
|
||||
holder.adpAppAllSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
binding.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(bean)
|
||||
binding.adpAppAllSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
fun saveState() {
|
||||
putAppNotifyHookAllOf(it, b)
|
||||
putAppNotifyHookAllOf(bean, b)
|
||||
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
|
||||
}
|
||||
if (b) showDialog {
|
||||
@@ -169,7 +152,6 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
} else saveState()
|
||||
}
|
||||
}
|
||||
return cView!!
|
||||
}
|
||||
}.apply {
|
||||
setOnItemLongClickListener { _, _, p, _ ->
|
||||
|
@@ -149,13 +149,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
var statusBarIconCount = modulePrefs.get(DataConst.HOOK_STATUS_ICON_COUNT)
|
||||
var notifyIconAutoSyncTime = modulePrefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
|
||||
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.notifyIconFixButton.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.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.statusIconCountSwitch.isChecked = 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)
|
||||
binding.moduleEnableLogSwitch.isVisible = b
|
||||
binding.colorIconHookItem.isVisible = b
|
||||
binding.statusIconCountItem.isVisible = b
|
||||
binding.statusIconCountItem.isVisible = b && isLowerAndroidR.not()
|
||||
binding.notifyIconConfigItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
@@ -210,16 +210,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, 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.notifyIconFixNotifyItem.isVisible = b
|
||||
binding.notifyIconFixNotifyItem.isVisible = b && isLowerAndroidR.not()
|
||||
binding.notifyIconAutoSyncItem.isVisible = b
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
fun saveState() {
|
||||
binding.notifyIconCustomCornerItem.isVisible = b.not()
|
||||
binding.notifyIconCustomCornerItem.isVisible = b.not() && isLowerAndroidR.not()
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
@@ -262,9 +263,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
|
||||
/** 修改状态栏通知图标个数按钮点击事件 */
|
||||
binding.statusIconCountButton.setOnClickListener {
|
||||
showDialog {
|
||||
showDialog<DiaStatusIconCountBinding> {
|
||||
title = "设置最多显示的图标个数"
|
||||
val editText = bind<DiaStatusIconCountBinding>().diaStatusIconCountInputEdit.apply {
|
||||
binding.iconCountEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
setText(statusBarIconCount.toString())
|
||||
@@ -272,12 +273,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
}
|
||||
confirmButton {
|
||||
when {
|
||||
(runCatching { editText.text.toString().toInt() }.getOrNull() ?: -1)
|
||||
(runCatching { binding.iconCountEdit.text.toString().toInt() }.getOrNull() ?: -1)
|
||||
!in 0..100 -> snake(msg = "请输入有效数值")
|
||||
editText.text.toString().isNotBlank() -> runCatching {
|
||||
statusBarIconCount = editText.text.toString().trim().toInt()
|
||||
binding.iconCountEdit.text.toString().isNotBlank() -> runCatching {
|
||||
statusBarIconCount = binding.iconCountEdit.text.toString().trim().toInt()
|
||||
modulePrefs.put(DataConst.HOOK_STATUS_ICON_COUNT, statusBarIconCount)
|
||||
binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
this@MainActivity.binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
SystemUITool.showNeedRestartSnake(context)
|
||||
}.onFailure { snake(msg = "数值格式无效") }
|
||||
else -> snake(msg = "请输入有效数值")
|
||||
@@ -299,7 +300,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
|
||||
confirmButton(text = "保存设置") {
|
||||
notifyIconAutoSyncTime = it
|
||||
binding.notifyIconAutoSyncText.text = it
|
||||
this@MainActivity.binding.notifyIconAutoSyncText.text = it
|
||||
modulePrefs.put(DataConst.NOTIFY_ICON_FIX_AUTO_TIME, it)
|
||||
SystemUITool.refreshSystemUI(context, isRefreshCacheOnly = true)
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ package com.fankes.miui.notify.ui.activity.base
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
|
||||
@@ -61,7 +61,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
/** 隐藏系统的标题栏 */
|
||||
supportActionBar?.hide()
|
||||
/** 初始化沉浸状态栏 */
|
||||
ViewCompat.getWindowInsetsController(window.decorView)?.apply {
|
||||
WindowCompat.getInsetsController(window, window.decorView).apply {
|
||||
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
||||
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
*
|
||||
* 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
|
||||
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -43,14 +43,6 @@ import com.highcapable.yukihookapi.annotation.CauseProblemsApi
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
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
|
||||
@@ -59,20 +51,45 @@ fun Context.showDialog(isUseBlackTheme: Boolean = false, initiate: DialogBuilder
|
||||
fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) =
|
||||
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 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 instanceAndroid: android.app.AlertDialog.Builder? = 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 风格对话框
|
||||
@@ -83,12 +100,7 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
|
||||
init {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) }
|
||||
else runInSafe {
|
||||
instanceAndroid = android.app.AlertDialog.Builder(
|
||||
context,
|
||||
if (isUseBlackTheme) android.R.style.Theme_Material_Dialog else android.R.style.Theme_Material_Light_Dialog
|
||||
)
|
||||
}
|
||||
else runInSafe { instanceAndroid = android.app.AlertDialog.Builder(context, 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
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框自定义布局
|
||||
* @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 按钮文本内容
|
||||
@@ -184,7 +184,10 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
|
||||
fun cancel() = dialogInstance?.cancel()
|
||||
|
||||
/** 显示对话框 */
|
||||
internal fun show() =
|
||||
@CauseProblemsApi
|
||||
fun show() {
|
||||
/** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */
|
||||
if (bindingClass != null) binding
|
||||
if (isUsingAndroidX) runInSafe {
|
||||
instanceAndroidX?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
@@ -196,8 +199,7 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
|
||||
window?.setBackgroundDrawable(
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
if (isUseBlackTheme) intArrayOf(0xFF2D2D2D.toInt(), 0xFF2D2D2D.toInt())
|
||||
else intArrayOf(Color.WHITE, Color.WHITE)
|
||||
intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
@@ -206,4 +208,5 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
|
||||
dialogInstance = this
|
||||
}?.show()
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,11 +24,15 @@ package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Activity
|
||||
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 okhttp3.*
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 获取 Github Release 最新版本工具类
|
||||
@@ -57,12 +61,12 @@ object GithubReleaseTool {
|
||||
override fun onFailure(call: Call, e: IOException) {}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) = runInSafe {
|
||||
JSONObject(response.body?.string() ?: "").apply {
|
||||
JSONObject(response.body.string()).apply {
|
||||
GithubReleaseBean(
|
||||
name = getString("name"),
|
||||
htmlUrl = getString("html_url"),
|
||||
content = getString("body"),
|
||||
date = getString("published_at").replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "")
|
||||
date = getString("published_at").localTime()
|
||||
).apply {
|
||||
fun showUpdate() = context.showDialog {
|
||||
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
|
||||
* @param name 版本名称
|
||||
|
@@ -78,40 +78,32 @@ object IconRuleManagerTool {
|
||||
* @param callback 成功后回调
|
||||
*/
|
||||
fun syncByHand(context: Context, callback: () -> Unit) =
|
||||
context.showDialog {
|
||||
context.showDialog<DiaSourceFromBinding> {
|
||||
title = "同步列表"
|
||||
var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY)
|
||||
var customUrl = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL)
|
||||
bind<DiaSourceFromBinding>().apply {
|
||||
diaSfText.apply {
|
||||
if (customUrl.isNotBlank()) {
|
||||
setText(customUrl)
|
||||
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
|
||||
binding.sourceUrlEdit.apply {
|
||||
if (customUrl.isNotBlank()) {
|
||||
setText(customUrl)
|
||||
setSelection(customUrl.length)
|
||||
}
|
||||
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 {
|
||||
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType)
|
||||
@@ -120,15 +112,15 @@ object IconRuleManagerTool {
|
||||
}
|
||||
cancelButton()
|
||||
neutralButton(text = "自定义规则") {
|
||||
context.showDialog {
|
||||
context.showDialog<DiaSourceFromStringBinding> {
|
||||
title = "自定义规则(调试)"
|
||||
val editText = bind<DiaSourceFromStringBinding>().diaSfsInputEdit.apply {
|
||||
binding.jsonRuleEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
}
|
||||
IconPackParams(context).also { params ->
|
||||
confirmButton(text = "合并") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
binding.jsonRuleEdit.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
@@ -146,7 +138,7 @@ object IconRuleManagerTool {
|
||||
}
|
||||
}
|
||||
cancelButton(text = "覆盖") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
binding.jsonRuleEdit.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
@@ -351,7 +343,7 @@ object IconRuleManagerTool {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
@@ -23,6 +23,7 @@
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
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.showDialog
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
@@ -35,7 +36,7 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
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)
|
||||
|
||||
/**
|
||||
* 显示推广对话框
|
||||
|
@@ -316,7 +316,7 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此选项默认开启,MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。"
|
||||
android:text="此选项默认开启,MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。\n请注意:可能无法兼容中置挖孔屏的设备。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@@ -885,7 +885,7 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
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:textSize="12sp" />
|
||||
|
||||
|
@@ -14,7 +14,7 @@
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -19,32 +20,40 @@
|
||||
android:text="在线规则将不定期更新,建议定期同步列表以适配更多 APP,若无法同步请自行寻找解决方法或魔法上网。"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从 FastGit 获取" />
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从 Github Raw 获取" />
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/source_radio_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从 FastGit 获取"
|
||||
app:buttonTint="@color/colorPrimaryAccent" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从自定义地址获取" />
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/source_radio_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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
|
||||
android:id="@+id/dia_sf_text_lin"
|
||||
android:id="@+id/source_from_text_lin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<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_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
|
@@ -25,7 +25,7 @@
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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_height="150dp"
|
||||
android:ellipsize="end"
|
||||
|
@@ -14,7 +14,7 @@
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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_height="wrap_content"
|
||||
android:digits="0123456789"
|
||||
|
@@ -2,15 +2,16 @@
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_200</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<item name="colorPrimary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnPrimary">@color/colorPrimaryAccent</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="colorSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/colorPrimaryAccent</item>
|
||||
<!-- 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. -->
|
||||
</style>
|
||||
</resources>
|
@@ -1,10 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#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="colorPrimaryAccent">#656565</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="trans">#00000000</color>
|
||||
|
@@ -2,15 +2,16 @@
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/teal_700</item>
|
||||
<item name="colorPrimary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnPrimary">@color/colorPrimaryAccent</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="colorSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/colorPrimaryAccent</item>
|
||||
<!-- 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. -->
|
||||
</style>
|
||||
</resources>
|
10
build.gradle
10
build.gradle
@@ -1,12 +1,12 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '7.2.0' apply false
|
||||
id 'com.android.library' version '7.2.0' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
|
||||
id 'com.android.application' version '7.2.1' apply false
|
||||
id 'com.android.library' version '7.2.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
appVersionName = "2.7"
|
||||
appVersionCode = 32
|
||||
appVersionName = "2.8"
|
||||
appVersionCode = 34
|
||||
enableR8 = true
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# 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.
|
||||
# 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
|
||||
@@ -18,4 +18,6 @@ android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
kotlin.code.style=official
|
||||
# Incremental
|
||||
kotlin.incremental.useClasspathSnapshot=true
|
Reference in New Issue
Block a user