mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-04 09:45:44 +08:00
Compare commits
248 Commits
Author | SHA1 | Date | |
---|---|---|---|
3e29a70969
|
|||
3015eade97
|
|||
c172e1e229
|
|||
25b7853313
|
|||
08e38c6770
|
|||
|
058c4534f7 | ||
1551013414
|
|||
8a775b3fdd
|
|||
c5ed4f720f
|
|||
914e44942a
|
|||
1b44e232ea
|
|||
7eb69e45f0
|
|||
487e249f33
|
|||
bbc14beb2e
|
|||
8a24cf3a4a
|
|||
139fafc758
|
|||
19e93cb15d
|
|||
739816c31a
|
|||
a7d457eb67
|
|||
|
76f113de78 | ||
aec000e252
|
|||
d308111476
|
|||
c8f1099326
|
|||
|
350e54fac7 | ||
|
4f1d74d5ff | ||
f00f6efcf3
|
|||
8b6d35fa01
|
|||
|
0c43bc5b97 | ||
|
a134385d26 | ||
|
6d62c02b42 | ||
4dcb05797c
|
|||
7598da4d65
|
|||
992db5c4cf
|
|||
|
3cc2787a88 | ||
b476c19035
|
|||
|
cb4bf479ba | ||
cd38dbf579
|
|||
259eb1dbd4
|
|||
4d2160ce8a
|
|||
bcf3a17e21
|
|||
e7763baa22
|
|||
e47754b870
|
|||
|
e9e27b1d5a | ||
b10ff658ab
|
|||
94f3fd12cd
|
|||
7678ea7612
|
|||
|
d1a7d140a3 | ||
01f5c902e9
|
|||
|
a601739679 | ||
|
a2bf9d24eb | ||
5a1672c0a4
|
|||
a506681431
|
|||
abd1189e75
|
|||
ad0a538f13
|
|||
46abe6a6c1
|
|||
b855113e4d
|
|||
c9411e5aa0
|
|||
8729979c33
|
|||
28d3d7fd86
|
|||
|
d2f8ef69c6 | ||
c5b5fcfe35
|
|||
219dd8b9e3
|
|||
ad8fb50183
|
|||
ba74c7c9d4
|
|||
f398f2bcc3
|
|||
0377bb7062
|
|||
099133c6d6
|
|||
7925629ef7
|
|||
c42fad05c6
|
|||
44483f1bd2
|
|||
1e4bf54b80
|
|||
3fe8dca9e9
|
|||
b101210ed1
|
|||
2a3398990b
|
|||
86d325ac31
|
|||
c74718572d
|
|||
d1dc64108a
|
|||
386d3c254b
|
|||
f2118bdc79
|
|||
5651618506
|
|||
91f3a3418b
|
|||
61849cebe0
|
|||
1f71fbda9a
|
|||
8f01e649fe
|
|||
ae15d72923
|
|||
3b82c33c2e
|
|||
621f973a2f
|
|||
ef2c8afe3f
|
|||
3d7e4d8825
|
|||
19b2efbb83
|
|||
d330510788
|
|||
25a23d7e1a
|
|||
db4b418ed4
|
|||
8a97e38d20
|
|||
|
f294120fa8 | ||
|
d244658aa6 | ||
|
445ac85d8d | ||
|
e3b22671c1 | ||
d574449e4a
|
|||
85a2e730e0
|
|||
ca367bde9e
|
|||
03ce7fbbe6
|
|||
88e3f79878
|
|||
ba67bd0a62
|
|||
0c0cf9bfba
|
|||
0e98ec16c7
|
|||
f1fd3f2679
|
|||
97065494b0
|
|||
b172d7a090
|
|||
b86988a310
|
|||
32f8ca9d63
|
|||
3cf67eb7fc
|
|||
9f39f297f9
|
|||
7feab98a1e
|
|||
b297b43dfb
|
|||
c7c03e891f
|
|||
5ddc5de475
|
|||
d09c11f026
|
|||
bf22cae957
|
|||
a08e085b2b
|
|||
9690e27511
|
|||
f9dde5f549
|
|||
8ddb938883
|
|||
8664d7b285
|
|||
d70d01cf6c
|
|||
4703d339b7
|
|||
76b1cc2f0b
|
|||
62ec1d16ae
|
|||
7db010c9a1
|
|||
e6fa34d7fd
|
|||
d4661abb71
|
|||
744d028160
|
|||
3f3a92f192
|
|||
49f18ef8c3
|
|||
73173cd7ab
|
|||
c181530ad7
|
|||
883325dc2f
|
|||
6fe1f0572c
|
|||
be8f558bf5
|
|||
175263c9aa
|
|||
f95fe45ce3
|
|||
42b0fa69b7
|
|||
d0a9554a28
|
|||
c500bdad43
|
|||
9bded26604
|
|||
c687c755f2
|
|||
b9e1d1abe7
|
|||
27cfcbada6
|
|||
f0c6dabf76
|
|||
208862bf62
|
|||
ee948f5327
|
|||
d62d0f99a2
|
|||
0e2b6c3df3
|
|||
b0c1f2bb8f
|
|||
53a7381824
|
|||
fb5f63f248
|
|||
49fa06a64d
|
|||
b17e39e27c
|
|||
3abe4d7800
|
|||
a5586c8505
|
|||
2325f0ea86
|
|||
63e4dd8299
|
|||
4c8b1b0d53
|
|||
881f4a46e5
|
|||
2de7455259
|
|||
d93492be80
|
|||
a7cdda61e9
|
|||
9fda7a975c
|
|||
a1819c6e1d
|
|||
fcd5a59047
|
|||
7e4c20ca05
|
|||
69f3637d22
|
|||
630b803fa4
|
|||
b2bb05c4e7
|
|||
d53c455dd2
|
|||
e0b5b462f9
|
|||
aa10d5491e
|
|||
098f6aaa3d
|
|||
69d66e8982
|
|||
629c402c44
|
|||
4707685cc2
|
|||
fc9d2a0d21
|
|||
d8e549b360
|
|||
741157336c
|
|||
596c4363d0
|
|||
1ffee75977
|
|||
2ff2f735a0
|
|||
74743e8d1e
|
|||
2982db6cc9
|
|||
68ccd4dafa
|
|||
e47359dfe9
|
|||
2289e3a5bf
|
|||
ee0c6a06ae
|
|||
d508dcd1e3
|
|||
241d2e9248
|
|||
0f10fb077f
|
|||
1ca26a76ef
|
|||
22a1fd63e7
|
|||
84ae130bc4
|
|||
6e4999da76
|
|||
54851231eb
|
|||
d5f366a82d
|
|||
b7ee52c65b
|
|||
c39343ba17
|
|||
4f54598ae2
|
|||
33b3cf6abc
|
|||
210c6898ab
|
|||
ec3f07791b
|
|||
0e435cf0e1
|
|||
ce29f65ce8
|
|||
baea7847c8
|
|||
1dd5a899f2
|
|||
3293b0f412
|
|||
7f0a951996
|
|||
50b32f6357
|
|||
1963537c09
|
|||
0a0c3ff28c
|
|||
de25660879
|
|||
3b174899bc
|
|||
d74f5c4654
|
|||
2f49c2bc6b
|
|||
4d4073b200
|
|||
a4081f27d5
|
|||
8499953588
|
|||
207279ff23
|
|||
29646fb127
|
|||
f3f157ea94
|
|||
41136687dd
|
|||
223a185358
|
|||
7c3d3d1bda
|
|||
7a35833bb6
|
|||
e2b274745d
|
|||
edc462e161
|
|||
5888d139b3
|
|||
|
790031dd4e | ||
|
d6cf855277 | ||
|
5a7ba08a27 | ||
|
244a5d2ec6 | ||
|
c7ce4d33bc | ||
2b9433df03
|
|||
f995d2a628
|
|||
0395e5a6de
|
|||
adbc126825
|
|||
1259a35747
|
|||
39fa9c38a8
|
|||
788d4605eb
|
|||
b986c2df18
|
|||
5c088ac243
|
33
.editorconfig
Normal file
33
.editorconfig
Normal file
@@ -0,0 +1,33 @@
|
||||
# noinspection EditorConfigKeyCorrectness
|
||||
[{*.kt,*.kts}]
|
||||
ktlint_standard_annotation = disabled
|
||||
ktlint_standard_filename = disabled
|
||||
ktlint_standard_wrapping = disabled
|
||||
ktlint_standard_import-ordering = enabled
|
||||
ktlint_standard_max-line-length = disabled
|
||||
ktlint_standard_multiline-if-else = disabled
|
||||
ktlint_standard_argument-list-wrapping = disabled
|
||||
ktlint_standard_parameter-list-wrapping = disabled
|
||||
ktlint_standard_trailing-comma-on-declaration-site = disabled
|
||||
ktlint_function_signature_body_expression_wrapping = multiline
|
||||
ktlint_standard_string-template-indent = disabled
|
||||
ktlint_standard_function-signature = disabled
|
||||
ktlint_standard_trailing-comma-on-call-site = disabled
|
||||
ktlint_standard_multiline-expression-wrapping = disabled
|
||||
ktlint_standard_no-empty-first-line-in-class-body = disabled
|
||||
ktlint_standard_if-else-wrapping = disabled
|
||||
ktlint_standard_if-else-bracing = disabled
|
||||
ktlint_standard_statement-wrapping = disabled
|
||||
ktlint_standard_blank-line-before-declaration = disabled
|
||||
ktlint_standard_no-empty-file = disabled
|
||||
ktlint_standard_property-naming = disabled
|
||||
ktlint_standard_function-naming = disabled
|
||||
ktlint_standard_chain-method-continuation = disabled
|
||||
ktlint_standard_class-signature = disabled
|
||||
ktlint_standard_condition-wrapping = disabled
|
||||
ktlint_standard_class-signature = disabled
|
||||
ij_continuation_indent_size = 2
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 150
|
29
.github/ISSUE_TEMPLATE/----------.md
vendored
29
.github/ISSUE_TEMPLATE/----------.md
vendored
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: 通知图标优化适配反馈
|
||||
about: 提交通知图标优化适配必须使用此模板提交
|
||||
title: "[通知图标优化适配反馈]"
|
||||
labels: To be adapted
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**需要适配的 APP 名称/包名/通知图标颜色 (必填)**
|
||||
|
||||
* (示例:小米音乐/com.miui.player/#fff16033)
|
||||
|
||||
*
|
||||
|
||||
**提供相关 APP 的下载渠道截图以及简要说明用途 (必填)**
|
||||
|
||||
*
|
||||
|
||||
**提供相关 APP 的通知单色图标适配素材 大小 50x50 (选填)**
|
||||
|
||||
* (可填写资源下载地址或直接添加附件提交,不接受百度网盘、天翼云盘以及各种快传、私有云盘)
|
||||
|
||||
* (若直接在附件提交这里可不填)
|
||||
|
||||
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
||||
<!--- 请保留模板原始标题 --->
|
||||
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
||||
<!--- Create by Template --->
|
54
.github/ISSUE_TEMPLATE/----bug---.md
vendored
54
.github/ISSUE_TEMPLATE/----bug---.md
vendored
@@ -1,54 +0,0 @@
|
||||
---
|
||||
name: 问题与 BUG 反馈
|
||||
about: 问题反馈必须使用此模板进行提交
|
||||
title: "[问题与 BUG 反馈] *简要描述问题原因*"
|
||||
labels: bug
|
||||
assignees: fankes
|
||||
|
||||
---
|
||||
|
||||
**MIUI 版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**MIUI 版本类型(请保留一个)**
|
||||
|
||||
* 公测版/内测版/稳定版
|
||||
|
||||
**Android 版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**模块版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**使用的 Xposed 框架名称与框架版本(必填)**
|
||||
|
||||
* (例如:LSPosed Zygisk/Riru 版本号)
|
||||
|
||||
**同时使用的带有系统界面作用域的 Xposed 模块(选填)**
|
||||
|
||||
* (没有可空)
|
||||
|
||||
**问题的具体描述**
|
||||
|
||||
* (复现步骤、前提以及详细截图和录屏演示)
|
||||
|
||||
|
||||
**提供模块问题 Log 或必要 Log**
|
||||
|
||||
* (LSPosed 可在日志管理中查看并筛选包含 `MIUINativeNotifyIcon` 的日志)
|
||||
|
||||
<details><summary>展开查看</summary><pre><code>
|
||||
|
||||
(此处粘贴问题Log)
|
||||
|
||||
</code></pre></details>
|
||||
|
||||
<!--- 注意:只接受 MIUI 正规官方版本系统,如果你正在使用 MIUI 官改(第三方改版)请不要提交任何 BUG 与问题,开发者无义务解决 --->
|
||||
|
||||
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
||||
<!--- 请保留模板原始标题 --->
|
||||
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
||||
<!--- Create by Template --->
|
97
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
97
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
name: 问题与 BUG 反馈
|
||||
description: 问题反馈必须使用此模板进行提交
|
||||
labels: [ bug ]
|
||||
title: "[问题与 BUG 反馈] (在这里简要描述问题原因)"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### 请在下方填写问题发生的具体原因和复现步骤。
|
||||
|
||||
我们只接受 MIUI 或 HyperOS 正规官方版本系统,如果你正在使用官改 (第三方修改版) 请不要提交任何 BUG 与问题,我们无义务去解决,请自求多福。
|
||||
|
||||
发生异常、崩溃、闪退或功能性问题,必须提交问题 Log (日志),没有 Log 的 issues 将直接被关闭。
|
||||
- type: input
|
||||
attributes:
|
||||
label: 模块版本
|
||||
description: 请填写当前使用的模块完整版本号,例如:**2.0**
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 系统版本
|
||||
description: |
|
||||
这里填写当前的系统,例如:**MIUI 13.0.1** 或 **HyperOS 1.0**
|
||||
开发版需要标注具体的版本号,例如:**MIUI 13 22.9.27** 或 **HyperOS 1.0 22.9.27**
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: 系统版本类型
|
||||
description: 请选择你使用的系统版本类型。
|
||||
options:
|
||||
- 稳定版
|
||||
- 稳定内测版
|
||||
- 开发版
|
||||
- 开发内测版
|
||||
- 开发公测版 DEV
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Android 版本
|
||||
options:
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12L/12.1
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8.1
|
||||
- 8.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Xposed 框架名称与版本号
|
||||
description: 请填写当前使用的 Xposed 框架,例如:**LSPosed 1.8.4(次版本号)**
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 与系统界面(系统 UI)同作用域的 Xposed 模块
|
||||
description: |
|
||||
此模块的作用域为系统界面(系统 UI),为确保非其它模块冲突造成的问题,请一定要填写当前你同时激活的相关模块。
|
||||
若没有,请直接在下方填写“无”。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 详细描述问题发生的具体原因
|
||||
description: 请在下方详细描述问题发生的具体场景、复现步骤和经过,以便我们能够按照你所描述的步骤复现这个问题。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 提供模块问题 Log 或必要 Log
|
||||
description: LSPosed 可在日志管理中查看并筛选包含 `MIUINativeNotifyIcon` 的日志。
|
||||
value: |
|
||||
<details><summary>展开查看</summary><pre><code>
|
||||
|
||||
(此处粘贴问题 Log)
|
||||
|
||||
</code></pre></details>
|
||||
<!-- 提交时请将括号内容包括括号全部删除,粘贴你复制的日志,不要破坏代码格式 -->
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 确认一下你提交的信息
|
||||
description: |
|
||||
为了确保 issues 的质量和避免浪费不必要的时间,未勾选下方选项的 issues 将直接被关闭。
|
||||
请一定确保你已经**勾选下方的选项**后再提交。
|
||||
options:
|
||||
- label: 我确保上述信息准确无误
|
||||
required: false
|
71
.github/ISSUE_TEMPLATE/request_notify_icon_adaption.yml
vendored
Normal file
71
.github/ISSUE_TEMPLATE/request_notify_icon_adaption.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: 通知图标优化适配反馈
|
||||
description: 提交通知图标优化适配必须使用此模板提交
|
||||
labels: [To be adapted]
|
||||
title: "[通知图标优化适配反馈]"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### 请在下方填写你需要适配的 APP 通知图标的必要信息。
|
||||
|
||||
**China and Chinese only.**
|
||||
**仅限中国和中文。**
|
||||
|
||||
以下类型的 APP 不予适配:
|
||||
|
||||
- VPN、翻墙软件
|
||||
- 涉嫌色情、赌博类软件
|
||||
- 申请超限权限、涉嫌泄露国家机密行为的软件
|
||||
|
||||
以下类型的 APP 通知图标暂不适配:
|
||||
|
||||
- 多态彩色图标,状态不唯一,例如 360 极速浏览器
|
||||
- 规范的原生图标,但未被通知图标规则适配的 (将稍后加入白名单)
|
||||
- type: input
|
||||
attributes:
|
||||
label: APP 名称
|
||||
description: 这里填写 APP 的名称,例如:**微信**
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: APP 包名
|
||||
description: 这里填写 APP 的包名,例如:**com.tencent.mm**
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 通知图标颜色 (HEX)
|
||||
description: |
|
||||
这里填写通知图标在下拉通知栏中的图标颜色,要求为 16 进制,例如:**#ff232323**
|
||||
如果不知道什么是 16 进制颜色,可以参考 [这里](https://www.qtccolor.com/tool/hex.aspx) 的取色。
|
||||
留空代表使用系统默认主题色。
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: 下载渠道、来源地址链接
|
||||
description: 请填写我们应该从何处得到你需要适配的这个 APP 的下载链接。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 简单描述适配的通知图标使用场景
|
||||
description: 简单描述一下当前 APP 的通知图标在何时会变成彩色的、不规范的以及可触发推送通知的操作,例如小米推送或 HMS 推送。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 通知单色图标适配素材 (大小 50x50~72x72)
|
||||
description: 请在这里填写我们能够获得这个图标的网址或在下方的文本框粘贴你需要上传的图标。
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 确认一下你提交的信息
|
||||
description: |
|
||||
为了确保 issues 的质量和避免浪费不必要的时间,未勾选下方选项的 issues 将直接被关闭。
|
||||
请一定确保你已经**勾选下方的选项**后再提交。
|
||||
options:
|
||||
- label: 我确保上述信息准确无误
|
||||
required: false
|
88
.github/workflows/commit_ci.yml
vendored
Normal file
88
.github/workflows/commit_ci.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: Automatic Build on Commit
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.txt'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build CI
|
||||
if: ${{ success() }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APK_OUTPUT_PATH: 'app/build/outputs/apk'
|
||||
TG_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||||
TG_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||||
COMMIT_MESSAGE: |+
|
||||
New push to GitHub\!
|
||||
```
|
||||
${{ github.event.head_commit.message }}
|
||||
```by `${{ github.event.head_commit.author.name }}`
|
||||
See commit detail [here](${{ github.event.head_commit.url }})
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare GitHub Env
|
||||
run: |
|
||||
GITHUB_SHA=${{ github.sha }}
|
||||
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
|
||||
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1
|
||||
with:
|
||||
cmake-version: '3.22.1'
|
||||
- name: Prepare Java 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
java-package: jdk
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
- name: Cache Gradle Dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
|
||||
restore-keys: |
|
||||
gradle-deps
|
||||
- name: Cache Gradle Build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: gradle-builds-core-${{ github.sha }}
|
||||
restore-keys: |
|
||||
gradle-builds
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
./gradlew :app:assembleDebug
|
||||
./gradlew :app:assembleRelease
|
||||
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
|
||||
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
|
||||
- name: Upload Artifacts (Debug)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ env.DEBUG_APK_PATH }}
|
||||
name: MIUINativeNotifyIcon-debug-${{ github.event.head_commit.id }}
|
||||
- name: Upload Artifacts (Release)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ env.RELEASE_APK_PATH }}
|
||||
name: MIUINativeNotifyIcon-release-${{ github.event.head_commit.id }}
|
||||
- name: Post Artifacts to Telegram
|
||||
run: |
|
||||
export debug=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name "*.apk")
|
||||
export release=$(find ${{ env.APK_OUTPUT_PATH }}/release -name "*.apk")
|
||||
ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); print(urllib.parse.quote(msg if len(msg) <= 1024 else json.dumps(os.environ["COMMIT_URL"])))'`
|
||||
curl -v "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMediaGroup?chat_id=${TG_CHAT_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fdebug%22%7D%2C%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Frelease%22%2C%22parse_mode%22%3A%22MarkdownV2%22%2C%22caption%22:${ESCAPED}%7D%5D" \
|
||||
-F debug="@$debug" \
|
||||
-F release="@$release"
|
70
.github/workflows/pull_request_ci.yml
vendored
Normal file
70
.github/workflows/pull_request_ci.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Pull Request Checker
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.txt'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Pull Request Check
|
||||
if: ${{ success() }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APK_OUTPUT_PATH: 'app/build/outputs/apk'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare GitHub Env
|
||||
run: |
|
||||
GITHUB_SHA=${{ github.sha }}
|
||||
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
|
||||
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1
|
||||
with:
|
||||
cmake-version: '3.22.1'
|
||||
- name: Prepare Java 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
java-package: jdk
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
- name: Cache Gradle Dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
|
||||
restore-keys: |
|
||||
gradle-deps
|
||||
- name: Cache Gradle Build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: gradle-builds-core-${{ github.sha }}
|
||||
restore-keys: |
|
||||
gradle-builds
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
./gradlew :app:assembleDebug
|
||||
./gradlew :app:assembleRelease
|
||||
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
|
||||
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
|
||||
- name: Upload Artifacts (Debug)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ env.DEBUG_APK_PATH }}
|
||||
name: MIUINativeNotifyIcon-debug-${{ github.event.head_commit.id }}
|
||||
- name: Upload Artifacts (Release)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ env.RELEASE_APK_PATH }}
|
||||
name: MIUINativeNotifyIcon-release-${{ github.event.head_commit.id }}
|
117
.gitignore
vendored
117
.gitignore
vendored
@@ -1,15 +1,110 @@
|
||||
## Fully .gtignore for IntelliJ, Android Studio and Gradle based Java projects
|
||||
## References:
|
||||
## - https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
## - https://github.com/android/platform-samples/blob/main/.gitignore
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
.idea/.name
|
||||
.idea/artifacts
|
||||
.idea/compiler.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/modules.xml
|
||||
.idea/*.iml
|
||||
.idea/modules
|
||||
.idea/caches
|
||||
.idea/material_theme**
|
||||
.idea/other.xml
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
*.ipr
|
||||
|
||||
# Kotlin
|
||||
.kotlin
|
||||
|
||||
# Misc
|
||||
.idea/misc.xml
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Android studio 3.1+ additional
|
||||
.idea/deployment*.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/androidTestResultsUserPreferences.xml
|
||||
|
||||
# Android projects
|
||||
**/local.properties
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
|
||||
# Gradle projects
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Mkdocs temporary serving folder
|
||||
docs-gen
|
||||
site
|
||||
*.bak
|
||||
.idea/appInsightsSettings.xml
|
||||
|
||||
# Mac OS
|
||||
.DS_Store
|
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
MIUINativeNotifyIcon
|
6
.idea/AndroidProjectSystem.xml
generated
Normal file
6
.idea/AndroidProjectSystem.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AndroidProjectSystem">
|
||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
||||
</component>
|
||||
</project>
|
6
.idea/compiler.xml
generated
6
.idea/compiler.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
20
.idea/gradle.xml
generated
20
.idea/gradle.xml
generated
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="11" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
BIN
.idea/icon.png
generated
Normal file
BIN
.idea/icon.png
generated
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,10 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="CheckImageSize" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="YAMLSchemaValidation" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
40
.idea/jarRepositories.xml
generated
40
.idea/jarRepositories.xml
generated
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven3" />
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="https://www.jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/jcenter" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="2.1.10" />
|
||||
</component>
|
||||
</project>
|
10
.idea/ktlint-plugin.xml
generated
Normal file
10
.idea/ktlint-plugin.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KtLint plugin">
|
||||
<ktlintMode>MANUAL</ktlintMode>
|
||||
<formatOnSave>false</formatOnSave>
|
||||
</component>
|
||||
<component name="com.nbadal.ktlint.KtlintProjectSettings">
|
||||
<ktlintMode>MANUAL</ktlintMode>
|
||||
</component>
|
||||
</project>
|
6
.idea/ktlint.xml
generated
Normal file
6
.idea/ktlint.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KtlintProjectConfiguration">
|
||||
<treatAsErrors>false</treatAsErrors>
|
||||
</component>
|
||||
</project>
|
10
.idea/migrations.xml
generated
Normal file
10
.idea/migrations.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectMigrations">
|
||||
<option name="MigrateToGradleLocalJavaHome">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
43
.idea/misc.xml
generated
43
.idea/misc.xml
generated
@@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="app/src/main/res/drawable-night/dark_round.xml" value="0.256" />
|
||||
<entry key="app/src/main/res/drawable-night/permotion_round.xml" value="0.256" />
|
||||
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.44871794871794873" />
|
||||
<entry key="app/src/main/res/drawable/bg_dark_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_dialog_background.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" />
|
||||
<entry key="app/src/main/res/drawable/bg_orange_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_warn_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" />
|
||||
<entry key="app/src/main/res/drawable/ic_nf_icon_refresh.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_nf_icon_update.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_notify_icon.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_system_clock.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" />
|
||||
<entry key="app/src/main/res/drawable/white_round.xml" value="0.256" />
|
||||
<entry key="app/src/main/res/layout-w1240dp/dia_source_from.xml" value="0.36484375" />
|
||||
<entry key="app/src/main/res/layout-w1240dp/dia_source_from_string.xml" value="0.36484375" />
|
||||
<entry key="app/src/main/res/layout-w936dp/dia_status_icon_cout.xml" value="0.935546875" />
|
||||
<entry key="app/src/main/res/layout/activity_config.xml" value="0.42168674698795183" />
|
||||
<entry key="app/src/main/res/layout/activity_login.xml" value="0.4375" />
|
||||
<entry key="app/src/main/res/layout/activity_main.xml" value="0.30387540746106484" />
|
||||
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.375" />
|
||||
<entry key="app/src/main/res/layout/dia_icon_filter.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_icon_search.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_source_from.xml" value="0.3591278324070115" />
|
||||
<entry key="app/src/main/res/layout/dia_source_from_string.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_status_icon_count.xml" value="0.45" />
|
||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
17
.idea/runConfigurations.xml
generated
Normal file
17
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
74
EXPLORE_HISTORY.md
Normal file
74
EXPLORE_HISTORY.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# 历史背景
|
||||
|
||||
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。
|
||||
|
||||
这当然不是系统的错,而是国内 APP 和 `MIPUSH` 的通知极其不规范的通知图标设计。
|
||||
|
||||
但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 `2021-5-18` 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。
|
||||
|
||||
对于 Android 开发者来说,官方文档中的 `setSmallIcon` 不再适用于魔改后的 MIUI,这将会严重破坏非常多的状态图标。
|
||||
|
||||
当然,国内的手机生态除了 `MIPUSH` 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。
|
||||
|
||||
但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 MIUI 修复了黑白块图标的问题。
|
||||
|
||||
补充:现在这个 [开发文档](https://dev.mi.com/distribute/doc/details?pId=1582) 竟然还在,那就放在这里鞭个尸吧。
|
||||
|
||||
## 效果展示
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/style.png?raw=true" alt="Screenshot"/>
|
||||
|
||||
## 探索历程
|
||||
|
||||
原生 Android 的小图标和通知图标具有状态性。
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native.jpg?raw=true" height = "35" alt="Screenshot"/>
|
||||
|
||||
而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么。
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui.jpg?raw=true" height = "40" alt="Screenshot"/>
|
||||
|
||||
同样地,通知面板的图标同样遵守这一状态性。
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native_n_1.jpg?raw=true" height = "100" alt="Screenshot"/>
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native_n_2.jpg?raw=true" height = "100" alt="Screenshot"/>
|
||||
|
||||
而 MIUI 做了什么呢?
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui_n_1.jpg?raw=true" height = "100" alt="Screenshot"/>
|
||||
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui_n_2.jpg?raw=true" height = "100" alt="Screenshot"/>
|
||||
|
||||
不曾记得是什么版本开始,MIUI 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。
|
||||
|
||||
由于目前大量通知图标都来自 `MIPUSH` 发出的营销通知,而 `MIPUSH` 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下,MIUI
|
||||
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
|
||||
|
||||
真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类。
|
||||
|
||||
```kotlin
|
||||
com.android.internal.util.ContrastColorUtil
|
||||
```
|
||||
|
||||
这个类中有一个方法可以拿出来判断图标的灰度效果。
|
||||
|
||||
```kotlin
|
||||
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable)
|
||||
```
|
||||
|
||||
问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角......
|
||||
|
||||
最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
|
||||
|
||||
后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
|
||||
|
||||
——来自一个无可奈何的 MIUI 老用户
|
||||
|
||||
## 后记
|
||||
|
||||
近期重新适配了 MIUI 11、12、12.5、13、14 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了。
|
||||
|
||||
特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好。
|
||||
|
||||
MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
|
142
README.md
142
README.md
@@ -1,40 +1,49 @@
|
||||
# MIUI 原生通知图标
|
||||
|
||||
[](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/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
|
||||
[](https://t.me/XiaofangInternet)
|
||||
<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
||||
<br/>
|
||||
Fix the native notification bar icon function abandoned by the MIUI development team.<br/>
|
||||
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 12、12.5、13 以及最新版本。
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/actions/workflows/commit_ci.yml)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||

|
||||

|
||||
|
||||
## Developer
|
||||
[](https://t.me/MIUINativeNotifyIcon_CI)
|
||||
[](https://t.me/XiaofangInternet)
|
||||
[](https://qm.qq.com/cgi-bin/qm/qr?k=dp2h5YhWiga9WWb_Oh7kSHmx01X8I8ii&jump_from=webapi&authKey=Za5CaFP0lk7+Zgsk2KpoBD7sSaYbeXbsDgFjiWelOeH4VSionpxFJ7V0qQBSqvFM)
|
||||
[](https://pd.qq.com/s/44gcy28h)
|
||||
|
||||
[酷安 @星夜不荟](http://www.coolapk.com/u/876977)
|
||||
<img src="img-src/icon.png" width = "100" height = "100" alt="LOGO"/>
|
||||
|
||||
Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
|
||||
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 11~14 以及 HyperOS 1.0。
|
||||
|
||||
## For Non-Chinese Users
|
||||
|
||||
This project will not be adapted i18n, please stay tuned for my new projects in the future.
|
||||
|
||||
## 项目迁移公告
|
||||
|
||||
由于本人同时维护 **MIUI** 与 **ColorOS** 两个系统需要同时维护两个模块,十分不方便,所以我决定在后期逐渐合并两个项目并解耦合为一个新项目并计划适配更多系统与设备,例如原生与类原生系统。
|
||||
|
||||
在新的项目确定后,会在这里添加新项目的链接,届时我会终止维护这个项目并建议大家转移到新项目。
|
||||
|
||||
## 适配说明
|
||||
|
||||
- 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b>
|
||||
- 此模块仅支持 **LSPosed** (作用域“系统界面”)、**~~EdXposed(随时停止支持)~~**、不支持**太极、无极**
|
||||
|
||||
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
|
||||
|
||||
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
|
||||
- 目前最低支持基于 Android 9 版本的 MIUI 11 或 MIUI 12、12.5 (最低建议)
|
||||
|
||||
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
|
||||
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、图标黑白块的问题
|
||||
|
||||
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化
|
||||
- 请始终保持最新版本的 **LSPosed**,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面” (“系统 UI”) 选择重新优化
|
||||
|
||||
## 请勿用于非法用途
|
||||
## 历史背景
|
||||
|
||||
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
|
||||
点击下方的链接查看此模块的历史背景与探索历程。
|
||||
|
||||
- 本模块发布地址仅有 [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)、
|
||||
[Release](https://github.com/fankes/MIUINativeNotifyIcon/releases)、[蓝奏云](https://fankes.lanzouy.com/b030o2e8h) 及**酷安应用市场**
|
||||
,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||
- [EXPLORE_HISTORY](EXPLORE_HISTORY.md)
|
||||
|
||||
## 贡献通知图标优化名单
|
||||
|
||||
@@ -42,80 +51,63 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
||||
|
||||
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
|
||||
|
||||
## 历史背景
|
||||
## 发行渠道
|
||||
|
||||
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。
|
||||
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub CI](https://github.com/fankes/MIUINativeNotifyIcon/actions/workflows/commit_ci.yml) | CI 自动构建 (测试版) |
|
||||
|------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|---------------|
|
||||
|
||||
这当然不是系统的错,而是国内 APP 和 `MIPUSH` 的通知极其不规范的通知图标设计。
|
||||
| <img src="https://github.com/peter-iakovlev/Telegram/blob/public/Icon.png?raw=true" width = "30" height = "30" alt="LOGO"/> | [Telegram CI 频道](https://t.me/MIUINativeNotifyIcon_CI) | CI 自动构建 (测试版) |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|---------------|
|
||||
|
||||
但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 `2021-5-18` 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。
|
||||
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub Releases](https://github.com/fankes/MIUINativeNotifyIcon/releases) | 正式版 (稳定版) |
|
||||
|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|-----------|
|
||||
|
||||
对于 Android 开发者来说,官方文档中的 `setSmallIcon` 不再适用于魔改后的 MIUI,这将会严重破坏非常多的状态图标。
|
||||
| <img src="https://avatars.githubusercontent.com/u/78217009?s=200&v=4?raw=true" width = "30" height = "30" alt="LOGO"/> | [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases) | 正式版 (稳定版) |
|
||||
|------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|-----------|
|
||||
|
||||
当然,国内的手机生态除了 `MIPUSH` 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。
|
||||
| <img src="https://github.com/fankes/fankes/assets/37344460/82113d3c-aa7b-4dd1-95c7-cda650065c12" width = "30" height = "30" alt="LOGO"/> | [123 云盘 **(密码:62ll)**](https://www.123pan.com/s/5SlUVv-W8DBh.html) | 正式版 (稳定版) |
|
||||
|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|-----------|
|
||||
|
||||
但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 MIUI 修复了黑白块图标的问题。
|
||||
本模块发布地址仅限于上述所列出的地址,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||
|
||||
## 探索历程
|
||||
## 注意事项
|
||||
|
||||
原生 Android 的小图标和通知图标具有状态性。<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native.jpg" height = "35"/><br/><br/>
|
||||
而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么。<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui.jpg" height = "40"/><br/><br/>
|
||||
同样地,通知面板的图标同样遵守这一状态性。<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_1.jpg" height = "100"/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_2.jpg" height = "100"/><br/><br/>
|
||||
而 MIUI 做了什么呢?<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_1.jpg" height = "100"/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_2.jpg" height = "100"/><br/><br/>
|
||||
不曾记得是什么版本开始,MIUI 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。
|
||||
<h3>1. 本软件免费、由兴趣驱动开发,仅供学习交流使用。如果你是从其他非官方渠道付费获得本软件,可能已遭遇欺诈,欢迎向我们举报可疑行为。</h3>
|
||||
|
||||
由于目前大量通知图标都来自 `MIPUSH` 发出的营销通知,而 `MIPUSH` 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下,MIUI
|
||||
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
|
||||
<h3>2. 本软件采用 <strong>GNU Affero General Public License (AGPL 3.0)</strong> 许可证。根据该许可证的要求:</h3>
|
||||
|
||||
真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类。
|
||||
- 任何衍生作品必须采用相同的 AGPL 许可证
|
||||
- 分发本软件或其修改版本时,必须提供完整的源代码
|
||||
- 必须保留原始的版权声明及许可证信息
|
||||
- 不得额外施加限制来限制他人对本软件的自由使用
|
||||
|
||||
```kotlin
|
||||
com.android.internal.util.ContrastColorUtil
|
||||
```
|
||||
<h3>3. 我们鼓励在遵守 AGPL 3.0 条款的前提下进行自由传播和改进,但请尊重作者署名权,勿冒用原作者名义。</h3>
|
||||
|
||||
这个类中有一个方法可以拿出来判断图标的灰度效果。
|
||||
## 项目推广
|
||||
|
||||
```kotlin
|
||||
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable)
|
||||
```
|
||||
<!--suppress HtmlDeprecatedAttribute -->
|
||||
<div align="center">
|
||||
<h2>嘿,还请君留步!👋</h2>
|
||||
<h3>这里有 Android 开发工具、UI 设计、Gradle 插件、Xposed 模块和实用软件等相关项目。</h3>
|
||||
<h3>如果下方的项目能为你提供帮助,不妨为我点个 star 吧!</h3>
|
||||
<h3>所有项目免费、开源,遵循对应开源许可协议。</h3>
|
||||
<h1><a href="https://github.com/fankes/fankes/blob/main/project-promote/README-zh-CN.md">→ 查看更多关于我的项目,请点击这里 ←</a></h1>
|
||||
</div>
|
||||
|
||||
问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角......
|
||||
## Star History
|
||||
|
||||
最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
|
||||
|
||||
后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
|
||||
|
||||
——来自一个无可奈何的 MIUI 老用户
|
||||
|
||||
## 后记
|
||||
|
||||
近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了。
|
||||
|
||||
特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好。
|
||||
|
||||
MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
|
||||
|
||||
## 捐赠支持
|
||||
|
||||
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
|
||||
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/>
|
||||

|
||||
|
||||
## 隐私政策
|
||||
|
||||
- [PRIVACY](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/PRIVACY.md)
|
||||
- [PRIVACY](PRIVACY.md)
|
||||
|
||||
## 许可证
|
||||
|
||||
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||
```
|
||||
Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -128,9 +120,9 @@ 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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
```
|
||||
|
||||
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)
|
||||
Powered by [YukiHookAPI](https://github.com/HighCapable/YukiHookAPI)
|
||||
|
||||
版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
版权所有 © 2017 Fankes Studio(qzmmcn@163.com)
|
3
app/.gitignore
vendored
3
app/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/build
|
||||
/src/main/assets/xposed_init
|
||||
/src/main/resources/META-INF/yukihookapi_init
|
@@ -1,74 +0,0 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.devtools.ksp' version '1.7.0-1.0.6'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 32
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('../keystore/public')
|
||||
storePassword '123456'
|
||||
keyAlias 'public'
|
||||
keyPassword '123456'
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.fankes.miui.notify"
|
||||
minSdk 28
|
||||
targetSdk 32
|
||||
versionCode rootProject.ext.appVersionCode
|
||||
versionName rootProject.ext.appVersionName
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled rootProject.ext.enableR8
|
||||
shrinkResources rootProject.ext.enableR8
|
||||
zipAlignEnabled rootProject.ext.enableR8
|
||||
signingConfig signingConfigs.debug
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '11'
|
||||
freeCompilerArgs = [
|
||||
'-Xno-param-assertions',
|
||||
'-Xno-call-assertions',
|
||||
'-Xno-receiver-assertions'
|
||||
]
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.92'
|
||||
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: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'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
}
|
89
app/build.gradle.kts
Normal file
89
app/build.gradle.kts
Normal file
@@ -0,0 +1,89 @@
|
||||
plugins {
|
||||
autowire(libs.plugins.android.application)
|
||||
autowire(libs.plugins.kotlin.android)
|
||||
autowire(libs.plugins.kotlin.ksp)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = property.project.app.packageName
|
||||
compileSdk = property.project.android.compileSdk
|
||||
|
||||
signingConfigs {
|
||||
create("universal") {
|
||||
keyAlias = property.project.app.signing.keyAlias
|
||||
keyPassword = property.project.app.signing.keyPassword
|
||||
storeFile = rootProject.file(property.project.app.signing.storeFilePath)
|
||||
storePassword = property.project.app.signing.storePassword
|
||||
enableV1Signing = true
|
||||
enableV2Signing = true
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId = property.project.app.packageName
|
||||
minSdk = property.project.android.minSdk
|
||||
targetSdk = property.project.android.targetSdk
|
||||
versionName = property.project.app.versionName
|
||||
versionCode = property.project.app.versionCode
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
all { signingConfig = signingConfigs.getByName("universal") }
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
}
|
||||
lint { checkReleaseBuilds = false }
|
||||
androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x37")
|
||||
}
|
||||
|
||||
androidComponents {
|
||||
onVariants(selector().all()) {
|
||||
it.outputs.forEach { output ->
|
||||
val currentType = it.buildType
|
||||
|
||||
// Workaround for GitHub Actions.
|
||||
// Why? I don't know, but it works.
|
||||
// Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
|
||||
// public inline fun CharSequence.isNotBlank(): Boolean defined in kotlin.text.
|
||||
@Suppress("UNNECESSARY_SAFE_CALL", "RemoveRedundantCallsOfConversionMethods")
|
||||
val currentSuffix = property.github.ci.commit.id?.let { suffix ->
|
||||
// Workaround for GitHub Actions.
|
||||
// Strongly transfer type to [String].
|
||||
val sSuffix = suffix.toString()
|
||||
if (sSuffix.isNotBlank()) "-$sSuffix" else ""
|
||||
}
|
||||
val currentVersion = "${output.versionName.get()}$currentSuffix(${output.versionCode.get()})"
|
||||
if (output is com.android.build.api.variant.impl.VariantOutputImpl)
|
||||
output.outputFileName.set("${property.project.name}-v$currentVersion-$currentType.apk")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(de.robv.android.xposed.api)
|
||||
implementation(com.highcapable.yukihookapi.api)
|
||||
ksp(com.highcapable.yukihookapi.ksp.xposed)
|
||||
implementation(com.highcapable.kavaref.kavaref.core)
|
||||
implementation(com.highcapable.kavaref.kavaref.extension)
|
||||
implementation(com.fankes.projectpromote.project.promote)
|
||||
implementation(com.github.topjohnwu.libsu.core)
|
||||
implementation(com.github.duanhong169.drawabletoolbox)
|
||||
implementation(com.squareup.okhttp3.okhttp)
|
||||
implementation(androidx.core.core.ktx)
|
||||
implementation(androidx.appcompat.appcompat)
|
||||
implementation(com.google.android.material.material)
|
||||
implementation(androidx.constraintlayout.constraintlayout)
|
||||
testImplementation(junit.junit)
|
||||
androidTestImplementation(androidx.test.ext.junit)
|
||||
androidTestImplementation(androidx.test.espresso.espresso.core)
|
||||
}
|
6
app/proguard-rules.pro
vendored
6
app/proguard-rules.pro
vendored
@@ -32,13 +32,15 @@
|
||||
-adaptresourcefilecontents
|
||||
|
||||
-renamesourcefileattribute P
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
-keepattributes SourceFile,Signature,LineNumberTable
|
||||
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
public static *** throwUninitializedProperty(...);
|
||||
public static *** throwUninitializedPropertyAccessException(...);
|
||||
}
|
||||
|
||||
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
|
||||
-keep class * extends android.app.Activity
|
||||
-keep class * implements androidx.viewbinding.ViewBinding {
|
||||
<init>();
|
||||
*** inflate(android.view.LayoutInflater);
|
||||
}
|
@@ -1,10 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.fankes.miui.notify">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-permission
|
||||
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
|
||||
tools:node="remove" />
|
||||
<permission
|
||||
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
|
||||
tools:node="remove" />
|
||||
|
||||
<application
|
||||
android:name=".application.MNNApplication"
|
||||
@@ -22,7 +29,7 @@
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="为金凡教我做事的 MIUI 修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||
android:value="为金凡教我做事的 MIUI 修复自 12.5 开始后期被破坏的单色图标。\n开发者:酷安 @星夜不荟" />
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="93" />
|
||||
|
@@ -1 +0,0 @@
|
||||
com.fankes.miui.notify.hook.HookEntry_YukiHookXposedInit
|
@@ -1 +0,0 @@
|
||||
com.fankes.miui.notify.hook.HookEntry
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,13 +18,14 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
* This file is created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.miui.notify.application
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
|
||||
|
||||
class MNNApplication : ModuleApplication() {
|
||||
@@ -33,5 +34,7 @@ class MNNApplication : ModuleApplication() {
|
||||
super.onCreate()
|
||||
/** 跟随系统夜间模式 */
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
/** 装载存储控制类 */
|
||||
ConfigData.init(instance = this)
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/30.
|
||||
* This file is created by fankes on 2022/1/30.
|
||||
*/
|
||||
package com.fankes.miui.notify.bean
|
||||
|
||||
@@ -47,13 +47,15 @@ data class IconDataBean(
|
||||
) : Serializable {
|
||||
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
|
||||
fun toEnabledAllName() = ("$appName$packageName").base64 + "_enable_all"
|
||||
override fun toString() = "{\n" +
|
||||
" \"appName\": \"$appName\",\n" +
|
||||
" \"packageName\": \"$packageName\",\n" +
|
||||
" \"iconBitmap\": \"${iconBitmap.base64}\",\n" +
|
||||
" \"iconColor\": \"#${Integer.toHexString(iconColor)}\",\n" +
|
||||
" \"contributorName\": \"$contributorName\",\n" +
|
||||
" \"isEnabled\": $isEnabled,\n" +
|
||||
" \"isEnabledAll\": $isEnabledAll\n" +
|
||||
" }"
|
||||
override fun toString() = """
|
||||
{
|
||||
"appName": "$appName",
|
||||
"packageName": "$packageName",
|
||||
"iconBitmap": "${iconBitmap.base64}",
|
||||
"iconColor": "#${Integer.toHexString(iconColor)}",
|
||||
"contributorName": "$contributorName",
|
||||
"isEnabled": $isEnabled,
|
||||
"isEnabledAll": $isEnabledAll
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/2/2.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.miui.notify.const
|
||||
|
||||
import com.fankes.miui.notify.generated.AppProperties
|
||||
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
|
||||
|
||||
/**
|
||||
* 包名常量定义类
|
||||
*/
|
||||
object PackageName {
|
||||
|
||||
/** 系统界面 (系统 UI) */
|
||||
const val SYSTEMUI = "com.android.systemui"
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知图标优化名单同步方式定义类
|
||||
*/
|
||||
object IconRuleSourceSyncType {
|
||||
|
||||
/** GitHub Raw (代理 - GitHub Proxy) */
|
||||
const val GITHUB_RAW_PROXY_1 = 500
|
||||
|
||||
/** GitHub Raw (代理 - 7ED Services) */
|
||||
const val GITHUB_RAW_PROXY_2 = 1000
|
||||
|
||||
/** GitHub Raw (直连) */
|
||||
const val GITHUB_RAW_DIRECT = 2000
|
||||
|
||||
/** 自定义地址 */
|
||||
const val CUSTOM_URL = 3000
|
||||
}
|
||||
|
||||
/**
|
||||
* 模块版本常量定义类
|
||||
*/
|
||||
object ModuleVersion {
|
||||
|
||||
/** 当前 GitHub 提交的 ID (CI 自动构建) */
|
||||
const val GITHUB_COMMIT_ID = AppProperties.GITHUB_CI_COMMIT_ID
|
||||
|
||||
/** 版本名称 */
|
||||
const val NAME = BuildConfigWrapper.VERSION_NAME
|
||||
|
||||
/** 版本号 */
|
||||
const val CODE = BuildConfigWrapper.VERSION_CODE
|
||||
|
||||
/** 是否为 CI 自动构建版本 */
|
||||
val isCiMode = GITHUB_COMMIT_ID.isNotBlank()
|
||||
|
||||
/** 当前版本名称后缀 */
|
||||
val suffix = GITHUB_COMMIT_ID.let { if (it.isNotBlank()) "-$it" else "" }
|
||||
|
||||
override fun toString() = "$NAME$suffix($CODE)"
|
||||
}
|
388
app/src/main/java/com/fankes/miui/notify/data/ConfigData.kt
Normal file
388
app/src/main/java/com/fankes/miui/notify/data/ConfigData.kt
Normal file
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/2/2.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.miui.notify.data
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.const.IconRuleSourceSyncType
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
/**
|
||||
* 全局配置存储控制类
|
||||
*/
|
||||
object ConfigData {
|
||||
|
||||
/** 启用模块 */
|
||||
val ENABLE_MODULE = PrefsData("_enable_module", true)
|
||||
|
||||
/** 启用模块日志 */
|
||||
val ENABLE_MODULE_LOG = PrefsData("_enable_module_log", false)
|
||||
|
||||
/** 解除状态栏通知图标个数限制 */
|
||||
val ENABLE_LIFTED_STATUS_ICON_COUNT = PrefsData("_enable_hook_status_icon_count", true)
|
||||
|
||||
/** 解除后的状态栏通知图标最大个数 */
|
||||
val LIFTED_STATUS_ICON_COUNT = PrefsData("_hook_status_icon_count", 5)
|
||||
|
||||
/** 启用通知图标兼容模式 */
|
||||
val ENABLE_COLOR_ICON_COMPAT = PrefsData("_color_icon_compat", false)
|
||||
|
||||
/** 状态栏中的通知图标暗色透明度 */
|
||||
val STATUS_ICON_DARK_ALPHA_LEVEL = PrefsData("_status_icon_dark_alpha", 75)
|
||||
|
||||
/** 状态栏中的通知图标亮色透明度 */
|
||||
val STATUS_ICON_LIGHT_ALPHA_LEVEL = PrefsData("_status_icon_light_alpha", 95)
|
||||
|
||||
/** 通知栏中的通知图标圆角程度 */
|
||||
val NOTIFY_ICON_CORNER_SIZE = PrefsData("_notify_icon_corner", 15)
|
||||
|
||||
/** 替换 MIUI 样式通知栏的通知图标 */
|
||||
val ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON = PrefsData("_replace_miui_style_notify_icon", true)
|
||||
|
||||
/** 强制通知栏中的通知图标使用系统着色 */
|
||||
val ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR = PrefsData("_notify_icon_force_system_color", false)
|
||||
|
||||
/** 强制通知栏中的通知图标为 APP 图标 */
|
||||
val ENABLE_NOTIFY_ICON_FORCE_APP_ICON = PrefsData("_notify_icon_force_app_icon", false)
|
||||
|
||||
/** 启用通知图标优化 */
|
||||
val ENABLE_NOTIFY_ICON_FIX = PrefsData("_notify_icon_fix", true)
|
||||
|
||||
/** 强制启用焦点通知反色 */
|
||||
val ENABLE_FOCUS_NOTIFICATION_FIX = PrefsData("_enable_focus_notification_fix", false)
|
||||
|
||||
/** 使用占位符修补未适配的通知图标 */
|
||||
val ENABLE_NOTIFY_ICON_FIX_PLACEHOLDER = PrefsData("_notify_icon_fix_placeholder", false)
|
||||
|
||||
/** 提醒未适配通知图标的新安装应用 */
|
||||
val ENABLE_NOTIFY_ICON_FIX_NOTIFY = PrefsData("_notify_icon_fix_notify", true)
|
||||
|
||||
/** 启用通知图标优化名单自动更新 */
|
||||
val ENABLE_NOTIFY_ICON_FIX_AUTO = PrefsData("_enable_notify_icon_fix_auto", true)
|
||||
|
||||
/** 通知图标优化名单自动更新时间 */
|
||||
val NOTIFY_ICON_FIX_AUTO_TIME = PrefsData("_notify_icon_fix_auto_time", "07:00")
|
||||
|
||||
/** 通知图标优化适配数据 */
|
||||
val NOTIFY_ICONS_DATA = PrefsData("_notify_icon_datas", "")
|
||||
|
||||
/** 通知图标优化名单同步方式 */
|
||||
val ICON_RULE_SOURCE_SYNC_TYPE = PrefsData("_rule_source_sync_way", IconRuleSourceSyncType.GITHUB_RAW_PROXY_1)
|
||||
|
||||
/** 通知图标优化名单同步地址 */
|
||||
val ICON_RULE_SOURCE_SYNC_CUSTOM_URL = PrefsData("_rule_source_sync_way_custom_url", "")
|
||||
|
||||
/** 忽略 Android 版本过低提示 */
|
||||
val IGNORED_ANDROID_VERSION_TO_LOW = PrefsData("_ignored_android_version_to_low", false)
|
||||
|
||||
/** 当前实例 - [Context] or [PackageParam] */
|
||||
private var instance: Any? = null
|
||||
|
||||
/**
|
||||
* 初始化存储控制类
|
||||
* @param instance 实例 - 只能是 [Context] or [PackageParam]
|
||||
* @throws IllegalStateException 如果类型错误
|
||||
*/
|
||||
fun init(instance: Any) {
|
||||
when (instance) {
|
||||
is Context, is PackageParam -> this.instance = instance
|
||||
else -> error("Unknown type for init ConfigData")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 [String] 数据
|
||||
* @param data 键值数据模板
|
||||
* @return [String]
|
||||
*/
|
||||
private fun getString(data: PrefsData<String>) = when (instance) {
|
||||
is Context -> (instance as Context).prefs().get(data)
|
||||
is PackageParam -> (instance as PackageParam).prefs.get(data)
|
||||
else -> error("Unknown type for get prefs data")
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入 [String] 数据
|
||||
* @param data 键值数据模板
|
||||
* @param value 键值内容
|
||||
*/
|
||||
private fun putString(data: PrefsData<String>, value: String) {
|
||||
when (instance) {
|
||||
is Context -> (instance as Context).prefs().edit { put(data, value) }
|
||||
is PackageParam -> YLog.warn("Not support for this method")
|
||||
else -> error("Unknown type for put prefs data")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 [Int] 数据
|
||||
* @param data 键值数据模板
|
||||
* @return [Int]
|
||||
*/
|
||||
internal fun getInt(data: PrefsData<Int>) = when (instance) {
|
||||
is Context -> (instance as Context).prefs().get(data)
|
||||
is PackageParam -> (instance as PackageParam).prefs.get(data)
|
||||
else -> error("Unknown type for get prefs data")
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入 [Int] 数据
|
||||
* @param data 键值数据模板
|
||||
* @param value 键值内容
|
||||
*/
|
||||
internal fun putInt(data: PrefsData<Int>, value: Int) {
|
||||
when (instance) {
|
||||
is Context -> (instance as Context).prefs().edit { put(data, value) }
|
||||
is PackageParam -> YLog.warn("Not support for this method")
|
||||
else -> error("Unknown type for put prefs data")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 [Boolean] 数据
|
||||
* @param data 键值数据模板
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun getBoolean(data: PrefsData<Boolean>) = when (instance) {
|
||||
is Context -> (instance as Context).prefs().get(data)
|
||||
is PackageParam -> (instance as PackageParam).prefs.get(data)
|
||||
else -> error("Unknown type for get prefs data")
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入 [Boolean] 数据
|
||||
* @param data 键值数据模板
|
||||
* @param value 键值内容
|
||||
*/
|
||||
internal fun putBoolean(data: PrefsData<Boolean>, value: Boolean) {
|
||||
when (instance) {
|
||||
is Context -> (instance as Context).prefs().edit { put(data, value) }
|
||||
is PackageParam -> YLog.warn("Not support for this method")
|
||||
else -> error("Unknown type for put prefs data")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用模块
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableModule
|
||||
get() = getBoolean(ENABLE_MODULE)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_MODULE, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用模块日志
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableModuleLog
|
||||
get() = getBoolean(ENABLE_MODULE_LOG)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_MODULE_LOG, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否解除状态栏通知图标个数限制
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableLiftedStatusIconCount
|
||||
get() = getBoolean(ENABLE_LIFTED_STATUS_ICON_COUNT)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_LIFTED_STATUS_ICON_COUNT, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除后的状态栏通知图标最大个数
|
||||
* @return [Int]
|
||||
*/
|
||||
var liftedStatusIconCount
|
||||
get() = getInt(LIFTED_STATUS_ICON_COUNT)
|
||||
set(value) {
|
||||
putInt(LIFTED_STATUS_ICON_COUNT, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用通知图标兼容模式
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableColorIconCompat
|
||||
get() = getBoolean(ENABLE_COLOR_ICON_COMPAT)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_COLOR_ICON_COMPAT, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态栏中的通知图标暗色透明度
|
||||
* @return [Int]
|
||||
*/
|
||||
var statusIconDarkAlphaLevel
|
||||
get() = getInt(STATUS_ICON_DARK_ALPHA_LEVEL)
|
||||
set(value) {
|
||||
putInt(STATUS_ICON_DARK_ALPHA_LEVEL, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态栏中的通知图标亮色透明度
|
||||
* @return [Int]
|
||||
*/
|
||||
var statusIconLightAlphaLevel
|
||||
get() = getInt(STATUS_ICON_LIGHT_ALPHA_LEVEL)
|
||||
set(value) {
|
||||
putInt(STATUS_ICON_LIGHT_ALPHA_LEVEL, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知栏中的通知图标圆角程度
|
||||
* @return [Int]
|
||||
*/
|
||||
var notifyIconCornerSize
|
||||
get() = getInt(NOTIFY_ICON_CORNER_SIZE)
|
||||
set(value) {
|
||||
putInt(NOTIFY_ICON_CORNER_SIZE, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否替换 MIUI 样式通知栏的通知图标
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableReplaceMiuiStyleNotifyIcon
|
||||
get() = getBoolean(ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否强制通知栏中的通知图标使用系统着色
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconForceSystemColor
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否强制通知栏中的通知图标为 APP 图标
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconForceAppIcon
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FORCE_APP_ICON)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FORCE_APP_ICON, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用通知图标优化
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconFix
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FIX)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FIX, value)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否强制启用焦点通知反色
|
||||
* @return [Boolean]*/
|
||||
var isEnableFocusNotificationFix
|
||||
get() = getBoolean(ENABLE_FOCUS_NOTIFICATION_FIX)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_FOCUS_NOTIFICATION_FIX, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用占位符修补未适配的通知图标
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconFixPlaceholder
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FIX_PLACEHOLDER)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FIX_PLACEHOLDER, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否提醒未适配通知图标的新安装应用
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconFixNotify
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FIX_NOTIFY)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FIX_NOTIFY, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用通知图标优化名单自动更新
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isEnableNotifyIconFixAuto
|
||||
get() = getBoolean(ENABLE_NOTIFY_ICON_FIX_AUTO)
|
||||
set(value) {
|
||||
putBoolean(ENABLE_NOTIFY_ICON_FIX_AUTO, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知图标优化名单自动更新时间
|
||||
* @return [String]
|
||||
*/
|
||||
var notifyIconFixAutoTime
|
||||
get() = getString(NOTIFY_ICON_FIX_AUTO_TIME)
|
||||
set(value) {
|
||||
putString(NOTIFY_ICON_FIX_AUTO_TIME, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知图标优化名单同步方式
|
||||
* @return [Int]
|
||||
*/
|
||||
var iconRuleSourceSyncType
|
||||
get() = getInt(ICON_RULE_SOURCE_SYNC_TYPE)
|
||||
set(value) {
|
||||
putInt(ICON_RULE_SOURCE_SYNC_TYPE, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知图标优化名单同步地址
|
||||
* @return [String]
|
||||
*/
|
||||
var iconRuleSourceSyncCustomUrl
|
||||
get() = getString(ICON_RULE_SOURCE_SYNC_CUSTOM_URL)
|
||||
set(value) {
|
||||
putString(ICON_RULE_SOURCE_SYNC_CUSTOM_URL, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否忽略 Android 版本过低提示
|
||||
* @return [Boolean]
|
||||
*/
|
||||
var isIgnoredAndroidVersionToLow
|
||||
get() = getBoolean(IGNORED_ANDROID_VERSION_TO_LOW)
|
||||
set(value) {
|
||||
putBoolean(IGNORED_ANDROID_VERSION_TO_LOW, value)
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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/3/26.
|
||||
*/
|
||||
package com.fankes.miui.notify.data
|
||||
|
||||
import com.fankes.miui.notify.hook.HookConst
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
object DataConst {
|
||||
|
||||
val ENABLE_MODULE = PrefsData("_enable_module", true)
|
||||
val ENABLE_MODULE_LOG = PrefsData("_enable_module_log", false)
|
||||
val ENABLE_HIDE_ICON = PrefsData("_hide_icon", false)
|
||||
val ENABLE_COLOR_ICON_COMPAT = PrefsData("_color_icon_compat", false)
|
||||
val ENABLE_NOTIFY_ICON_FIX = PrefsData("_notify_icon_fix", true)
|
||||
val ENABLE_NOTIFY_ICON_FORCE_APP_ICON = PrefsData("_notify_icon_force_app_icon", false)
|
||||
val ENABLE_NOTIFY_ICON_FIX_NOTIFY = PrefsData("_notify_icon_fix_notify", true)
|
||||
val ENABLE_HOOK_STATUS_ICON_COUNT = PrefsData("_enable_hook_status_icon_count", true)
|
||||
val ENABLE_NOTIFY_ICON_FIX_AUTO = PrefsData("_enable_notify_icon_fix_auto", true)
|
||||
val NOTIFY_ICON_CORNER = PrefsData("_notify_icon_corner", 15)
|
||||
val NOTIFY_ICON_DATAS = PrefsData("_notify_icon_datas", "")
|
||||
val NOTIFY_ICON_FIX_AUTO_TIME = PrefsData("_notify_icon_fix_auto_time", "07:00")
|
||||
val HOOK_STATUS_ICON_COUNT = PrefsData("_hook_status_icon_count", 5)
|
||||
|
||||
val IGNORED_ANDROID_VERSION_TO_LOW = PrefsData("_ignored_android_version_to_low", false)
|
||||
|
||||
val SOURCE_SYNC_WAY = PrefsData("_rule_source_sync_way", HookConst.TYPE_SOURCE_SYNC_WAY_1)
|
||||
val SOURCE_SYNC_WAY_CUSTOM_URL = PrefsData("_rule_source_sync_way_custom_url", "")
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/2/3.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.miui.notify.data.factory
|
||||
|
||||
import android.widget.CompoundButton
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
/**
|
||||
* 绑定到 [CompoundButton] 自动设置选中状态
|
||||
* @param data 键值数据模板
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun CompoundButton.bind(data: PrefsData<Boolean>, initiate: CompoundButtonDataBinder.(CompoundButton) -> Unit = {}) {
|
||||
val binder = CompoundButtonDataBinder(button = this).also { initiate(it, this) }
|
||||
isChecked = ConfigData.getBoolean(data).also { binder.initializeCallback?.invoke(it) }
|
||||
binder.applyChangesCallback = { ConfigData.putBoolean(data, it) }
|
||||
setOnCheckedChangeListener { button, isChecked ->
|
||||
if (button.isPressed) {
|
||||
if (binder.isAutoApplyChanges) binder.applyChangesCallback?.invoke(isChecked)
|
||||
binder.changedCallback?.invoke(isChecked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [CompoundButton] 数据绑定管理器实例
|
||||
* @param button 当前实例
|
||||
*/
|
||||
class CompoundButtonDataBinder(private val button: CompoundButton) {
|
||||
|
||||
/** 状态初始化回调事件 */
|
||||
internal var initializeCallback: ((Boolean) -> Unit)? = null
|
||||
|
||||
/** 状态改变回调事件 */
|
||||
internal var changedCallback: ((Boolean) -> Unit)? = null
|
||||
|
||||
/** 应用更改回调事件 */
|
||||
internal var applyChangesCallback: ((Boolean) -> Unit)? = null
|
||||
|
||||
/** 是否启用自动应用更改 */
|
||||
var isAutoApplyChanges = true
|
||||
|
||||
/**
|
||||
* 监听状态初始化
|
||||
* @param result 回调结果
|
||||
*/
|
||||
fun onInitialize(result: (Boolean) -> Unit) {
|
||||
initializeCallback = result
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听状态改变
|
||||
* @param result 回调结果
|
||||
*/
|
||||
fun onChanged(result: (Boolean) -> Unit) {
|
||||
changedCallback = result
|
||||
}
|
||||
|
||||
/** 重新初始化 */
|
||||
fun reinitialize() {
|
||||
initializeCallback?.invoke(button.isChecked)
|
||||
}
|
||||
|
||||
/** 应用更改并重新初始化 */
|
||||
fun applyChangesAndReinitialize() {
|
||||
applyChanges()
|
||||
reinitialize()
|
||||
}
|
||||
|
||||
/** 应用更改 */
|
||||
fun applyChanges() {
|
||||
applyChangesCallback?.invoke(button.isChecked)
|
||||
}
|
||||
|
||||
/** 取消更改 */
|
||||
fun cancelChanges() {
|
||||
button.isChecked = button.isChecked.not()
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/2/4.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n")
|
||||
|
||||
package com.fankes.miui.notify.data.factory
|
||||
|
||||
import android.widget.SeekBar
|
||||
import android.widget.TextView
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
/**
|
||||
* 绑定到 [SeekBar] 自动设置进度与 [TextView]
|
||||
* @param data 键值数据模板
|
||||
* @param textView 文本框
|
||||
* @param suffix 文本显示的后缀 - 默认空
|
||||
* @param onChange 当改变停止时回调
|
||||
*/
|
||||
fun SeekBar.bind(data: PrefsData<Int>, textView: TextView, suffix: String = "", onChange: (Int) -> Unit = {}) {
|
||||
ConfigData.getInt(data).also { value ->
|
||||
textView.text = "$value$suffix"
|
||||
progress = value
|
||||
}
|
||||
setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
textView.text = "$progress$suffix"
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
ConfigData.putInt(data, seekBar.progress)
|
||||
onChange(seekBar.progress)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
|
||||
})
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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/1/24.
|
||||
*/
|
||||
@file:Suppress("SetWorldReadable")
|
||||
|
||||
package com.fankes.miui.notify.hook
|
||||
|
||||
object HookConst {
|
||||
|
||||
const val TYPE_SOURCE_SYNC_WAY_1 = 1000
|
||||
const val TYPE_SOURCE_SYNC_WAY_2 = 2000
|
||||
const val TYPE_SOURCE_SYNC_WAY_3 = 3000
|
||||
|
||||
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,43 +18,43 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/15.
|
||||
* This file is created by fankes on 2022/2/15.
|
||||
*/
|
||||
package com.fankes.miui.notify.hook
|
||||
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
import com.fankes.miui.notify.const.PackageName
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.hook.entity.SystemUIHooker
|
||||
import com.fankes.miui.notify.utils.factory.isLowerAndroidP
|
||||
import com.fankes.miui.notify.utils.factory.isNotMIUI
|
||||
import com.fankes.miui.notify.utils.factory.isNotSupportMiuiVersion
|
||||
import com.fankes.miui.notify.utils.factory.miuiVersion
|
||||
import com.fankes.miui.notify.utils.factory.isNotMiSystem
|
||||
import com.fankes.miui.notify.utils.factory.isNotSupportMiSystemVersion
|
||||
import com.fankes.miui.notify.utils.factory.miSystemVersion
|
||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.factory.configs
|
||||
import com.highcapable.yukihookapi.hook.factory.encase
|
||||
import com.highcapable.yukihookapi.hook.log.loggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
||||
|
||||
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
|
||||
class HookEntry : IYukiHookXposedInit {
|
||||
@InjectYukiHookWithXposed
|
||||
object HookEntry : IYukiHookXposedInit {
|
||||
|
||||
override fun onInit() = configs {
|
||||
debugTag = "MIUINativeNotifyIcon"
|
||||
debugLog {
|
||||
tag = "MIUINativeNotifyIcon"
|
||||
isRecord = true
|
||||
elements(PRIORITY)
|
||||
}
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
override fun onHook() = encase {
|
||||
loadApp(SYSTEMUI_PACKAGE_NAME) {
|
||||
loadApp(PackageName.SYSTEMUI) {
|
||||
ConfigData.init(instance = this)
|
||||
when {
|
||||
/** 不是 MIUI 系统停止 Hook */
|
||||
isNotMIUI -> loggerW(msg = "Aborted Hook -> This System is not MIUI")
|
||||
/** 系统版本低于 Android P 停止 Hook */
|
||||
isLowerAndroidP -> loggerW(msg = "Aborted Hook -> This System is lower than Android P")
|
||||
/** 不是支持的 MIUI 系统停止 Hook */
|
||||
isNotSupportMiuiVersion -> loggerW(msg = "Aborted Hook -> This MIUI Version $miuiVersion not supported")
|
||||
/** Hook 被手动关闭停止 Hook */
|
||||
prefs.get(DataConst.ENABLE_MODULE).not() -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
||||
/** 开始 Hook */
|
||||
isNotMiSystem -> YLog.warn("Aborted Hook -> This System is not MIUI or HyperOS")
|
||||
isLowerAndroidP -> YLog.warn("Aborted Hook -> This System is lower than Android P")
|
||||
isNotSupportMiSystemVersion -> YLog.warn("Aborted Hook -> This System Version ${miSystemVersion.ifBlank { "unknown" }} not supported")
|
||||
ConfigData.isEnableModule.not() -> YLog.warn("Aborted Hook -> Hook Closed")
|
||||
else -> loadHooker(SystemUIHooker)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
* This file is created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
@@ -27,9 +27,13 @@ package com.fankes.miui.notify.params
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.utils.factory.bitmap
|
||||
import com.fankes.miui.notify.utils.factory.safeOf
|
||||
import com.fankes.miui.notify.utils.factory.safeOfNan
|
||||
import com.fankes.miui.notify.utils.factory.safeOfNull
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
@@ -47,7 +51,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* 已存储的 JSON 数据
|
||||
* @return [String]
|
||||
*/
|
||||
internal val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.direct()?.get(DataConst.NOTIFY_ICON_DATAS)
|
||||
internal val storageDataJson get() = (context?.prefs() ?: param?.prefs)?.get(ConfigData.NOTIFY_ICONS_DATA)
|
||||
|
||||
/**
|
||||
* 获取图标数据
|
||||
@@ -92,7 +96,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* @return [String] 拼接后的数据
|
||||
*/
|
||||
fun splicingJsonArray(dataJson1: String, dataJson2: String) = safeOf(default = "[]") {
|
||||
dataJson1.replace(oldValue = "]", newValue = "") + "," + dataJson2.replace(oldValue = "[", newValue = "")
|
||||
dataJson1.replace("]", "") + "," + dataJson2.replace("[", "")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +125,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* @param json 数据
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun isHackString(json: String) = json.contains(other = "Checking your browser before accessing")
|
||||
fun isHackString(json: String) = json.contains("Checking your browser before accessing")
|
||||
|
||||
/**
|
||||
* 比较图标数据不相等
|
||||
@@ -134,5 +138,5 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* 保存图标数据
|
||||
* @param dataJson 图标数据 JSON
|
||||
*/
|
||||
fun save(dataJson: String) = context?.modulePrefs?.put(DataConst.NOTIFY_ICON_DATAS, dataJson)
|
||||
}
|
||||
fun save(dataJson: String) = context?.prefs()?.edit { put(ConfigData.NOTIFY_ICONS_DATA, dataJson) }
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,13 +18,14 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/15.
|
||||
* This file is created by fankes on 2022/2/15.
|
||||
* This file is Modified by fankes on 2023/2/3.
|
||||
*/
|
||||
package com.fankes.miui.notify.hook.factory
|
||||
package com.fankes.miui.notify.params.factory
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
|
||||
/**
|
||||
@@ -37,14 +38,14 @@ fun PackageParam.isAppNotifyHookOf(bean: IconDataBean) = prefs.getBoolean(bean.t
|
||||
* 获取此 APP 的通知图标是否被 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun Context.isAppNotifyHookOf(bean: IconDataBean) = modulePrefs.getBoolean(bean.toEnabledName(), bean.isEnabled)
|
||||
fun Context.isAppNotifyHookOf(bean: IconDataBean) = prefs().getBoolean(bean.toEnabledName(), bean.isEnabled)
|
||||
|
||||
/**
|
||||
* 设置 Hook 此 APP 的通知图标
|
||||
* @param bean 图标 bean
|
||||
* @param isHook 是否 Hook
|
||||
*/
|
||||
fun Context.putAppNotifyHookOf(bean: IconDataBean, isHook: Boolean) = modulePrefs.putBoolean(bean.toEnabledName(), isHook)
|
||||
fun Context.putAppNotifyHookOf(bean: IconDataBean, isHook: Boolean) = prefs().edit { putBoolean(bean.toEnabledName(), isHook) }
|
||||
|
||||
/**
|
||||
* 获取此 APP 的通知图标是否被全部 Hook
|
||||
@@ -56,11 +57,11 @@ fun PackageParam.isAppNotifyHookAllOf(bean: IconDataBean) = prefs.getBoolean(bea
|
||||
* 获取此 APP 的通知图标是否被全部 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun Context.isAppNotifyHookAllOf(bean: IconDataBean) = modulePrefs.getBoolean(bean.toEnabledAllName(), bean.isEnabledAll)
|
||||
fun Context.isAppNotifyHookAllOf(bean: IconDataBean) = prefs().getBoolean(bean.toEnabledAllName(), bean.isEnabledAll)
|
||||
|
||||
/**
|
||||
* 设置全部 Hook 此 APP 的通知图标
|
||||
* @param bean 图标 bean
|
||||
* @param isHook 是否 Hook
|
||||
*/
|
||||
fun Context.putAppNotifyHookAllOf(bean: IconDataBean, isHook: Boolean) = modulePrefs.putBoolean(bean.toEnabledAllName(), isHook)
|
||||
fun Context.putAppNotifyHookAllOf(bean: IconDataBean, isHook: Boolean) = prefs().edit { putBoolean(bean.toEnabledAllName(), isHook) }
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/26.
|
||||
* This file is created by fankes on 2022/3/26.
|
||||
*/
|
||||
package com.fankes.miui.notify.service
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,25 +18,35 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/30.
|
||||
* This file is created by fankes on 2022/1/30.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n", "InflateParams", "DEPRECATION")
|
||||
@file:Suppress("SetTextI18n", "InflateParams")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity
|
||||
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.databinding.ActivityConfigBinding
|
||||
import com.fankes.miui.notify.databinding.AdapterConfigBinding
|
||||
import com.fankes.miui.notify.databinding.DiaIconFilterBinding
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.params.factory.isAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.params.factory.isAppNotifyHookOf
|
||||
import com.fankes.miui.notify.params.factory.putAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.params.factory.putAppNotifyHookOf
|
||||
import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.factory.addOnBackPressedEvent
|
||||
import com.fankes.miui.notify.utils.factory.bindAdapter
|
||||
import com.fankes.miui.notify.utils.factory.callOnBackPressed
|
||||
import com.fankes.miui.notify.utils.factory.colorOf
|
||||
import com.fankes.miui.notify.utils.factory.copyToClipboard
|
||||
import com.fankes.miui.notify.utils.factory.navigate
|
||||
import com.fankes.miui.notify.utils.factory.openBrowser
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.fankes.miui.notify.utils.factory.toast
|
||||
import com.fankes.miui.notify.utils.tool.IconRuleManagerTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
@@ -56,18 +66,18 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
private var iconAllDatas = ArrayList<IconDataBean>()
|
||||
|
||||
override fun onCreate() {
|
||||
/** 检查激活状态 */
|
||||
if (YukiHookAPI.Status.isXposedModuleActive.not()) {
|
||||
/** 检查激活和启用状态 */
|
||||
if (YukiHookAPI.Status.isXposedModuleActive.not() || ConfigData.isEnableModule.not()) {
|
||||
showDialog {
|
||||
title = "模块没有激活"
|
||||
msg = "模块没有激活,你无法使用这里的功能,请先激活模块。"
|
||||
title = "模块不可用"
|
||||
msg = "模块没有激活或已被停用,你无法使用这里的功能,请先激活或启用模块。"
|
||||
confirmButton(text = "我知道了") { finish() }
|
||||
noCancelable()
|
||||
}
|
||||
return
|
||||
}
|
||||
/** 返回按钮点击事件 */
|
||||
binding.titleBackIcon.setOnClickListener { onBackPressed() }
|
||||
binding.titleBackIcon.setOnClickListener { callOnBackPressed() }
|
||||
/** 刷新适配器结果相关 */
|
||||
refreshAdapterResult()
|
||||
/** 设置上下按钮点击事件 */
|
||||
@@ -117,7 +127,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
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 ->
|
||||
(if (bean.iconColor != 0) bean.iconColor else resources.colorOf(R.color.colorTextGray)).also { color ->
|
||||
binding.adpAppIcon.setColorFilter(color)
|
||||
binding.adpAppName.setTextColor(color)
|
||||
}
|
||||
@@ -144,8 +154,8 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
if (b) showDialog {
|
||||
title = "全部替换"
|
||||
msg = "此功能仅针对严重不遵守规范的 APP 通知图标才需要开启,例如:APP 推送通知后无法识别出现的黑白块图标。\n\n" +
|
||||
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
|
||||
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
|
||||
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
|
||||
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
|
||||
confirmButton { saveState() }
|
||||
cancelButton { btn.isChecked = btn.isChecked.not() }
|
||||
noCancelable()
|
||||
@@ -172,8 +182,8 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
showDialog {
|
||||
title = "感谢你的贡献"
|
||||
msg = "通知图标优化名单需要大家的共同维护才能得以完善,请选择你的贡献方式。"
|
||||
confirmButton(text = "贡献规则") { openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md") }
|
||||
cancelButton(text = "请求适配") { openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon/issues/new/choose") }
|
||||
confirmButton(text = "贡献规则") { openBrowser(IconRuleManagerTool.RULES_CONTRIBUTING_URL) }
|
||||
cancelButton(text = "请求适配") { openBrowser(IconRuleManagerTool.RULES_FEEDBACK_URL) }
|
||||
neutralButton(text = "暂时不用")
|
||||
}
|
||||
}
|
||||
@@ -187,30 +197,56 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
val pkgName = intent?.getStringExtra("pkgName") ?: ""
|
||||
title = "新安装应用通知图标适配"
|
||||
msg = "你已安装 $appName($pkgName)\n\n" +
|
||||
"此应用未在通知优化名单中发现适配数据,若此应用发送的通知为彩色图标," +
|
||||
"可随时点击本页面下方的“贡献通知图标优化名单”按钮提交贡献或请求适配。\n\n" +
|
||||
"若你已知晓此应用会遵守原生通知图标规范,可忽略此提示。\n\n" +
|
||||
"你可以现在立即同步适配列表,以获取最新的适配数据。"
|
||||
"此应用未在通知优化名单中发现适配数据,若此应用发送的通知为彩色图标," +
|
||||
"可随时点击本页面下方的“贡献通知图标优化名单”按钮提交贡献或请求适配。\n\n" +
|
||||
"若你已知晓此应用会遵守原生通知图标规范,可忽略此提示。\n\n" +
|
||||
"你可以现在立即同步适配列表,以获取最新的适配数据。"
|
||||
confirmButton(text = "同步列表") { onStartRefresh() }
|
||||
cancelButton(text = "复制名称+包名") { copyToClipboard(content = "$appName($pkgName)") }
|
||||
neutralButton(text = "取消")
|
||||
noCancelable()
|
||||
}
|
||||
intent?.getBooleanExtra("isDirectUpdate", false) == true -> onStartRefresh(isByHand = false)
|
||||
intent?.getBooleanExtra("isShowUpdDialog", true) == true -> onStartRefresh()
|
||||
}
|
||||
/** 清除数据 */
|
||||
intent?.apply {
|
||||
removeExtra("isNewAppSupport")
|
||||
removeExtra("isDirectUpdate")
|
||||
removeExtra("isShowUpdDialog")
|
||||
}
|
||||
/** 设置返回监听事件 */
|
||||
addOnBackPressedEvent {
|
||||
if (MainActivity.isActivityLive.not())
|
||||
showDialog {
|
||||
title = "提示"
|
||||
msg = "要返回模块主页吗?"
|
||||
confirmButton {
|
||||
releaseEventAndBack()
|
||||
navigate<MainActivity>()
|
||||
}
|
||||
cancelButton { releaseEventAndBack() }
|
||||
}
|
||||
else releaseEventAndBack()
|
||||
}
|
||||
}
|
||||
|
||||
/** 开始手动同步 */
|
||||
private fun onStartRefresh() =
|
||||
IconRuleManagerTool.syncByHand(context = this) {
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
}
|
||||
/**
|
||||
* 开始同步
|
||||
* @param isByHand 是否手动同步 - 默认是
|
||||
*/
|
||||
private fun onStartRefresh(isByHand: Boolean = true) {
|
||||
if (isByHand)
|
||||
IconRuleManagerTool.syncByHand(context = this) {
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
}
|
||||
else
|
||||
IconRuleManagerTool.sync(context = this) {
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
}
|
||||
}
|
||||
|
||||
/** 装载或刷新本地数据 */
|
||||
private fun mockLocalData() {
|
||||
@@ -223,7 +259,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
onChanged?.invoke()
|
||||
binding.configTitleCountText.text =
|
||||
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
||||
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
||||
else "“$filterText” 匹配到 ${iconDatas.size} 个结果"
|
||||
binding.configListNoDataView.apply {
|
||||
text = if (iconAllDatas.isEmpty()) "噫,竟然什么都没有~\n请点击右上角同步按钮获取云端数据" else "噫,竟然什么都没找到~"
|
||||
isVisible = iconDatas.isEmpty()
|
||||
@@ -239,18 +275,4 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
else iconAllDatas.filter {
|
||||
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (MainActivity.isActivityLive.not())
|
||||
showDialog {
|
||||
title = "提示"
|
||||
msg = "要返回模块主页吗?"
|
||||
confirmButton {
|
||||
super.onBackPressed()
|
||||
navigate<MainActivity>()
|
||||
}
|
||||
cancelButton { super.onBackPressed() }
|
||||
}
|
||||
else super.onBackPressed()
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,30 +18,45 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
* This file is created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.widget.SeekBar
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.miui.notify.BuildConfig
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.const.ModuleVersion
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.data.factory.bind
|
||||
import com.fankes.miui.notify.databinding.ActivityMainBinding
|
||||
import com.fankes.miui.notify.databinding.DiaStatusIconCountBinding
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.factory.androidVersionCodeName
|
||||
import com.fankes.miui.notify.utils.factory.hideOrShowLauncherIcon
|
||||
import com.fankes.miui.notify.utils.factory.isLauncherIconShowing
|
||||
import com.fankes.miui.notify.utils.factory.isLowerAndroidP
|
||||
import com.fankes.miui.notify.utils.factory.isLowerAndroidR
|
||||
import com.fankes.miui.notify.utils.factory.isMIOS
|
||||
import com.fankes.miui.notify.utils.factory.isNotMiSystem
|
||||
import com.fankes.miui.notify.utils.factory.isNotNoificationEnabled
|
||||
import com.fankes.miui.notify.utils.factory.isNotSupportMiSystemVersion
|
||||
import com.fankes.miui.notify.utils.factory.miSystemVersion
|
||||
import com.fankes.miui.notify.utils.factory.miuiVersionCode
|
||||
import com.fankes.miui.notify.utils.factory.navigate
|
||||
import com.fankes.miui.notify.utils.factory.openBrowser
|
||||
import com.fankes.miui.notify.utils.factory.openNotifySetting
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.showTimePicker
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.fankes.miui.notify.utils.factory.systemFullVersion
|
||||
import com.fankes.miui.notify.utils.tool.GithubReleaseTool
|
||||
import com.fankes.miui.notify.utils.tool.I18nWarnTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.fankes.miui.notify.utils.tool.YukiPromoteTool
|
||||
import com.fankes.projectpromote.ProjectPromote
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
@@ -50,27 +65,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
/** 窗口是否启动 */
|
||||
internal var isActivityLive = false
|
||||
|
||||
/** 模块版本 */
|
||||
private const val moduleVersion = BuildConfig.VERSION_NAME
|
||||
/** 模块是否可用 */
|
||||
internal var isModuleRegular = false
|
||||
|
||||
/** 预发布的版本标识 */
|
||||
private const val pendingFlag = ""
|
||||
/** 模块是否有效 */
|
||||
internal var isModuleValied = false
|
||||
}
|
||||
|
||||
/** 模块是否可用 */
|
||||
private var isModuleRegular = false
|
||||
|
||||
/** 模块是否有效 */
|
||||
private var isModuleValied = false
|
||||
|
||||
override fun onCreate() {
|
||||
/** 设置可用性 */
|
||||
isActivityLive = true
|
||||
/** 设置文本 */
|
||||
binding.mainTextVersion.text = "模块版本:$moduleVersion $pendingFlag"
|
||||
binding.mainTextMiuiVersion.text = "系统版本:$miuiFullVersion"
|
||||
/** 检查更新 */
|
||||
GithubReleaseTool.checkingForUpdate(context = this, moduleVersion) { version, function ->
|
||||
GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function ->
|
||||
binding.mainTextReleaseVersion.apply {
|
||||
text = "点击更新 $version"
|
||||
isVisible = true
|
||||
@@ -78,45 +84,58 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
}
|
||||
}
|
||||
when {
|
||||
/** 判断是否为 MIUI 系统 */
|
||||
isNotMIUI ->
|
||||
/** 判断是否为小米系统 */
|
||||
isNotMiSystem ->
|
||||
showDialog {
|
||||
title = "不是 MIUI 系统"
|
||||
msg = "此模块专为 MIUI 系统打造,当前无法识别你的系统为 MIUI,所以模块无法工作。\n" +
|
||||
"如有问题请联系 酷安 @星夜不荟"
|
||||
confirmButton(text = "退出") { finish() }
|
||||
title = "不是 MIUI 或 HyperOS 系统"
|
||||
msg = "此模块专为 MIUI、HyperOS 系统打造,当前无法识别你的系统为其中任意之一,所以模块无法工作。"
|
||||
confirmButton(text = "查看支持的模块") {
|
||||
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt")
|
||||
finish()
|
||||
}
|
||||
cancelButton(text = "退出") { finish() }
|
||||
noCancelable()
|
||||
}
|
||||
/** 判断最低 Android 系统版本 */
|
||||
isLowerAndroidP ->
|
||||
showDialog {
|
||||
title = "Android 系统版本过低"
|
||||
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\n" +
|
||||
"如有问题请联系 酷安 @星夜不荟"
|
||||
confirmButton(text = "退出") { finish() }
|
||||
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\n\n" +
|
||||
"若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
|
||||
confirmButton(text = "前往项目地址") {
|
||||
openProjectUrl()
|
||||
finish()
|
||||
}
|
||||
cancelButton(text = "退出") { finish() }
|
||||
noCancelable()
|
||||
}
|
||||
/** 判断最低 MIUI 版本 */
|
||||
isNotSupportMiuiVersion ->
|
||||
/** 判断支持的系统版本 */
|
||||
isNotSupportMiSystemVersion ->
|
||||
showDialog {
|
||||
title = "MIUI 版本过低"
|
||||
msg = "此模块最低支持 MIUI 12 系统,你的 MIUI 版本为 ${miuiVersion},不再进行适配。\n" +
|
||||
"如有问题请联系 酷安 @星夜不荟"
|
||||
confirmButton(text = "退出") { finish() }
|
||||
title = "不支持的系统版本"
|
||||
msg = (if (miSystemVersion.isNotBlank())
|
||||
"此模块目前支持 MIUI 11~14 和 HyperOS 1.0~2.0 系统,你的系统版本为 $miSystemVersion,暂不支持。\n\n" +
|
||||
"如果你的系统版本识别有误,请检查是否有相关插件修改了系统版本。\n\n"
|
||||
else "无法获取系统版本,请检查你是否修改了系统参数或使用非官方系统。\n\n") + "若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
|
||||
confirmButton(text = "前往项目地址") {
|
||||
openProjectUrl()
|
||||
finish()
|
||||
}
|
||||
cancelButton(text = "退出") { finish() }
|
||||
noCancelable()
|
||||
}
|
||||
/** 判断是否 Hook */
|
||||
YukiHookAPI.Status.isXposedModuleActive -> {
|
||||
if (IconPackParams(context = this).iconDatas.isEmpty() && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX))
|
||||
if (IconPackParams(context = this).iconDatas.isEmpty() && ConfigData.isEnableNotifyIconFix)
|
||||
showDialog {
|
||||
title = "配置通知图标优化名单"
|
||||
msg = "模块需要获取在线规则以更新“通知图标优化名单”,它现在是空的,这看起来是你第一次使用模块,请首先进行配置才可以使用相关功能。\n" +
|
||||
"你可以随时在本页面下方找到“配置通知图标优化名单”手动前往。"
|
||||
"你可以随时在本页面下方找到“配置通知图标优化名单”手动前往。"
|
||||
confirmButton(text = "前往") { navigate<ConfigureActivity>() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
if (isNotNoificationEnabled && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX))
|
||||
if (isNotNoificationEnabled && ConfigData.isEnableNotifyIconFix)
|
||||
showDialog {
|
||||
title = "模块的通知权限已关闭"
|
||||
msg = "请开启通知权限,以确保你能收到通知图标优化在线规则的更新。"
|
||||
@@ -124,143 +143,208 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
if (isLowerAndroidR && modulePrefs.get(DataConst.IGNORED_ANDROID_VERSION_TO_LOW).not())
|
||||
if (isLowerAndroidR && ConfigData.isIgnoredAndroidVersionToLow.not())
|
||||
showDialog {
|
||||
title = "Android 版本过低"
|
||||
msg = "你当前使用的 Android 版本过低,模块的部分功能可能会发生问题," +
|
||||
"由于设备有限,无法逐一调试,若有好的建议可向我们贡献代码提交适配请求,建议在 Android 11 及以上版本中使用效果最佳。"
|
||||
confirmButton(text = "我知道了") { modulePrefs.put(DataConst.IGNORED_ANDROID_VERSION_TO_LOW, value = true) }
|
||||
"由于设备有限,无法逐一调试,若有好的建议可向我们贡献代码提交适配请求,建议在 Android 11 及以上版本中使用效果最佳。"
|
||||
confirmButton(text = "我知道了") { ConfigData.isIgnoredAndroidVersionToLow = true }
|
||||
noCancelable()
|
||||
}
|
||||
/** 推广、恰饭 */
|
||||
YukiPromoteTool.promote(context = this)
|
||||
ProjectPromote.show(activity = this, ModuleVersion.toString())
|
||||
}
|
||||
else ->
|
||||
showDialog {
|
||||
title = "模块没有激活"
|
||||
msg = "检测到模块没有激活,模块需要 Xposed 环境依赖," +
|
||||
"同时需要系统拥有 Root 权限," +
|
||||
"请自行查看本页面使用帮助与说明第二条。\n" +
|
||||
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
|
||||
"同时需要系统拥有 Root 权限," +
|
||||
"请自行查看本页面使用帮助与说明第二条。\n" +
|
||||
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
|
||||
confirmButton(text = "我知道了")
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
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) && 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() && isLowerAndroidR.not()
|
||||
binding.notifyIconForceAppIconItem.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)
|
||||
binding.notifyIconAutoSyncChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
|
||||
binding.moduleEnableSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE)
|
||||
binding.moduleEnableLogSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE_LOG)
|
||||
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
|
||||
binding.colorIconCompatSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT)
|
||||
binding.notifyIconFixSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
|
||||
binding.notifyIconForceAppIconSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON)
|
||||
binding.notifyIconFixNotifySwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY)
|
||||
binding.notifyIconAutoSyncSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
|
||||
binding.notifyIconCustomCornerSeekbar.progress = modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)
|
||||
binding.notifyIconCustomCornerText.text = "${modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)} dp"
|
||||
binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
binding.notifyIconAutoSyncText.text = notifyIconAutoSyncTime
|
||||
binding.moduleEnableSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_MODULE, b)
|
||||
binding.moduleEnableLogSwitch.isVisible = b
|
||||
binding.colorIconHookItem.isVisible = b
|
||||
binding.statusIconCountItem.isVisible = b && isLowerAndroidR.not()
|
||||
binding.notifyIconConfigItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.moduleEnableLogSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_MODULE_LOG, b)
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
ComponentName(this@MainActivity, "com.fankes.miui.notify.Home"),
|
||||
if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
binding.statusIconCountSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT, b)
|
||||
binding.statusIconCountChildItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.colorIconCompatSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_COLOR_ICON_COMPAT, b)
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
binding.notifyIconFixSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
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() && isLowerAndroidR.not()
|
||||
binding.notifyIconForceAppIconItem.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() && isLowerAndroidR.not()
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
I18nWarnTool.checkingOrShowing(context = this)
|
||||
if (isMIOS) binding.mainTitle.text = binding.mainTitle.text.toString().replace("MIUI", "HyperOS")
|
||||
binding.mainTextVersion.text = "模块版本:${ModuleVersion.NAME}"
|
||||
/** 设置 CI 自动构建标识 */
|
||||
if (ModuleVersion.isCiMode)
|
||||
binding.mainTextReleaseVersion.apply {
|
||||
text = "CI ${ModuleVersion.GITHUB_COMMIT_ID}"
|
||||
isVisible = true
|
||||
setOnClickListener {
|
||||
showDialog {
|
||||
title = "CI 自动构建说明"
|
||||
msg = """
|
||||
你正在使用的是 CI 自动构建版本,Commit ID 为 ${ModuleVersion.GITHUB_COMMIT_ID}。
|
||||
|
||||
它是由代码提交后自动触发并构建、自动编译发布的,并未经任何稳定性测试,使用风险自负。
|
||||
""".trimIndent()
|
||||
confirmButton(text = "我知道了")
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (b) showDialog {
|
||||
title = "破坏性功能警告"
|
||||
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
|
||||
binding.mainTextMiuiVersion.text = "系统版本:[$androidVersionCodeName] $systemFullVersion"
|
||||
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
|
||||
binding.warnMiuiNotifyStyleTip.isGone = miuiVersionCode > 11
|
||||
binding.statusIconCountText.text = ConfigData.liftedStatusIconCount.toString()
|
||||
binding.notifyIconAutoSyncText.text = ConfigData.notifyIconFixAutoTime
|
||||
binding.moduleEnableSwitch.bind(ConfigData.ENABLE_MODULE) {
|
||||
onInitialize {
|
||||
binding.moduleEnableLogItem.isVisible = it
|
||||
binding.colorIconHookItem.isVisible = it
|
||||
binding.statusIconCountItem.isVisible = isLowerAndroidR.not() && it
|
||||
binding.notifyStyleConfigItem.isVisible = it
|
||||
binding.notifyIconConfigItem.isVisible = it
|
||||
}
|
||||
onChanged {
|
||||
reinitialize()
|
||||
refreshModuleStatus()
|
||||
SystemUITool.showNeedRestartSnake(context = this@MainActivity)
|
||||
}
|
||||
}
|
||||
binding.moduleEnableLogSwitch.bind(ConfigData.ENABLE_MODULE_LOG) {
|
||||
onInitialize { binding.expAllDebugLogButton.isVisible = it }
|
||||
onChanged {
|
||||
reinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity, isRefreshCacheOnly = true)
|
||||
}
|
||||
}
|
||||
binding.statusIconCountSwitch.bind(ConfigData.ENABLE_LIFTED_STATUS_ICON_COUNT) {
|
||||
onInitialize { binding.statusIconCountChildItem.isVisible = it }
|
||||
onChanged {
|
||||
reinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity) { snake(msg = "设置将在新通知推送或状态栏刷新后自动生效") }
|
||||
}
|
||||
}
|
||||
binding.colorIconCompatSwitch.bind(ConfigData.ENABLE_COLOR_ICON_COMPAT) {
|
||||
isAutoApplyChanges = false
|
||||
onChanged {
|
||||
/** 应用更改并刷新系统界面 */
|
||||
fun applyChangesAndRefresh() {
|
||||
applyChanges()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity)
|
||||
}
|
||||
if (it) showDialog {
|
||||
title = "启用兼容模式"
|
||||
msg = "启用兼容模式可修复部分系统版本可能出现无法判定通知图标反色的问题," +
|
||||
"但是这也可能会导致新的问题,一般情况下不建议开启,确定要继续吗?\n\n" +
|
||||
"如果系统界面刷新后通知图标颜色发生错误,请尝试重启一次系统界面。"
|
||||
confirmButton { applyChangesAndRefresh() }
|
||||
cancelButton { cancelChanges() }
|
||||
noCancelable()
|
||||
} else applyChangesAndRefresh()
|
||||
}
|
||||
}
|
||||
binding.miuiNotifyIconReplacementSwitch.bind(ConfigData.ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON) {
|
||||
onChanged { SystemUITool.refreshSystemUI(context = this@MainActivity) }
|
||||
}
|
||||
binding.miuiFocusNotifyIconFixSwitch.bind(ConfigData.ENABLE_FOCUS_NOTIFICATION_FIX) {
|
||||
onChanged { SystemUITool.refreshSystemUI(context = this@MainActivity) }
|
||||
}
|
||||
binding.notifyIconForceSystemColorSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR) {
|
||||
isAutoApplyChanges = false
|
||||
onChanged {
|
||||
/** 应用更改并刷新系统界面 */
|
||||
fun applyChangesAndRefresh() {
|
||||
applyChangesAndReinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity)
|
||||
}
|
||||
if (it) showDialog {
|
||||
title = "破坏性功能警告"
|
||||
msg = "开启这个功能后,任何通知栏中的通知图标都会忽略图标自身的着色属性,全部使用系统默认颜色 (系统提供的统一色调) 着色。\n\n" +
|
||||
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
|
||||
confirmButton { applyChangesAndRefresh() }
|
||||
cancelButton { cancelChanges() }
|
||||
noCancelable()
|
||||
} else applyChangesAndRefresh()
|
||||
}
|
||||
}
|
||||
binding.notifyIconForceAppIconSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) {
|
||||
isAutoApplyChanges = false
|
||||
onInitialize {
|
||||
arrayOf(
|
||||
binding.notifyIconCustomCornerItem,
|
||||
binding.notifyIconForceSystemColorItem
|
||||
).forEach { e -> e.isVisible = isLowerAndroidR.not() && it.not() }
|
||||
binding.miuiNotifyIconReplacementItem.isVisible = it.not()
|
||||
}
|
||||
onChanged {
|
||||
/** 应用更改并刷新系统界面 */
|
||||
fun applyChangesAndRefresh() {
|
||||
applyChangesAndReinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity)
|
||||
}
|
||||
if (it) showDialog {
|
||||
title = "破坏性功能警告"
|
||||
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
|
||||
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
|
||||
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
|
||||
confirmButton { saveState() }
|
||||
cancelButton { btn.isChecked = btn.isChecked.not() }
|
||||
noCancelable()
|
||||
} else saveState()
|
||||
}
|
||||
binding.notifyIconFixNotifySwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY, b)
|
||||
SystemUITool.refreshSystemUI(context = this, isRefreshCacheOnly = true)
|
||||
}
|
||||
binding.notifyIconAutoSyncSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO, b)
|
||||
binding.notifyIconAutoSyncChildItem.isVisible = b
|
||||
SystemUITool.refreshSystemUI(context = this, isRefreshCacheOnly = true)
|
||||
}
|
||||
binding.notifyIconCustomCornerSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
binding.notifyIconCustomCornerText.text = "$progress dp"
|
||||
confirmButton { applyChangesAndRefresh() }
|
||||
cancelButton { cancelChanges() }
|
||||
noCancelable()
|
||||
} else applyChangesAndRefresh()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
modulePrefs.put(DataConst.NOTIFY_ICON_CORNER, seekBar.progress)
|
||||
}
|
||||
binding.notifyIconFixSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FIX) {
|
||||
onInitialize {
|
||||
binding.notifyIconFixButton.isVisible = it
|
||||
binding.notifyIconFixPlaceholderItem.isVisible = it
|
||||
binding.notifyIconFixNotifyItem.isVisible = it
|
||||
binding.notifyIconAutoSyncItem.isVisible = it
|
||||
}
|
||||
onChanged {
|
||||
reinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
|
||||
})
|
||||
}
|
||||
binding.notifyIconFixPlaceholderSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FIX_PLACEHOLDER) {
|
||||
isAutoApplyChanges = false
|
||||
onChanged {
|
||||
/** 应用更改并刷新系统界面 */
|
||||
fun applyChangesAndRefresh() {
|
||||
applyChanges()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity)
|
||||
}
|
||||
if (it) showDialog {
|
||||
title = "注意"
|
||||
msg = "开启这个功能后,当发现未适配的彩色通知图标时," +
|
||||
"状态栏中显示的通知图标将会使用预置的占位符图标进行修补," +
|
||||
"通知栏中显示的通知图标保持原始图标不变。\n\n" +
|
||||
"此功能的作用仅为临时修复破坏规范的通知图标,仍然继续开启吗?"
|
||||
confirmButton { applyChangesAndRefresh() }
|
||||
cancelButton { cancelChanges() }
|
||||
noCancelable()
|
||||
} else applyChangesAndRefresh()
|
||||
}
|
||||
}
|
||||
binding.notifyIconFixNotifySwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FIX_NOTIFY) {
|
||||
onChanged { SystemUITool.refreshSystemUI(context = this@MainActivity, isRefreshCacheOnly = true) }
|
||||
}
|
||||
binding.notifyIconAutoSyncSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FIX_AUTO) {
|
||||
onInitialize { binding.notifyIconAutoSyncChildItem.isVisible = it }
|
||||
onChanged {
|
||||
reinitialize()
|
||||
SystemUITool.refreshSystemUI(context = this@MainActivity, isRefreshCacheOnly = true)
|
||||
}
|
||||
}
|
||||
binding.statusDarkIconCustomAlphaSeekbar.bind(
|
||||
ConfigData.STATUS_ICON_DARK_ALPHA_LEVEL, binding.statusDarkIconCustomAlphaText, suffix = "%"
|
||||
) { SystemUITool.refreshSystemUI(context = this) }
|
||||
binding.statusLightIconCustomAlphaSeekbar.bind(
|
||||
ConfigData.STATUS_ICON_LIGHT_ALPHA_LEVEL, binding.statusLightIconCustomAlphaText, suffix = "%"
|
||||
) { SystemUITool.refreshSystemUI(context = this) }
|
||||
binding.notifyIconCustomCornerSeekbar.bind(ConfigData.NOTIFY_ICON_CORNER_SIZE, binding.notifyIconCustomCornerText, suffix = " dp") {
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
/** 导出全部日志按钮点击事件 */
|
||||
binding.expAllDebugLogButton.setOnClickListener { SystemUITool.obtainAndExportDebugLogs(context = this) }
|
||||
/** MIUI 通知显示设置按钮点击事件 */
|
||||
binding.miuiNotifyStyleButton.setOnClickListener { SystemUITool.openMiuiNotificationDisplaySettings(context = this) }
|
||||
/** 通知图标优化名单按钮点击事件 */
|
||||
binding.notifyIconFixButton.setOnClickListener { navigate<ConfigureActivity>() }
|
||||
/** 设置警告 */
|
||||
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
|
||||
/** 修改状态栏通知图标个数按钮点击事件 */
|
||||
binding.statusIconCountButton.setOnClickListener {
|
||||
showDialog<DiaStatusIconCountBinding> {
|
||||
@@ -268,18 +352,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
binding.iconCountEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
setText(statusBarIconCount.toString())
|
||||
setSelection(statusBarIconCount.toString().length)
|
||||
setText(ConfigData.liftedStatusIconCount.toString())
|
||||
setSelection(ConfigData.liftedStatusIconCount.toString().length)
|
||||
}
|
||||
confirmButton {
|
||||
when {
|
||||
(runCatching { binding.iconCountEdit.text.toString().toInt() }.getOrNull() ?: -1)
|
||||
!in 0..100 -> snake(msg = "请输入有效数值")
|
||||
!in 0..100 -> snake(msg = "请输入有效数值")
|
||||
binding.iconCountEdit.text.toString().isNotBlank() -> runCatching {
|
||||
statusBarIconCount = binding.iconCountEdit.text.toString().trim().toInt()
|
||||
modulePrefs.put(DataConst.HOOK_STATUS_ICON_COUNT, statusBarIconCount)
|
||||
this@MainActivity.binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
SystemUITool.showNeedRestartSnake(context)
|
||||
ConfigData.liftedStatusIconCount = binding.iconCountEdit.text.toString().trim().toInt()
|
||||
this@MainActivity.binding.statusIconCountText.text = ConfigData.liftedStatusIconCount.toString()
|
||||
SystemUITool.refreshSystemUI(context) { context.snake(msg = "设置将在新通知推送或状态栏刷新后自动生效") }
|
||||
}.onFailure { snake(msg = "数值格式无效") }
|
||||
else -> snake(msg = "请输入有效数值")
|
||||
}
|
||||
@@ -289,19 +372,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
}
|
||||
/** 自动更新在线规则修改时间按钮点击事件 */
|
||||
binding.notifyIconAutoSyncButton.setOnClickListener {
|
||||
showTimePicker(notifyIconAutoSyncTime) {
|
||||
showTimePicker(ConfigData.notifyIconFixAutoTime) {
|
||||
showDialog {
|
||||
title = "每天 $it 自动更新"
|
||||
msg = "设置保存后将在每天 $it 自动同步名单到最新云端数据,若数据已是最新则不会显示任何提示,否则会发送一条通知。\n\n" +
|
||||
"请确保:\n\n" +
|
||||
"1.模块没有被禁止前台以及后台联网权限\n" +
|
||||
"2.模块没有被禁止被其它 APP 关联唤醒\n" +
|
||||
"3.模块的系统通知权限已开启\n\n" +
|
||||
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
|
||||
"请确保:\n\n" +
|
||||
"1.模块没有被禁止前台以及后台联网权限\n" +
|
||||
"2.模块没有被禁止被其它 APP 关联唤醒\n" +
|
||||
"3.模块的系统通知权限已开启\n\n" +
|
||||
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
|
||||
confirmButton(text = "保存设置") {
|
||||
notifyIconAutoSyncTime = it
|
||||
ConfigData.notifyIconFixAutoTime = it
|
||||
this@MainActivity.binding.notifyIconAutoSyncText.text = it
|
||||
modulePrefs.put(DataConst.NOTIFY_ICON_FIX_AUTO_TIME, it)
|
||||
SystemUITool.refreshSystemUI(context, isRefreshCacheOnly = true)
|
||||
}
|
||||
cancelButton()
|
||||
@@ -312,38 +394,51 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
/** 重启按钮点击事件 */
|
||||
binding.titleRestartIcon.setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
||||
/** 项目地址按钮点击事件 */
|
||||
binding.titleGithubIcon.setOnClickListener { openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon") }
|
||||
binding.titleGithubIcon.setOnClickListener { openProjectUrl() }
|
||||
/** 恰饭! */
|
||||
binding.linkWithFollowMe.setOnClickListener {
|
||||
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
|
||||
}
|
||||
/** 设置桌面图标显示隐藏 */
|
||||
binding.hideIconInLauncherSwitch.isChecked = isLauncherIconShowing.not()
|
||||
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
hideOrShowLauncherIcon(b)
|
||||
}
|
||||
/** 注册导出调试日志启动器 */
|
||||
SystemUITool.registerExportDebugLogsLauncher(activity = this)
|
||||
}
|
||||
|
||||
/** 前往项目地址 */
|
||||
private fun openProjectUrl() {
|
||||
openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon")
|
||||
}
|
||||
|
||||
/** 刷新模块状态 */
|
||||
private fun refreshModuleStatus() {
|
||||
binding.mainLinStatus.setBackgroundResource(
|
||||
when {
|
||||
YukiHookAPI.Status.isXposedModuleActive && (isModuleRegular.not() || isModuleValied.not()) -> R.drawable.bg_yellow_round
|
||||
YukiHookAPI.Status.isXposedModuleActive &&
|
||||
(isModuleRegular.not() || isModuleValied.not() || ConfigData.isEnableModule.not()) -> R.drawable.bg_yellow_round
|
||||
YukiHookAPI.Status.isXposedModuleActive -> R.drawable.bg_green_round
|
||||
else -> R.drawable.bg_dark_round
|
||||
}
|
||||
)
|
||||
binding.mainImgStatus.setImageResource(
|
||||
when {
|
||||
YukiHookAPI.Status.isXposedModuleActive -> R.mipmap.ic_success
|
||||
else -> R.mipmap.ic_warn
|
||||
YukiHookAPI.Status.isXposedModuleActive && ConfigData.isEnableModule -> R.drawable.ic_success
|
||||
else -> R.drawable.ic_warn
|
||||
}
|
||||
)
|
||||
binding.mainTextStatus.text =
|
||||
when {
|
||||
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() && modulePrefs.get(DataConst.ENABLE_MODULE).not() -> "模块已停用"
|
||||
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
|
||||
YukiHookAPI.Status.isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
|
||||
YukiHookAPI.Status.isXposedModuleActive -> "模块已激活"
|
||||
else -> "模块未激活"
|
||||
}
|
||||
binding.mainTextStatus.text = when {
|
||||
YukiHookAPI.Status.isXposedModuleActive && ConfigData.isEnableModule.not() -> "模块已停用"
|
||||
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
|
||||
YukiHookAPI.Status.isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
|
||||
YukiHookAPI.Status.isXposedModuleActive -> "模块已激活"
|
||||
else -> "模块未激活"
|
||||
}
|
||||
binding.mainTextApiWay.isVisible = YukiHookAPI.Status.isXposedModuleActive
|
||||
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.executorName} API ${YukiHookAPI.Status.executorVersion}"
|
||||
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.Executor.name} API ${YukiHookAPI.Status.Executor.apiLevel}"
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/26.
|
||||
* This file is created by fankes on 2022/3/26.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.delayedRun
|
||||
import com.fankes.miui.notify.utils.tool.IconRuleManagerTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
|
||||
|
||||
class NotifyIconRuleUpdateActivity : Activity() {
|
||||
|
||||
@@ -49,7 +48,7 @@ class NotifyIconRuleUpdateActivity : Activity() {
|
||||
return
|
||||
}
|
||||
/** 拉取云端数据 */
|
||||
IconRuleManagerTool.sync(appContext) {
|
||||
IconRuleManagerTool.sync(context = this) {
|
||||
/** 刷新系统界面 */
|
||||
SystemUITool.refreshSystemUI()
|
||||
/** 结束当前窗口 */
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,22 +18,22 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/30.
|
||||
* This file is created by fankes on 2022/1/30.
|
||||
*/
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity.base
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import com.highcapable.kavaref.KavaRef.Companion.resolve
|
||||
import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
|
||||
import com.highcapable.kavaref.extension.toClassOrNull
|
||||
|
||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
@@ -49,15 +49,13 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
isMainThreadRunning = true
|
||||
javaClass.genericSuperclass.also { type ->
|
||||
if (type is ParameterizedType) {
|
||||
binding = (type.actualTypeArguments[0] as Class<VB>).method {
|
||||
name = "inflate"
|
||||
param(LayoutInflaterClass)
|
||||
}.get().invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||
setContentView(binding.root)
|
||||
} else error("binding but got wrong type")
|
||||
}
|
||||
val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
|
||||
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "inflate"
|
||||
parameters(LayoutInflater::class)
|
||||
}?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
||||
setContentView(binding.root)
|
||||
/** 隐藏系统的标题栏 */
|
||||
supportActionBar?.hide()
|
||||
/** 初始化沉浸状态栏 */
|
||||
@@ -65,6 +63,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
||||
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
||||
window?.statusBarColor = it
|
||||
window?.navigationBarColor = it
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,11 +18,11 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
* This file is created by fankes on 2022/1/8.
|
||||
*/
|
||||
@file:Suppress("SameParameterValue")
|
||||
|
||||
package com.fankes.miui.notify.ui.view
|
||||
package com.fankes.miui.notify.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
@@ -30,9 +30,9 @@ import android.graphics.Color
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import com.fankes.miui.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.miui.notify.utils.factory.dp
|
||||
import com.fankes.miui.notify.utils.factory.isSystemInDarkMode
|
||||
import top.defaults.drawabletoolbox.DrawableBuilder
|
||||
|
||||
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
|
||||
|
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
@file:Suppress("SameParameterValue")
|
||||
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.RippleDrawable
|
||||
import android.graphics.drawable.RotateDrawable
|
||||
import android.os.Build
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
|
||||
private val gradientState = resolveGradientState()
|
||||
|
||||
private fun resolveGradientState(): Class<*> {
|
||||
val classes = GradientDrawable::class.java.declaredClasses
|
||||
for (singleClass in classes) {
|
||||
if (singleClass.simpleName == "GradientState") return singleClass
|
||||
}
|
||||
throw RuntimeException("GradientState could not be found in thisAny GradientDrawable implementation")
|
||||
}
|
||||
|
||||
private val rotateState = resolveRotateState()
|
||||
|
||||
private fun resolveRotateState(): Class<*> {
|
||||
val classes = RotateDrawable::class.java.declaredClasses
|
||||
for (singleClass in classes) {
|
||||
if (singleClass.simpleName == "RotateState") return singleClass
|
||||
}
|
||||
throw RuntimeException("RotateState could not be found in thisAny RotateDrawable implementation")
|
||||
}
|
||||
|
||||
@Throws(SecurityException::class, NoSuchFieldException::class)
|
||||
private fun resolveField(source: Class<*>, fieldName: String): Field {
|
||||
val field = source.getDeclaredField(fieldName)
|
||||
field.isAccessible = true
|
||||
return field
|
||||
}
|
||||
|
||||
@Throws(SecurityException::class, NoSuchMethodException::class)
|
||||
private fun resolveMethod(
|
||||
source: Class<*>,
|
||||
methodName: String,
|
||||
vararg parameterTypes: Class<*>
|
||||
): Method {
|
||||
val method = source.getDeclaredMethod(methodName, *parameterTypes)
|
||||
method.isAccessible = true
|
||||
return method
|
||||
}
|
||||
|
||||
fun setInnerRadius(drawable: GradientDrawable, value: Int) {
|
||||
try {
|
||||
val innerRadius = resolveField(gradientState, "mInnerRadius")
|
||||
innerRadius.setInt(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setInnerRadiusRatio(drawable: GradientDrawable, value: Float) {
|
||||
try {
|
||||
val innerRadius = resolveField(gradientState, "mInnerRadiusRatio")
|
||||
innerRadius.setFloat(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setThickness(drawable: GradientDrawable, value: Int) {
|
||||
try {
|
||||
val innerRadius = resolveField(gradientState, "mThickness")
|
||||
innerRadius.setInt(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setThicknessRatio(drawable: GradientDrawable, value: Float) {
|
||||
try {
|
||||
val innerRadius = resolveField(gradientState, "mThicknessRatio")
|
||||
innerRadius.setFloat(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setUseLevelForShape(drawable: GradientDrawable, value: Boolean) {
|
||||
try {
|
||||
val useLevelForShape = resolveField(gradientState, "mUseLevelForShape")
|
||||
useLevelForShape.setBoolean(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
fun setOrientation(drawable: GradientDrawable, value: GradientDrawable.Orientation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
drawable.orientation = value
|
||||
} else {
|
||||
try {
|
||||
val orientation = resolveField(gradientState, "mOrientation")
|
||||
orientation.set(drawable.constantState, value)
|
||||
val rectIdDirty = resolveField(GradientDrawable::class.java, "mRectIsDirty")
|
||||
rectIdDirty.setBoolean(drawable, true)
|
||||
drawable.invalidateSelf()
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
fun setColors(drawable: GradientDrawable, value: IntArray) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
drawable.colors = value
|
||||
} else {
|
||||
try {
|
||||
val colors = resolveField(gradientState, "mColors")
|
||||
colors.set(drawable.constantState, value)
|
||||
drawable.invalidateSelf()
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setGradientRadiusType(drawable: GradientDrawable, value: Int) {
|
||||
try {
|
||||
val type = resolveField(gradientState, "mGradientRadiusType")
|
||||
type.setInt(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setGradientRadius(drawable: GradientDrawable, value: Float) {
|
||||
try {
|
||||
val gradientRadius = resolveField(gradientState, "mGradientRadius")
|
||||
gradientRadius.setFloat(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setStrokeColor(drawable: GradientDrawable, value: Int) {
|
||||
try {
|
||||
val type = resolveField(gradientState, "mStrokeColor")
|
||||
type.setInt(drawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setDrawable(rotateDrawable: RotateDrawable, drawable: Drawable) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
rotateDrawable.drawable = drawable
|
||||
} else {
|
||||
try {
|
||||
val drawableField = resolveField(rotateState, "mDrawable")
|
||||
val stateField = resolveField(RotateDrawable::class.java, "mState")
|
||||
drawableField.set(stateField.get(rotateDrawable), drawable)
|
||||
drawable.callback = rotateDrawable
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setPivotX(rotateDrawable: RotateDrawable, value: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
rotateDrawable.pivotX = value
|
||||
} else {
|
||||
try {
|
||||
val pivotXField = resolveField(rotateState, "mPivotX")
|
||||
pivotXField.setFloat(rotateDrawable.constantState, value)
|
||||
val pivotXRelField = resolveField(rotateState, "mPivotXRel")
|
||||
pivotXRelField.setBoolean(rotateDrawable.constantState, true)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setPivotY(rotateDrawable: RotateDrawable, value: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
rotateDrawable.pivotY = value
|
||||
} else {
|
||||
try {
|
||||
val pivotYField = resolveField(rotateState, "mPivotY")
|
||||
pivotYField.setFloat(rotateDrawable.constantState, value)
|
||||
val pivotYRelField = resolveField(rotateState, "mPivotYRel")
|
||||
pivotYRelField.setBoolean(rotateDrawable.constantState, true)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setFromDegrees(rotateDrawable: RotateDrawable, value: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
rotateDrawable.fromDegrees = value
|
||||
} else {
|
||||
try {
|
||||
val fromDegreesField = resolveField(rotateState, "mFromDegrees")
|
||||
fromDegreesField.setFloat(rotateDrawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setToDegrees(rotateDrawable: RotateDrawable, value: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
rotateDrawable.toDegrees = value
|
||||
} else {
|
||||
try {
|
||||
val toDegreesField = resolveField(rotateState, "mToDegrees")
|
||||
toDegreesField.setFloat(rotateDrawable.constantState, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setRadius(rippleDrawable: RippleDrawable, value: Int) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
rippleDrawable.radius = value
|
||||
} else {
|
||||
try {
|
||||
val setRadiusMethod =
|
||||
resolveMethod(RippleDrawable::class.java, "setMaxRadius", Int::class.java)
|
||||
setRadiusMethod.invoke(rippleDrawable, value)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
class Constants {
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_COLOR = 0xFFBA68C8.toInt()
|
||||
}
|
||||
}
|
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.StateSet
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class DrawableBuilder {
|
||||
|
||||
private var properties = DrawableProperties()
|
||||
private var order: AtomicInteger = AtomicInteger(1)
|
||||
private var transformsMap = TreeMap<Int, (Drawable) -> Drawable>()
|
||||
private var baseDrawable: Drawable? = null
|
||||
|
||||
fun batch(properties: DrawableProperties) = apply { this.properties = properties.copy() }
|
||||
fun baseDrawable(drawable: Drawable) = apply { baseDrawable = drawable }
|
||||
|
||||
// <shape>
|
||||
fun shape(shape: Int) = apply { properties.shape = shape }
|
||||
|
||||
fun rectangle() = apply { shape(GradientDrawable.RECTANGLE) }
|
||||
fun oval() = apply { shape(GradientDrawable.OVAL) }
|
||||
fun line() = apply { shape(GradientDrawable.LINE) }
|
||||
fun ring() = apply { shape(GradientDrawable.RING) }
|
||||
fun innerRadius(innerRadius: Int) = apply { properties.innerRadius = innerRadius }
|
||||
fun innerRadiusRatio(innerRadiusRatio: Float) =
|
||||
apply { properties.innerRadiusRatio = innerRadiusRatio }
|
||||
|
||||
fun thickness(thickness: Int) = apply { properties.thickness = thickness }
|
||||
fun thicknessRatio(thicknessRatio: Float) = apply { properties.thicknessRatio = thicknessRatio }
|
||||
|
||||
fun useLevelForRing(use: Boolean = true) = apply { properties.useLevelForRing = use }
|
||||
|
||||
// <corner>
|
||||
fun cornerRadius(cornerRadius: Int) = apply { properties.cornerRadius = cornerRadius }
|
||||
|
||||
fun topLeftRadius(topLeftRadius: Int) = apply { properties.topLeftRadius = topLeftRadius }
|
||||
fun topRightRadius(topRightRadius: Int) = apply { properties.topRightRadius = topRightRadius }
|
||||
fun bottomRightRadius(bottomRightRadius: Int) =
|
||||
apply { properties.bottomRightRadius = bottomRightRadius }
|
||||
|
||||
fun bottomLeftRadius(bottomLeftRadius: Int) =
|
||||
apply { properties.bottomLeftRadius = bottomLeftRadius }
|
||||
|
||||
fun rounded() = apply { cornerRadius(Int.MAX_VALUE) }
|
||||
fun cornerRadii(
|
||||
topLeftRadius: Int,
|
||||
topRightRadius: Int,
|
||||
bottomRightRadius: Int,
|
||||
bottomLeftRadius: Int
|
||||
) = apply {
|
||||
topLeftRadius(topLeftRadius); topRightRadius(topRightRadius); bottomRightRadius(
|
||||
bottomRightRadius
|
||||
); bottomLeftRadius(bottomLeftRadius)
|
||||
}
|
||||
|
||||
// <gradient>
|
||||
|
||||
fun gradient(useGradient: Boolean = true) = apply { properties.useGradient = useGradient }
|
||||
|
||||
fun gradientType(type: Int) = apply { properties.type = type }
|
||||
fun linearGradient() = apply { gradientType(GradientDrawable.LINEAR_GRADIENT) }
|
||||
fun radialGradient() = apply { gradientType(GradientDrawable.RADIAL_GRADIENT) }
|
||||
fun sweepGradient() = apply { gradientType(GradientDrawable.SWEEP_GRADIENT) }
|
||||
fun angle(angle: Int) = apply { properties.angle = angle }
|
||||
fun centerX(centerX: Float) = apply { properties.centerX = centerX }
|
||||
fun centerY(centerY: Float) = apply { properties.centerY = centerY }
|
||||
fun center(centerX: Float, centerY: Float) = apply { centerX(centerX); centerY(centerY) }
|
||||
|
||||
fun useCenterColor(useCenterColor: Boolean = true) =
|
||||
apply { properties.useCenterColor = useCenterColor }
|
||||
|
||||
fun startColor(startColor: Int) = apply { properties.startColor = startColor }
|
||||
fun centerColor(centerColor: Int) = apply {
|
||||
properties.centerColor = centerColor
|
||||
useCenterColor(true)
|
||||
}
|
||||
|
||||
fun endColor(endColor: Int) = apply { properties.endColor = endColor }
|
||||
fun gradientColors(startColor: Int, endColor: Int, centerColor: Int?) = apply {
|
||||
startColor(startColor); endColor(endColor)
|
||||
useCenterColor(centerColor != null)
|
||||
centerColor?.let {
|
||||
centerColor(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun gradientRadiusType(gradientRadiusType: Int) =
|
||||
apply { properties.gradientRadiusType = gradientRadiusType }
|
||||
|
||||
fun gradientRadius(gradientRadius: Float) = apply { properties.gradientRadius = gradientRadius }
|
||||
fun gradientRadius(radius: Float, type: Int) =
|
||||
apply { gradientRadius(radius); gradientRadiusType(type) }
|
||||
|
||||
fun gradientRadiusInPixel(radius: Float) =
|
||||
apply { gradientRadius(radius); gradientRadiusType(DrawableProperties.RADIUS_TYPE_PIXELS) }
|
||||
|
||||
fun gradientRadiusInFraction(radius: Float) =
|
||||
apply { gradientRadius(radius); gradientRadiusType(DrawableProperties.RADIUS_TYPE_FRACTION) }
|
||||
|
||||
fun useLevelForGradient(use: Boolean) = apply { properties.useLevelForGradient = use }
|
||||
fun useLevelForGradient() = apply { useLevelForGradient(true) }
|
||||
|
||||
// <size>
|
||||
fun width(width: Int) = apply { properties.width = width }
|
||||
|
||||
fun height(height: Int) = apply { properties.height = height }
|
||||
fun size(width: Int, height: Int) = apply { width(width); height(height) }
|
||||
fun size(size: Int) = apply { width(size).height(size) }
|
||||
|
||||
// <solid>
|
||||
fun solidColor(solidColor: Int) = apply { properties.solidColor = solidColor }
|
||||
|
||||
private var solidColorPressed: Int? = null
|
||||
fun solidColorPressed(color: Int?) = apply { solidColorPressed = color }
|
||||
private var solidColorPressedWhenRippleUnsupported: Int? = null
|
||||
fun solidColorPressedWhenRippleUnsupported(color: Int?) =
|
||||
apply { solidColorPressedWhenRippleUnsupported = color }
|
||||
|
||||
private var solidColorDisabled: Int? = null
|
||||
fun solidColorDisabled(color: Int?) = apply { solidColorDisabled = color }
|
||||
private var solidColorSelected: Int? = null
|
||||
fun solidColorSelected(color: Int?) = apply { solidColorSelected = color }
|
||||
fun solidColorStateList(colorStateList: ColorStateList) =
|
||||
apply { properties.solidColorStateList = colorStateList }
|
||||
|
||||
// <stroke>
|
||||
fun strokeWidth(strokeWidth: Int) = apply { properties.strokeWidth = strokeWidth }
|
||||
|
||||
fun strokeColor(strokeColor: Int) = apply { properties.strokeColor = strokeColor }
|
||||
private var strokeColorPressed: Int? = null
|
||||
fun strokeColorPressed(color: Int?) = apply { strokeColorPressed = color }
|
||||
private var strokeColorDisabled: Int? = null
|
||||
fun strokeColorDisabled(color: Int?) = apply { strokeColorDisabled = color }
|
||||
private var strokeColorSelected: Int? = null
|
||||
fun strokeColorSelected(color: Int?) = apply { strokeColorSelected = color }
|
||||
fun strokeColorStateList(colorStateList: ColorStateList) =
|
||||
apply { properties.strokeColorStateList = colorStateList }
|
||||
|
||||
fun dashWidth(dashWidth: Int) = apply { properties.dashWidth = dashWidth }
|
||||
fun dashGap(dashGap: Int) = apply { properties.dashGap = dashGap }
|
||||
fun hairlineBordered() = apply { strokeWidth(1) }
|
||||
fun shortDashed() = apply { dashWidth(12).dashGap(12) }
|
||||
fun mediumDashed() = apply { dashWidth(24).dashGap(24) }
|
||||
fun longDashed() = apply { dashWidth(36).dashGap(36) }
|
||||
fun dashed() = apply { mediumDashed() }
|
||||
|
||||
// <rotate>
|
||||
private var rotateOrder = 0
|
||||
|
||||
|
||||
fun rotate(boolean: Boolean = true) = apply {
|
||||
properties.useRotate = boolean
|
||||
rotateOrder = if (boolean) {
|
||||
order.getAndIncrement()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fun pivotX(pivotX: Float) = apply { properties.pivotX = pivotX }
|
||||
fun pivotY(pivotY: Float) = apply { properties.pivotY = pivotY }
|
||||
fun pivot(pivotX: Float, pivotY: Float) = apply { pivotX(pivotX).pivotY(pivotY) }
|
||||
fun fromDegrees(degrees: Float) = apply { properties.fromDegrees = degrees }
|
||||
fun toDegrees(degrees: Float) = apply { properties.toDegrees = degrees }
|
||||
fun degrees(fromDegrees: Float, toDegrees: Float) =
|
||||
apply { fromDegrees(fromDegrees).toDegrees(toDegrees) }
|
||||
|
||||
fun degrees(degrees: Float) = apply { fromDegrees(degrees).toDegrees(degrees) }
|
||||
fun rotate(fromDegrees: Float, toDegrees: Float) =
|
||||
apply { rotate().fromDegrees(fromDegrees).toDegrees(toDegrees) }
|
||||
|
||||
fun rotate(degrees: Float) = apply { rotate().degrees(degrees) }
|
||||
|
||||
// <scale>
|
||||
private var scaleOrder = 0
|
||||
|
||||
|
||||
fun scale(boolean: Boolean = true) = apply {
|
||||
properties.useScale = boolean
|
||||
scaleOrder = if (boolean) {
|
||||
order.getAndIncrement()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fun scaleLevel(level: Int) = apply { properties.scaleLevel = level }
|
||||
fun scaleGravity(gravity: Int) = apply { properties.scaleGravity = gravity }
|
||||
fun scaleWidth(scale: Float) = apply { properties.scaleWidth = scale }
|
||||
fun scaleHeight(scale: Float) = apply { properties.scaleHeight = scale }
|
||||
fun scale(scale: Float) = apply { scale().scaleWidth(scale).scaleHeight(scale) }
|
||||
fun scale(scaleWidth: Float, scaleHeight: Float) =
|
||||
apply { scale().scaleWidth(scaleWidth).scaleHeight(scaleHeight) }
|
||||
|
||||
// flip
|
||||
|
||||
fun flip(boolean: Boolean = true) = apply { properties.useFlip = boolean }
|
||||
|
||||
fun orientation(orientation: Int) = apply { properties.orientation = orientation }
|
||||
fun flipVertical() = apply { flip().orientation(FlipDrawable.ORIENTATION_VERTICAL) }
|
||||
|
||||
// <ripple>
|
||||
|
||||
fun ripple(boolean: Boolean = true) = apply { properties.useRipple = boolean }
|
||||
|
||||
fun rippleColor(color: Int) = apply { properties.rippleColor = color }
|
||||
fun rippleColorStateList(colorStateList: ColorStateList) =
|
||||
apply { properties.rippleColorStateList = colorStateList }
|
||||
|
||||
fun rippleRadius(radius: Int) = apply { properties.rippleRadius = radius }
|
||||
|
||||
fun build(): Drawable {
|
||||
if (baseDrawable != null) {
|
||||
return wrap(baseDrawable!!)
|
||||
}
|
||||
|
||||
var drawable: Drawable
|
||||
|
||||
// fall back when ripple is unavailable on devices with API < 21
|
||||
if (shouldFallbackRipple()) {
|
||||
if (solidColorPressedWhenRippleUnsupported != null) {
|
||||
solidColorPressed(solidColorPressedWhenRippleUnsupported)
|
||||
} else {
|
||||
solidColorPressed(properties.rippleColor)
|
||||
}
|
||||
}
|
||||
|
||||
if (needStateListDrawable()) {
|
||||
drawable = StateListDrawableBuilder()
|
||||
.pressed(buildPressedDrawable())
|
||||
.disabled(buildDisabledDrawable())
|
||||
.selected(buildSelectedDrawable())
|
||||
.normal(buildNormalDrawable())
|
||||
.build()
|
||||
} else {
|
||||
drawable = GradientDrawable()
|
||||
setupGradientDrawable(drawable)
|
||||
}
|
||||
drawable = wrap(drawable)
|
||||
return drawable
|
||||
}
|
||||
|
||||
private fun getSolidColorStateList(): ColorStateList {
|
||||
if (properties.solidColorStateList != null) {
|
||||
return properties.solidColorStateList!!
|
||||
}
|
||||
|
||||
val states = mutableListOf<IntArray>()
|
||||
val colors = mutableListOf<Int>()
|
||||
|
||||
solidColorPressed?.let {
|
||||
states.add(intArrayOf(android.R.attr.state_pressed))
|
||||
colors.add(it)
|
||||
}
|
||||
solidColorDisabled?.let {
|
||||
states.add(intArrayOf(-android.R.attr.state_enabled))
|
||||
colors.add(it)
|
||||
}
|
||||
solidColorSelected?.let {
|
||||
states.add(intArrayOf(android.R.attr.state_selected))
|
||||
colors.add(it)
|
||||
}
|
||||
states.add(StateSet.WILD_CARD)
|
||||
colors.add(properties.solidColor)
|
||||
|
||||
return ColorStateList(states.toTypedArray(), colors.toIntArray())
|
||||
}
|
||||
|
||||
private fun getStrokeColorStateList(): ColorStateList {
|
||||
if (properties.strokeColorStateList != null) {
|
||||
return properties.strokeColorStateList!!
|
||||
}
|
||||
|
||||
val states = mutableListOf<IntArray>()
|
||||
val colors = mutableListOf<Int>()
|
||||
|
||||
strokeColorPressed?.let {
|
||||
states.add(intArrayOf(android.R.attr.state_pressed))
|
||||
colors.add(it)
|
||||
}
|
||||
strokeColorDisabled?.let {
|
||||
states.add(intArrayOf(-android.R.attr.state_enabled))
|
||||
colors.add(it)
|
||||
}
|
||||
strokeColorSelected?.let {
|
||||
states.add(intArrayOf(android.R.attr.state_selected))
|
||||
colors.add(it)
|
||||
}
|
||||
states.add(StateSet.WILD_CARD)
|
||||
colors.add(properties.strokeColor)
|
||||
|
||||
return ColorStateList(states.toTypedArray(), colors.toIntArray())
|
||||
}
|
||||
|
||||
private fun buildPressedDrawable(): Drawable? {
|
||||
if (solidColorPressed == null && strokeColorPressed == null) return null
|
||||
|
||||
val pressedDrawable = GradientDrawable()
|
||||
setupGradientDrawable(pressedDrawable)
|
||||
solidColorPressed?.let {
|
||||
pressedDrawable.setColor(it)
|
||||
}
|
||||
strokeColorPressed?.let {
|
||||
setStrokeColor(pressedDrawable, it)
|
||||
}
|
||||
return pressedDrawable
|
||||
}
|
||||
|
||||
private fun buildDisabledDrawable(): Drawable? {
|
||||
if (solidColorDisabled == null && strokeColorDisabled == null) return null
|
||||
|
||||
val disabledDrawable = GradientDrawable()
|
||||
setupGradientDrawable(disabledDrawable)
|
||||
solidColorDisabled?.let {
|
||||
disabledDrawable.setColor(it)
|
||||
}
|
||||
strokeColorDisabled?.let {
|
||||
setStrokeColor(disabledDrawable, it)
|
||||
}
|
||||
return disabledDrawable
|
||||
}
|
||||
|
||||
private fun buildSelectedDrawable(): Drawable? {
|
||||
if (solidColorSelected == null && strokeColorSelected == null) return null
|
||||
|
||||
val selectedDrawable = GradientDrawable()
|
||||
setupGradientDrawable(selectedDrawable)
|
||||
solidColorSelected?.let {
|
||||
selectedDrawable.setColor(it)
|
||||
}
|
||||
strokeColorSelected?.let {
|
||||
setStrokeColor(selectedDrawable, it)
|
||||
}
|
||||
return selectedDrawable
|
||||
}
|
||||
|
||||
private fun buildNormalDrawable(): Drawable {
|
||||
val pressedDrawable = GradientDrawable()
|
||||
setupGradientDrawable(pressedDrawable)
|
||||
return pressedDrawable
|
||||
}
|
||||
|
||||
private fun setupGradientDrawable(drawable: GradientDrawable) {
|
||||
properties.apply {
|
||||
drawable.shape = shape
|
||||
if (shape == GradientDrawable.RING) {
|
||||
setInnerRadius(drawable, innerRadius)
|
||||
setInnerRadiusRatio(drawable, innerRadiusRatio)
|
||||
setThickness(drawable, thickness)
|
||||
setThicknessRatio(drawable, thicknessRatio)
|
||||
setUseLevelForShape(drawable, useLevelForRing)
|
||||
}
|
||||
drawable.cornerRadii = getCornerRadii()
|
||||
if (useGradient) {
|
||||
drawable.gradientType = type
|
||||
setGradientRadiusType(drawable, gradientRadiusType)
|
||||
setGradientRadius(drawable, gradientRadius)
|
||||
drawable.setGradientCenter(centerX, centerY)
|
||||
setOrientation(drawable, getOrientation())
|
||||
setColors(drawable, getColors())
|
||||
drawable.useLevel = useLevelForGradient
|
||||
} else {
|
||||
drawable.color = getSolidColorStateList()
|
||||
}
|
||||
drawable.setSize(width, height)
|
||||
drawable.setStroke(
|
||||
strokeWidth,
|
||||
getStrokeColorStateList(),
|
||||
dashWidth.toFloat(),
|
||||
dashGap.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun needStateListDrawable(): Boolean {
|
||||
return (hasStrokeColorStateList() || (!properties.useGradient && hasSolidColorStateList()))
|
||||
}
|
||||
|
||||
private fun needRotateDrawable(): Boolean {
|
||||
return properties.useRotate &&
|
||||
!(properties.pivotX == 0.5f && properties.pivotY == 0.5f
|
||||
&& properties.fromDegrees == 0f && properties.toDegrees == 0f)
|
||||
}
|
||||
|
||||
private fun needScaleDrawable(): Boolean {
|
||||
return properties.useScale
|
||||
}
|
||||
|
||||
private fun wrap(drawable: Drawable): Drawable {
|
||||
var wrappedDrawable = drawable
|
||||
|
||||
if (rotateOrder > 0) {
|
||||
transformsMap[rotateOrder] = ::wrapRotateIfNeeded
|
||||
}
|
||||
if (scaleOrder > 0) {
|
||||
transformsMap[scaleOrder] = ::wrapScaleIfNeeded
|
||||
}
|
||||
|
||||
for (action in transformsMap.values) {
|
||||
wrappedDrawable = action.invoke(wrappedDrawable)
|
||||
}
|
||||
|
||||
if (properties.useFlip) {
|
||||
wrappedDrawable = FlipDrawableBuilder()
|
||||
.drawable(wrappedDrawable)
|
||||
.orientation(properties.orientation)
|
||||
.build()
|
||||
}
|
||||
|
||||
if (isRippleSupported() && properties.useRipple) {
|
||||
wrappedDrawable = RippleDrawableBuilder()
|
||||
.drawable(wrappedDrawable)
|
||||
.color(properties.rippleColor)
|
||||
.colorStateList(properties.rippleColorStateList)
|
||||
.radius(properties.rippleRadius)
|
||||
.build()
|
||||
}
|
||||
|
||||
return wrappedDrawable
|
||||
}
|
||||
|
||||
private fun shouldFallbackRipple(): Boolean {
|
||||
return properties.useRipple && !isRippleSupported()
|
||||
}
|
||||
|
||||
private fun isRippleSupported() = true
|
||||
|
||||
private fun wrapRotateIfNeeded(drawable: Drawable): Drawable {
|
||||
if (!needRotateDrawable()) return drawable
|
||||
|
||||
with(properties) {
|
||||
return RotateDrawableBuilder()
|
||||
.drawable(drawable)
|
||||
.pivotX(pivotX)
|
||||
.pivotY(pivotY)
|
||||
.fromDegrees(fromDegrees)
|
||||
.toDegrees(toDegrees)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapScaleIfNeeded(drawable: Drawable): Drawable {
|
||||
if (!needScaleDrawable()) return drawable
|
||||
|
||||
with(properties) {
|
||||
return ScaleDrawableBuilder()
|
||||
.drawable(drawable)
|
||||
.level(scaleLevel)
|
||||
.scaleGravity(scaleGravity)
|
||||
.scaleWidth(scaleWidth)
|
||||
.scaleHeight(scaleHeight)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasSolidColorStateList(): Boolean {
|
||||
return solidColorPressed != null || solidColorDisabled != null || solidColorSelected != null
|
||||
}
|
||||
|
||||
private fun hasStrokeColorStateList(): Boolean {
|
||||
return strokeColorPressed != null || strokeColorDisabled != null || strokeColorSelected != null
|
||||
}
|
||||
}
|
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
@file:Suppress("SetterBackingFieldAssignment", "unused")
|
||||
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.view.Gravity
|
||||
import java.io.Serializable
|
||||
|
||||
data class DrawableProperties(
|
||||
|
||||
// <shape>
|
||||
@JvmField var shape: Int = GradientDrawable.RECTANGLE,
|
||||
@JvmField var innerRadius: Int = -1,
|
||||
@JvmField var innerRadiusRatio: Float = 9f,
|
||||
@JvmField var thickness: Int = -1,
|
||||
@JvmField var thicknessRatio: Float = 3f,
|
||||
@JvmField var useLevelForRing: Boolean = false,
|
||||
|
||||
// <corner>
|
||||
private var _cornerRadius: Int = 0,
|
||||
@JvmField var topLeftRadius: Int = 0,
|
||||
@JvmField var topRightRadius: Int = 0,
|
||||
@JvmField var bottomRightRadius: Int = 0,
|
||||
@JvmField var bottomLeftRadius: Int = 0,
|
||||
|
||||
// <gradient>
|
||||
@JvmField var useGradient: Boolean = false,
|
||||
@JvmField var type: Int = GradientDrawable.RADIAL_GRADIENT,
|
||||
@JvmField var angle: Int = 0,
|
||||
@JvmField var centerX: Float = 0.5f,
|
||||
@JvmField var centerY: Float = 0.5f,
|
||||
@JvmField var useCenterColor: Boolean = false,
|
||||
@JvmField var startColor: Int = Constants.DEFAULT_COLOR,
|
||||
@JvmField var centerColor: Int? = null,
|
||||
@JvmField var endColor: Int = 0x7FFFFFFF,
|
||||
@JvmField var gradientRadiusType: Int = RADIUS_TYPE_FRACTION,
|
||||
@JvmField var gradientRadius: Float = 0.5f,
|
||||
@JvmField var useLevelForGradient: Boolean = false,
|
||||
|
||||
// <size>
|
||||
@JvmField var width: Int = -1,
|
||||
@JvmField var height: Int = -1,
|
||||
|
||||
// <solid>
|
||||
@JvmField var solidColor: Int = Color.TRANSPARENT,
|
||||
@JvmField var solidColorStateList: ColorStateList? = null,
|
||||
|
||||
// <stroke>
|
||||
@JvmField var strokeWidth: Int = 0,
|
||||
@JvmField var strokeColor: Int = Color.DKGRAY,
|
||||
@JvmField var strokeColorStateList: ColorStateList? = null,
|
||||
@JvmField var dashWidth: Int = 0,
|
||||
@JvmField var dashGap: Int = 0,
|
||||
|
||||
// <rotate>
|
||||
@JvmField var useRotate: Boolean = false,
|
||||
@JvmField var pivotX: Float = 0.5f,
|
||||
@JvmField var pivotY: Float = 0.5f,
|
||||
@JvmField var fromDegrees: Float = 0f,
|
||||
@JvmField var toDegrees: Float = 0f,
|
||||
|
||||
// <scale>
|
||||
@JvmField var useScale: Boolean = false,
|
||||
@JvmField var scaleLevel: Int = 10000,
|
||||
@JvmField var scaleGravity: Int = Gravity.CENTER,
|
||||
@JvmField var scaleWidth: Float = 0f,
|
||||
@JvmField var scaleHeight: Float = 0f,
|
||||
|
||||
// flip
|
||||
@JvmField var useFlip: Boolean = false,
|
||||
@JvmField var orientation: Int = FlipDrawable.ORIENTATION_HORIZONTAL,
|
||||
|
||||
// ripple
|
||||
@JvmField var useRipple: Boolean = false,
|
||||
@JvmField var rippleColor: Int = Constants.DEFAULT_COLOR,
|
||||
@JvmField var rippleColorStateList: ColorStateList? = null,
|
||||
@JvmField var rippleRadius: Int = -1
|
||||
) : Serializable {
|
||||
|
||||
companion object {
|
||||
const val RADIUS_TYPE_PIXELS = 0
|
||||
const val RADIUS_TYPE_FRACTION = 1
|
||||
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<DrawableProperties> {
|
||||
override fun createFromParcel(parcel: Parcel): DrawableProperties {
|
||||
return DrawableProperties(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<DrawableProperties?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cornerRadius: Int = _cornerRadius
|
||||
set(value) {
|
||||
_cornerRadius = value
|
||||
topLeftRadius = value
|
||||
topRightRadius = value
|
||||
bottomRightRadius = value
|
||||
bottomLeftRadius = value
|
||||
}
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readFloat(),
|
||||
parcel.readInt(),
|
||||
parcel.readFloat(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readFloat(),
|
||||
parcel.readFloat(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readFloat(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readParcelable(ColorStateList::class.java.classLoader),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readParcelable(ColorStateList::class.java.classLoader),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readFloat(),
|
||||
parcel.readFloat(),
|
||||
parcel.readFloat(),
|
||||
parcel.readFloat(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readInt(),
|
||||
parcel.readFloat(),
|
||||
parcel.readFloat(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readByte() != 0.toByte(),
|
||||
parcel.readInt(),
|
||||
parcel.readParcelable(ColorStateList::class.java.classLoader),
|
||||
parcel.readInt()
|
||||
)
|
||||
|
||||
fun copy(): DrawableProperties {
|
||||
val parcel = Parcel.obtain()
|
||||
parcel.setDataPosition(0)
|
||||
val properties = CREATOR.createFromParcel(parcel)
|
||||
parcel.recycle()
|
||||
return properties
|
||||
}
|
||||
|
||||
fun getCornerRadii(): FloatArray {
|
||||
return floatArrayOf(
|
||||
topLeftRadius.toFloat(), topLeftRadius.toFloat(),
|
||||
topRightRadius.toFloat(), topRightRadius.toFloat(),
|
||||
bottomRightRadius.toFloat(), bottomRightRadius.toFloat(),
|
||||
bottomLeftRadius.toFloat(), bottomLeftRadius.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
fun getOrientation(): GradientDrawable.Orientation {
|
||||
val orientation: GradientDrawable.Orientation = when (val angle = this.angle % 360) {
|
||||
0 -> GradientDrawable.Orientation.LEFT_RIGHT
|
||||
45 -> GradientDrawable.Orientation.BL_TR
|
||||
90 -> GradientDrawable.Orientation.BOTTOM_TOP
|
||||
135 -> GradientDrawable.Orientation.BR_TL
|
||||
180 -> GradientDrawable.Orientation.RIGHT_LEFT
|
||||
225 -> GradientDrawable.Orientation.TR_BL
|
||||
270 -> GradientDrawable.Orientation.TOP_BOTTOM
|
||||
315 -> GradientDrawable.Orientation.TL_BR
|
||||
else -> throw IllegalArgumentException("Unsupported angle: $angle")
|
||||
}
|
||||
return orientation
|
||||
}
|
||||
|
||||
fun getColors(): IntArray {
|
||||
return if (useCenterColor && centerColor != null) {
|
||||
intArrayOf(startColor, centerColor!!, endColor)
|
||||
} else intArrayOf(startColor, endColor)
|
||||
}
|
||||
|
||||
fun materialization(): Drawable = DrawableBuilder().batch(this).build()
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "CanvasSize", "OVERRIDE_DEPRECATION")
|
||||
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
class FlipDrawable(
|
||||
private var drawable: Drawable,
|
||||
private var orientation: Int = ORIENTATION_HORIZONTAL
|
||||
) : Drawable() {
|
||||
|
||||
companion object {
|
||||
const val ORIENTATION_HORIZONTAL = 0
|
||||
const val ORIENTATION_VERTICAL = 1
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
val saveCount = canvas.save()
|
||||
if (orientation == ORIENTATION_VERTICAL) {
|
||||
canvas.scale(1f, -1f, (canvas.width / 2).toFloat(), (canvas.height / 2).toFloat())
|
||||
} else {
|
||||
canvas.scale(-1f, 1f, (canvas.width / 2).toFloat(), (canvas.height / 2).toFloat())
|
||||
}
|
||||
drawable.bounds = Rect(0, 0, canvas.width, canvas.height)
|
||||
drawable.draw(canvas)
|
||||
canvas.restoreToCount(saveCount)
|
||||
}
|
||||
|
||||
override fun onLevelChange(level: Int): Boolean {
|
||||
drawable.level = level
|
||||
invalidateSelf()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getIntrinsicWidth(): Int {
|
||||
return drawable.intrinsicWidth
|
||||
}
|
||||
|
||||
override fun getIntrinsicHeight(): Int {
|
||||
return drawable.intrinsicHeight
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Int) {
|
||||
drawable.alpha = alpha
|
||||
}
|
||||
|
||||
override fun getOpacity(): Int {
|
||||
return drawable.opacity
|
||||
}
|
||||
|
||||
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||
drawable.colorFilter = colorFilter
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
class FlipDrawableBuilder : DrawableWrapperBuilder<FlipDrawableBuilder>() {
|
||||
|
||||
private var orientation: Int = FlipDrawable.ORIENTATION_HORIZONTAL
|
||||
|
||||
fun orientation(orientation: Int) = apply { this.orientation = orientation }
|
||||
|
||||
override fun build(): Drawable {
|
||||
return FlipDrawable(drawable!!, orientation)
|
||||
}
|
||||
}
|
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.view.Gravity
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.util.*
|
||||
|
||||
class LayerDrawableBuilder {
|
||||
|
||||
companion object {
|
||||
const val DIMEN_UNDEFINED = Int.MIN_VALUE
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private var paddingMode = LayerDrawable.PADDING_MODE_NEST
|
||||
private var paddingLeft = 0
|
||||
private var paddingTop = 0
|
||||
private var paddingRight = 0
|
||||
private var paddingBottom = 0
|
||||
private var paddingStart = 0
|
||||
private var paddingEnd = 0
|
||||
private val layers = ArrayList<Layer>()
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
fun paddingMode(mode: Int) = apply { paddingMode = mode }
|
||||
fun paddingLeft(padding: Int) = apply { paddingLeft = padding }
|
||||
fun paddingTop(padding: Int) = apply { paddingTop = padding }
|
||||
fun paddingRight(padding: Int) = apply { paddingRight = padding }
|
||||
fun paddingBottom(padding: Int) = apply { paddingBottom = padding }
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun paddingStart(padding: Int) = apply { paddingStart = padding }
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun paddingEnd(padding: Int) = apply { paddingEnd = padding }
|
||||
fun padding(padding: Int) = apply {
|
||||
paddingLeft(padding).paddingTop(padding).paddingRight(padding).paddingBottom(padding)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun paddingRelative(padding: Int) = apply {
|
||||
paddingStart(padding).paddingTop(padding).paddingEnd(padding).paddingBottom(padding)
|
||||
}
|
||||
|
||||
fun add(drawable: Drawable) = apply { layers.add(Layer(drawable)) }
|
||||
|
||||
fun width(width: Int) = apply { layers.last().width = width }
|
||||
fun height(height: Int) = apply { layers.last().height = height }
|
||||
|
||||
fun insetLeft(inset: Int) = apply { layers.last().insetLeft = inset }
|
||||
fun insetTop(inset: Int) = apply { layers.last().insetTop = inset }
|
||||
fun insetRight(inset: Int) = apply { layers.last().insetRight = inset }
|
||||
fun insetBottom(inset: Int) = apply { layers.last().insetBottom = inset }
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun insetStart(inset: Int) = apply { layers.last().insetStart = inset }
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun insetEnd(inset: Int) = apply { layers.last().insetEnd = inset }
|
||||
fun inset(inset: Int) =
|
||||
apply { insetLeft(inset).insetTop(inset).insetRight(inset).insetBottom(inset) }
|
||||
|
||||
fun inset(insetLeft: Int, insetTop: Int, insetRight: Int, insetBottom: Int) = apply {
|
||||
insetLeft(insetLeft).insetTop(insetTop).insetRight(insetRight).insetBottom(insetBottom)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun insetRelative(inset: Int) =
|
||||
apply { insetStart(inset).insetTop(inset).insetEnd(inset).insetBottom(inset) }
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun insetRelative(insetStart: Int, insetTop: Int, insetEnd: Int, insetBottom: Int) = apply {
|
||||
insetStart(insetStart).insetTop(insetTop).insetEnd(insetEnd).insetBottom(insetBottom)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun gravity(gravity: Int) = apply { layers.last().gravity = gravity }
|
||||
|
||||
fun modify(
|
||||
index: Int, drawable: Drawable,
|
||||
width: Int = DIMEN_UNDEFINED,
|
||||
height: Int = DIMEN_UNDEFINED,
|
||||
insetLeft: Int = DIMEN_UNDEFINED,
|
||||
insetTop: Int = DIMEN_UNDEFINED,
|
||||
insetRight: Int = DIMEN_UNDEFINED,
|
||||
insetBottom: Int = DIMEN_UNDEFINED,
|
||||
insetStart: Int = DIMEN_UNDEFINED,
|
||||
insetEnd: Int = DIMEN_UNDEFINED
|
||||
) =
|
||||
apply {
|
||||
val layer = layers[index]
|
||||
layer.drawable = drawable
|
||||
if (width != DIMEN_UNDEFINED) layer.width = width
|
||||
if (height != DIMEN_UNDEFINED) layer.height = height
|
||||
if (insetLeft != DIMEN_UNDEFINED) layer.insetLeft = insetLeft
|
||||
if (insetTop != DIMEN_UNDEFINED) layer.insetTop = insetTop
|
||||
if (insetRight != DIMEN_UNDEFINED) layer.insetRight = insetRight
|
||||
if (insetBottom != DIMEN_UNDEFINED) layer.insetBottom = insetBottom
|
||||
if (insetStart != DIMEN_UNDEFINED) layer.insetStart = insetStart
|
||||
if (insetEnd != DIMEN_UNDEFINED) layer.insetEnd = insetEnd
|
||||
}
|
||||
|
||||
fun build(): LayerDrawable {
|
||||
val layerDrawable = LayerDrawable(layers.map { it -> it.drawable }.toTypedArray())
|
||||
for (i in 0 until layers.size) {
|
||||
val layer = layers[i]
|
||||
layerDrawable.setLayerInset(
|
||||
i,
|
||||
layer.insetLeft,
|
||||
layer.insetTop,
|
||||
layer.insetRight,
|
||||
layer.insetBottom
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (layer.insetStart != DIMEN_UNDEFINED || layer.insetEnd != DIMEN_UNDEFINED) {
|
||||
layerDrawable.setLayerInsetRelative(
|
||||
i,
|
||||
layer.insetStart,
|
||||
layer.insetTop,
|
||||
layer.insetEnd,
|
||||
layer.insetBottom
|
||||
)
|
||||
}
|
||||
}
|
||||
layerDrawable.setId(i, i)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
layerDrawable.setLayerGravity(i, layer.gravity)
|
||||
layerDrawable.setLayerInsetStart(i, layer.insetStart)
|
||||
layerDrawable.setLayerInsetEnd(i, layer.insetEnd)
|
||||
}
|
||||
}
|
||||
layerDrawable.paddingMode = paddingMode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
layerDrawable.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
|
||||
if (paddingStart != DIMEN_UNDEFINED || paddingEnd != DIMEN_UNDEFINED) {
|
||||
layerDrawable.setPaddingRelative(
|
||||
paddingStart,
|
||||
paddingTop,
|
||||
paddingEnd,
|
||||
paddingBottom
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return layerDrawable
|
||||
}
|
||||
|
||||
internal class Layer(var drawable: Drawable) {
|
||||
var gravity: Int = Gravity.NO_GRAVITY
|
||||
var width: Int = -1
|
||||
var height: Int = -1
|
||||
var insetLeft: Int = 0
|
||||
var insetTop: Int = 0
|
||||
var insetRight: Int = 0
|
||||
var insetBottom: Int = 0
|
||||
var insetStart: Int = DIMEN_UNDEFINED
|
||||
var insetEnd: Int = DIMEN_UNDEFINED
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.Path
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.PathShape
|
||||
|
||||
class PathShapeDrawableBuilder {
|
||||
|
||||
private var path: Path? = null
|
||||
private var pathStandardWidth: Float = 100f
|
||||
private var pathStandardHeight: Float = 100f
|
||||
private var width: Int = -1
|
||||
private var height: Int = -1
|
||||
|
||||
fun path(path: Path, pathStandardWidth: Float, pathStandardHeight: Float) = apply {
|
||||
this.path = path
|
||||
this.pathStandardWidth = pathStandardWidth
|
||||
this.pathStandardHeight = pathStandardHeight
|
||||
}
|
||||
|
||||
fun width(width: Int) = apply { this.width = width }
|
||||
fun height(height: Int) = apply { this.height = height }
|
||||
fun size(size: Int) = apply { width(size).height(size) }
|
||||
|
||||
fun build(custom: ((shapeDrawable: ShapeDrawable) -> Unit)? = null): ShapeDrawable {
|
||||
val shapeDrawable = ShapeDrawable()
|
||||
if (path == null || width <= 0 || height <= 0) {
|
||||
return shapeDrawable
|
||||
}
|
||||
val pathShape = PathShape(path!!, pathStandardWidth, pathStandardHeight)
|
||||
|
||||
shapeDrawable.shape = pathShape
|
||||
shapeDrawable.intrinsicWidth = width
|
||||
shapeDrawable.intrinsicHeight = height
|
||||
if (custom != null) {
|
||||
custom(shapeDrawable)
|
||||
}
|
||||
return shapeDrawable
|
||||
}
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.*
|
||||
import android.util.StateSet
|
||||
|
||||
class RippleDrawableBuilder : DrawableWrapperBuilder<RippleDrawableBuilder>() {
|
||||
|
||||
private var color: Int = Constants.DEFAULT_COLOR
|
||||
private var colorStateList: ColorStateList? = null
|
||||
private var radius: Int = -1
|
||||
|
||||
fun color(color: Int) = apply { this.color = color }
|
||||
fun colorStateList(colorStateList: ColorStateList?) =
|
||||
apply { this.colorStateList = colorStateList }
|
||||
|
||||
fun radius(radius: Int) = apply { this.radius = radius }
|
||||
|
||||
override fun build(): Drawable {
|
||||
var drawable = this.drawable!!
|
||||
val colorStateList = this.colorStateList ?: ColorStateList(
|
||||
arrayOf(StateSet.WILD_CARD),
|
||||
intArrayOf(color)
|
||||
)
|
||||
|
||||
var mask = if (drawable is DrawableContainer) drawable.getCurrent() else drawable
|
||||
if (mask is ShapeDrawable) {
|
||||
val state = mask.getConstantState()
|
||||
if (state != null) {
|
||||
val temp = state.newDrawable().mutate() as ShapeDrawable
|
||||
temp.paint.color = Color.BLACK
|
||||
mask = temp
|
||||
}
|
||||
} else if (mask is GradientDrawable) {
|
||||
val state = mask.getConstantState()
|
||||
if (state != null) {
|
||||
val temp = state.newDrawable().mutate() as GradientDrawable
|
||||
temp.setColor(Color.BLACK)
|
||||
mask = temp
|
||||
}
|
||||
} else {
|
||||
mask = ColorDrawable(Color.BLACK)
|
||||
}
|
||||
|
||||
val rippleDrawable = RippleDrawable(colorStateList, drawable, mask)
|
||||
setRadius(rippleDrawable, radius)
|
||||
rippleDrawable.invalidateSelf()
|
||||
drawable = rippleDrawable
|
||||
return drawable
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.RotateDrawable
|
||||
|
||||
class RotateDrawableBuilder : DrawableWrapperBuilder<RotateDrawableBuilder>() {
|
||||
|
||||
private var pivotX: Float = 0.5f
|
||||
private var pivotY: Float = 0.5f
|
||||
private var fromDegrees: Float = 0f
|
||||
private var toDegrees: Float = 360f
|
||||
|
||||
fun pivotX(x: Float) = apply { pivotX = x }
|
||||
fun pivotY(y: Float) = apply { pivotY = y }
|
||||
fun fromDegrees(degree: Float) = apply { fromDegrees = degree }
|
||||
fun toDegrees(degree: Float) = apply { toDegrees = degree }
|
||||
|
||||
override fun build(): Drawable {
|
||||
val rotateDrawable = RotateDrawable()
|
||||
drawable?.let {
|
||||
setDrawable(rotateDrawable, it)
|
||||
apply {
|
||||
setPivotX(rotateDrawable, pivotX)
|
||||
setPivotY(rotateDrawable, pivotY)
|
||||
setFromDegrees(rotateDrawable, fromDegrees)
|
||||
setToDegrees(rotateDrawable, toDegrees)
|
||||
}
|
||||
}
|
||||
return rotateDrawable
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.ScaleDrawable
|
||||
import android.view.Gravity
|
||||
|
||||
class ScaleDrawableBuilder : DrawableWrapperBuilder<ScaleDrawableBuilder>() {
|
||||
|
||||
private var level: Int = 10000
|
||||
private var scaleGravity = Gravity.CENTER
|
||||
private var scaleWidth: Float = 0f
|
||||
private var scaleHeight: Float = 0f
|
||||
|
||||
fun level(level: Int) = apply { this.level = level }
|
||||
fun scaleGravity(gravity: Int) = apply { this.scaleGravity = gravity }
|
||||
fun scaleWidth(scale: Float) = apply { this.scaleWidth = scale }
|
||||
fun scaleHeight(scale: Float) = apply { this.scaleHeight = scale }
|
||||
|
||||
override fun build(): Drawable {
|
||||
val scaleDrawable = ScaleDrawable(drawable, scaleGravity, scaleWidth, scaleHeight)
|
||||
scaleDrawable.level = level
|
||||
return scaleDrawable
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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/1/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.StateListDrawable
|
||||
import android.util.StateSet
|
||||
|
||||
class StateListDrawableBuilder {
|
||||
|
||||
private var pressed: Drawable? = null
|
||||
private var disabled: Drawable? = null
|
||||
private var selected: Drawable? = null
|
||||
private var normal: Drawable = ColorDrawable(Color.TRANSPARENT)
|
||||
|
||||
fun pressed(pressed: Drawable?) = apply { this.pressed = pressed }
|
||||
fun disabled(disabled: Drawable?) = apply { this.disabled = disabled }
|
||||
fun selected(selected: Drawable?) = apply { this.selected = selected }
|
||||
fun normal(normal: Drawable) = apply { this.normal = normal }
|
||||
|
||||
fun build(): StateListDrawable {
|
||||
val stateListDrawable = StateListDrawable()
|
||||
setupStateListDrawable(stateListDrawable)
|
||||
return stateListDrawable
|
||||
}
|
||||
|
||||
private fun setupStateListDrawable(stateListDrawable: StateListDrawable) {
|
||||
pressed?.let {
|
||||
stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), it)
|
||||
}
|
||||
disabled?.let {
|
||||
stateListDrawable.addState(intArrayOf(-android.R.attr.state_enabled), it)
|
||||
}
|
||||
selected?.let {
|
||||
stateListDrawable.addState(intArrayOf(android.R.attr.state_selected), it)
|
||||
}
|
||||
stateListDrawable.addState(StateSet.WILD_CARD, normal)
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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/10/6.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
/** 已添加的返回监听事件 */
|
||||
private val onBackPressedCallbacks = HashMap<AppCompatActivity, OnBackPressedCallback>()
|
||||
|
||||
/**
|
||||
* 手动调用返回事件
|
||||
* @param ignored 是否忽略现有返回监听事件立即返回 - 否则将执行返回事件 - 默认否
|
||||
*/
|
||||
fun AppCompatActivity.callOnBackPressed(ignored: Boolean = false) {
|
||||
if (isDestroyed) return
|
||||
onBackPressedCallbacks[this]?.isEnabled = ignored.not()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加返回监听事件
|
||||
* @param callback 回调事件
|
||||
*/
|
||||
fun AppCompatActivity.addOnBackPressedEvent(callback: OnBackPressedEvent.() -> Unit) {
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
OnBackPressedEvent(this@addOnBackPressedEvent).apply(callback)
|
||||
}
|
||||
}.also { result ->
|
||||
onBackPressedCallbacks.computeIfAbsent(this) {
|
||||
onBackPressedDispatcher.addCallback(result)
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回监听事件实现类
|
||||
* @param instance 当前实例
|
||||
*/
|
||||
class OnBackPressedEvent(private val instance: AppCompatActivity) {
|
||||
|
||||
/** 立即释放返回事件并调用返回功能 */
|
||||
fun releaseEventAndBack() = instance.callOnBackPressed(ignored = true)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/6/3.
|
||||
* This file is created by fankes on 2022/6/3.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
@@ -64,6 +64,7 @@ class BaseAdapterCreater(val context: Context) {
|
||||
* 绑定 [BaseAdapter] 到 [ListView]
|
||||
* @param bindViews 回调 - ([VB] 每项,[Int] 下标)
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
inline fun <reified VB : ViewBinding> onBindViews(crossinline bindViews: (binding: VB, position: Int) -> Unit) {
|
||||
baseAdapter = object : BaseAdapter() {
|
||||
override fun getCount() = listDataCallback?.let { it() }?.size ?: 0
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,28 +18,26 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/7.
|
||||
* This file is created by fankes on 2022/1/7.
|
||||
*/
|
||||
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.app.Dialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
|
||||
@@ -55,7 +53,7 @@ fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) =
|
||||
* 构造 [VB] 自定义 View 对话框
|
||||
* @param initiate 对话框方法体
|
||||
*/
|
||||
@JvmName(name = "showDialog-VB")
|
||||
@JvmName(name = "showDialog_Generics")
|
||||
inline fun <reified VB : ViewBinding> Context.showDialog(initiate: DialogBuilder<VB>.() -> Unit) =
|
||||
DialogBuilder<VB>(context = this, VB::class.java).apply(initiate).show()
|
||||
|
||||
@@ -70,13 +68,20 @@ inline fun Context.showDialog(initiate: DialogBuilder<*>.() -> Unit) = DialogBui
|
||||
* @param context 实例
|
||||
* @param bindingClass [ViewBinding] 的 [Class] 实例 or null
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
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 instance: AlertDialog.Builder? = null
|
||||
|
||||
private var dialogInstance: Dialog? = null // 对话框实例
|
||||
private var customLayoutView: View? = null // 自定义布局
|
||||
/** 对话框取消监听 */
|
||||
private var onCancel: (() -> Unit)? = null
|
||||
|
||||
/** 对话框实例 */
|
||||
private var dialogInstance: Dialog? = null
|
||||
|
||||
/** 自定义布局 */
|
||||
private var customLayoutView: View? = null
|
||||
|
||||
/**
|
||||
* 获取 [DialogBuilder] 绑定布局对象
|
||||
@@ -91,41 +96,28 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
|
||||
} ?: error("This dialog maybe not a custom view dialog")
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要使用 AndroidX 风格对话框
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val isUsingAndroidX get() = runCatching { context is AppCompatActivity }.getOrNull() ?: false
|
||||
|
||||
init {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) }
|
||||
else runInSafe { instanceAndroid = android.app.AlertDialog.Builder(context, android.R.style.Theme_Material_Light_Dialog) }
|
||||
if (YukiHookAPI.Status.isXposedEnvironment) error("This dialog is not allowed to created in Xposed environment")
|
||||
instance = MaterialAlertDialogBuilder(context)
|
||||
}
|
||||
|
||||
/** 设置对话框不可关闭 */
|
||||
fun noCancelable() {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setCancelable(false) }
|
||||
else runInSafe { instanceAndroid?.setCancelable(false) }
|
||||
instance?.setCancelable(false)
|
||||
}
|
||||
|
||||
/** 设置对话框标题 */
|
||||
var title
|
||||
get() = ""
|
||||
set(value) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setTitle(value) }
|
||||
else runInSafe { instanceAndroid?.setTitle(value) }
|
||||
instance?.setTitle(value)
|
||||
}
|
||||
|
||||
/** 设置对话框消息内容 */
|
||||
var msg
|
||||
get() = ""
|
||||
set(value) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setMessage(value) }
|
||||
else runInSafe { instanceAndroid?.setMessage(value) }
|
||||
instance?.setMessage(value)
|
||||
}
|
||||
|
||||
/** 设置进度条对话框消息内容 */
|
||||
@@ -136,7 +128,10 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
|
||||
customLayoutView = LinearLayout(context).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER or Gravity.START
|
||||
addView(ProgressBar(context))
|
||||
addView(CircularProgressIndicator(context).apply {
|
||||
isIndeterminate = true
|
||||
trackCornerRadius = 10.dp(context)
|
||||
})
|
||||
addView(View(context).apply { layoutParams = ViewGroup.LayoutParams(20.dp(context), 5) })
|
||||
addView(TextView(context).apply {
|
||||
tag = "progressContent"
|
||||
@@ -153,9 +148,7 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
|
||||
* @param callback 点击事件
|
||||
*/
|
||||
fun confirmButton(text: String = "确定", callback: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> callback() } }
|
||||
else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> callback() } }
|
||||
instance?.setPositiveButton(text) { _, _ -> callback() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,9 +157,7 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
|
||||
* @param callback 点击事件
|
||||
*/
|
||||
fun cancelButton(text: String = "取消", callback: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> callback() } }
|
||||
else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> callback() } }
|
||||
instance?.setNegativeButton(text) { _, _ -> callback() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,38 +166,28 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
|
||||
* @param callback 点击事件
|
||||
*/
|
||||
fun neutralButton(text: String = "更多", callback: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> callback() } }
|
||||
else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> callback() } }
|
||||
instance?.setNeutralButton(text) { _, _ -> callback() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 当对话框关闭时
|
||||
* @param callback 回调
|
||||
*/
|
||||
fun onCancel(callback: () -> Unit) {
|
||||
onCancel = callback
|
||||
}
|
||||
|
||||
/** 取消对话框 */
|
||||
fun cancel() = dialogInstance?.cancel()
|
||||
|
||||
/** 显示对话框 */
|
||||
@CauseProblemsApi
|
||||
fun show() {
|
||||
fun show() = runInSafe {
|
||||
/** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */
|
||||
if (bindingClass != null) binding
|
||||
if (isUsingAndroidX) runInSafe {
|
||||
instanceAndroidX?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
dialogInstance = this
|
||||
}?.show()
|
||||
} else runInSafe {
|
||||
instanceAndroid?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
window?.setBackgroundDrawable(
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
cornerRadius = 15.dpFloat(this@DialogBuilder.context)
|
||||
})
|
||||
dialogInstance = this
|
||||
}?.show()
|
||||
}
|
||||
instance?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
dialogInstance = this
|
||||
setOnCancelListener { onCancel?.invoke() }
|
||||
}?.show()
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,13 +18,13 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/13.
|
||||
* This file is created by fankes on 2022/3/13.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
@@ -79,5 +79,5 @@ inline fun <T> safeOf(default: T, result: () -> T) = try {
|
||||
* @param block 正常回调
|
||||
*/
|
||||
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
|
||||
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
|
||||
runCatching(block).onFailure { if (msg.isNotBlank()) YLog.error(msg, it) }
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,25 +18,37 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/7.
|
||||
* This file is created by fankes on 2022/1/7.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "PrivateApi", "unused", "ObsoleteSdkInt")
|
||||
@file:Suppress("unused", "ObsoleteSdkInt")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.Service
|
||||
import android.app.WallpaperManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.PackageInfoFlags
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.*
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffXfermode
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
@@ -45,19 +57,28 @@ import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import android.util.Base64
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.createBitmap
|
||||
import androidx.core.net.toUri
|
||||
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.classOf
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.java.StringType
|
||||
import com.highcapable.yukihookapi.hook.factory.toClassOrNull
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.java.StringClass
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
@@ -83,11 +104,23 @@ val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Confi
|
||||
*/
|
||||
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
|
||||
|
||||
/**
|
||||
* 系统版本是否高于或等于 Android 14
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
inline val isUpperOfAndroidU get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
||||
|
||||
/**
|
||||
* 系统版本是否高于或等于 Android 13
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
inline val isUpperOfAndroidT get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
||||
|
||||
/**
|
||||
* 系统版本是否高于或等于 Android 12
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
inline val isUpperOfAndroidS get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.R
|
||||
inline val isUpperOfAndroidS get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
|
||||
/**
|
||||
* 系统版本是否低于 Android 9
|
||||
@@ -101,11 +134,30 @@ inline val isLowerAndroidP get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
|
||||
*/
|
||||
inline val isLowerAndroidR get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
|
||||
|
||||
/**
|
||||
* 当前设备是否是 MIUI、HyperOS 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isMiSystem get() = isMIUI || isMIOS
|
||||
|
||||
/**
|
||||
* 当前设备是否不是 MIUI、HyperOS 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isNotMiSystem get() = !isMiSystem
|
||||
|
||||
/**
|
||||
* 当前设备是否是 MIUI 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isMIUI by lazy { ("android.miui.R").hasClass }
|
||||
@Suppress("DEPRECATION")
|
||||
val isMIUI by lazy { "android.miui.R".hasClass() }
|
||||
|
||||
/**
|
||||
* 当前设备是否是 HyperOS 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isMIOS get() = isMIUI && miuiVersion == "816"
|
||||
|
||||
/**
|
||||
* 当前设备是否不是 MIUI 定制 Android 系统
|
||||
@@ -114,22 +166,79 @@ val isMIUI by lazy { ("android.miui.R").hasClass }
|
||||
inline val isNotMIUI get() = !isMIUI
|
||||
|
||||
/**
|
||||
* 是否为支持的 MIUI 版本
|
||||
* 当前设备是否不是 HyperOS 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
inline val isNotMIOS get() = !isMIOS
|
||||
|
||||
/**
|
||||
* 是否为支持的 MIUI、HyperOS 版本
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val isSupportMiuiVersion
|
||||
get() = when (miuiVersion) {
|
||||
"12" -> true
|
||||
"12.5" -> true
|
||||
"13" -> true
|
||||
val isSupportMiSystemVersion
|
||||
get() = when {
|
||||
isMIOS -> when (miosVersion) {
|
||||
"1.0", "1.1", "2.0" -> true
|
||||
else -> false
|
||||
}
|
||||
isMIUI -> when (miuiVersion) {
|
||||
"11", "12", "12.5", "13", "14" -> true
|
||||
else -> false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否不为支持的 MIUI 版本
|
||||
* 是否不为支持的 MIUI、HyperOS 版本
|
||||
* @return [Boolean]
|
||||
*/
|
||||
inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
|
||||
inline val isNotSupportMiSystemVersion get() = !isSupportMiSystemVersion
|
||||
|
||||
/**
|
||||
* 获取 Android 版本代号
|
||||
* @return [String]
|
||||
*/
|
||||
val androidVersionCodeName
|
||||
get() = when (Build.VERSION.SDK_INT) {
|
||||
35 -> "V"
|
||||
34 -> "U"
|
||||
33 -> "T"
|
||||
32 -> "S_V2"
|
||||
31 -> "S"
|
||||
30 -> "R"
|
||||
29 -> "Q"
|
||||
28 -> "P"
|
||||
27 -> "O_MR1"
|
||||
26 -> "O"
|
||||
25 -> "N_MR1"
|
||||
24 -> "N"
|
||||
23 -> "M"
|
||||
22 -> "L_MR1"
|
||||
21 -> "L"
|
||||
else -> "?"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 MIUI、HyperOS 版本
|
||||
* @return [String]
|
||||
*/
|
||||
val miSystemVersion
|
||||
get() = when {
|
||||
isMIOS -> miosVersion
|
||||
isMIUI -> miuiVersion
|
||||
else -> ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 MIUI、HyperOS 版本号
|
||||
* @return [Float]
|
||||
*/
|
||||
val miSystemVersionCode
|
||||
get() = when {
|
||||
isMIOS -> miosVersionCode
|
||||
isMIUI -> miuiVersionCode
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 MIUI 版本
|
||||
@@ -137,121 +246,160 @@ inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
|
||||
*/
|
||||
val miuiVersion
|
||||
get() = if (isMIUI)
|
||||
findPropString(key = "ro.miui.ui.version.name", default = "V无法获取").let {
|
||||
findPropString("ro.miui.ui.version.name").let {
|
||||
when (it) {
|
||||
"V110" -> "11"
|
||||
"V11" -> "11"
|
||||
"V120" -> "12"
|
||||
"V12" -> "12"
|
||||
"V11", "V110" -> "11"
|
||||
"V12", "V120" -> "12"
|
||||
"V125" -> "12.5"
|
||||
"V130" -> "13"
|
||||
"V13" -> "13"
|
||||
else -> it.replace(oldValue = "V", newValue = "")
|
||||
"V13", "V130" -> "13"
|
||||
"V14", "V140" -> "14"
|
||||
else -> it.replace("V", "")
|
||||
}
|
||||
}.trim()
|
||||
else "NULL"
|
||||
else ""
|
||||
|
||||
/**
|
||||
* 获取 HyperOS 版本
|
||||
* @return [String]
|
||||
*/
|
||||
val miosVersion
|
||||
get() = if (isMIOS)
|
||||
findPropString("ro.mi.os.version.name").let {
|
||||
if (it.startsWith("OS")) it.replaceFirst("OS", "") else it
|
||||
}.trim()
|
||||
else ""
|
||||
|
||||
/**
|
||||
* 获取 MIUI 版本号
|
||||
* @return [Float]
|
||||
*/
|
||||
val miuiVersionCode get() = safeOf(default = 0f) { miuiVersion.toFloat() }
|
||||
val miuiVersionCode get() = miuiVersion.toFloatOrNull() ?: 0f
|
||||
|
||||
/**
|
||||
* 获取 HyperOS 版本号
|
||||
* @return [Float]
|
||||
*/
|
||||
val miosVersionCode get() = findPropString("ro.mi.os.version.code").toFloatOrNull() ?: 0f
|
||||
|
||||
/**
|
||||
* 获取 MIUI 次版本号
|
||||
* @return [String]
|
||||
*/
|
||||
val miuiIncrementalVersion get() = findPropString(key = "ro.system.build.version.incremental").trim()
|
||||
val miuiIncrementalVersion get() = findPropString("ro.system.build.version.incremental").trim()
|
||||
|
||||
/**
|
||||
* 获取 MIUI 完全版本
|
||||
* 获取 HyperOS 次版本号
|
||||
* @return [String]
|
||||
*/
|
||||
val miuiFullVersion
|
||||
get() = if (isMIUI) miuiIncrementalVersion.let {
|
||||
if (it.lowercase().contains("a") ||
|
||||
it.lowercase().contains("b") ||
|
||||
it.lowercase().contains("c") ||
|
||||
it.lowercase().contains("d") ||
|
||||
it.lowercase().contains("e") ||
|
||||
it.lowercase().contains("f") ||
|
||||
it.lowercase().contains("g") ||
|
||||
it.lowercase().contains("h") ||
|
||||
it.lowercase().contains("i") ||
|
||||
it.lowercase().contains("j") ||
|
||||
it.lowercase().contains("k") ||
|
||||
it.lowercase().contains("l") ||
|
||||
it.lowercase().contains("m") ||
|
||||
it.lowercase().contains("n") ||
|
||||
it.lowercase().contains("o") ||
|
||||
it.lowercase().contains("p") ||
|
||||
it.lowercase().contains("q") ||
|
||||
it.lowercase().contains("r") ||
|
||||
it.lowercase().contains("s") ||
|
||||
it.lowercase().contains("t") ||
|
||||
it.lowercase().contains("u") ||
|
||||
it.lowercase().contains("v") ||
|
||||
it.lowercase().contains("w") ||
|
||||
it.lowercase().contains("x") ||
|
||||
it.lowercase().contains("y") ||
|
||||
it.lowercase().contains("z")
|
||||
) "$it 稳定版" else "V$miuiVersion $it 开发版"
|
||||
} else "不是 MIUI 系统"
|
||||
val miosIncrementalVersion get() = findPropString("ro.mi.os.version.incremental").trim()
|
||||
|
||||
/**
|
||||
* 得到安装包信息
|
||||
* @return [PackageInfo]
|
||||
* 获取 MIUI、HyperOS 完全版本
|
||||
* @return [String]
|
||||
*/
|
||||
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo()
|
||||
|
||||
/**
|
||||
* 判断应用是否安装
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val String.isInstall
|
||||
get() = safeOfFalse {
|
||||
appContext.packageManager.getPackageInfo(
|
||||
this,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
)
|
||||
true
|
||||
val systemFullVersion
|
||||
get() = when {
|
||||
isMIOS -> "HyperOS " + miosIncrementalVersion.let {
|
||||
if (it.lowercase().endsWith(".dev").not() && it.lowercase().any { e -> e.code in 97..122 })
|
||||
"${it.replaceFirst("OS", "")} 稳定版"
|
||||
else when {
|
||||
it.lowercase().endsWith(".dev") -> "${it.replaceFirst("OS", "")} 开发版"
|
||||
else -> "$miosVersion $it 开发版"
|
||||
}
|
||||
}
|
||||
isMIUI -> miuiIncrementalVersion.let {
|
||||
if (it.lowercase().endsWith(".dev").not() && it.lowercase().any { e -> e.code in 97..122 })
|
||||
"$it 稳定版"
|
||||
else when {
|
||||
it.lowercase().endsWith(".dev") -> "$it 开发版"
|
||||
else -> "V$miuiVersion $it 开发版"
|
||||
}
|
||||
}
|
||||
else -> "不是 MIUI 或 HyperOS 系统"
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到版本信息
|
||||
* @return [String]
|
||||
* 获取 [Drawable]
|
||||
* @param resId 属性资源 ID
|
||||
* @return [Drawable]
|
||||
*/
|
||||
val Context.versionName get() = packageInfo.versionName ?: ""
|
||||
fun Resources.drawableOf(@DrawableRes resId: Int) = ResourcesCompat.getDrawable(this, resId, null) ?: error("Invalid resources")
|
||||
|
||||
/**
|
||||
* 得到版本号
|
||||
* 获取颜色
|
||||
* @param resId 属性资源 ID
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.versionCode get() = packageInfo.versionCode
|
||||
fun Resources.colorOf(@ColorRes resId: Int) = ResourcesCompat.getColor(this, resId, null)
|
||||
|
||||
/**
|
||||
* 得到 APP 安装包信息 (兼容)
|
||||
* @param packageName APP 包名
|
||||
* @param flag [PackageInfoFlags]
|
||||
* @return [PackageInfo] or null
|
||||
*/
|
||||
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
|
||||
@Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
|
||||
if (Build.VERSION.SDK_INT >= 33)
|
||||
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
|
||||
else packageManager?.getPackageInfo(packageName, flag.toInt())
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
* 得到 APP 版本号 (兼容 [PackageInfo.getLongVersionCode])
|
||||
* @return [Int]
|
||||
*/
|
||||
private val PackageInfo.versionCodeCompat get() = PackageInfoCompat.getLongVersionCode(this)
|
||||
|
||||
/**
|
||||
* 判断 APP 是否安装
|
||||
* @param packageName APP 包名
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun Context.isInstall(packageName: String) = getPackageInfoCompat(packageName)?.let { true } ?: false
|
||||
|
||||
/**
|
||||
* 得到 APP 版本信息
|
||||
* @return [String]
|
||||
*/
|
||||
val Context.appVersionName get() = getPackageInfoCompat(packageName)?.versionName ?: ""
|
||||
|
||||
/**
|
||||
* 得到 APP 版本号
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.appVersionCode get() = getPackageInfoCompat(packageName)?.versionCodeCompat
|
||||
|
||||
/**
|
||||
* 得到 APP 名称
|
||||
* @param name APP 包名
|
||||
* @param packageName APP 包名 - 默认为当前 APP
|
||||
* @return [String]
|
||||
*/
|
||||
fun Context.findAppName(name: String) =
|
||||
safeOfNothing { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadLabel(packageManager).toString() }
|
||||
fun Context.appNameOf(packageName: String = getPackageName()) =
|
||||
getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: ""
|
||||
|
||||
/**
|
||||
* 得到 APP 图标
|
||||
* @param name APP 包名
|
||||
* @param packageName APP 包名 - 默认为当前 APP
|
||||
* @return [Drawable] or null
|
||||
*/
|
||||
fun Context.findAppIcon(name: String) =
|
||||
safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) }
|
||||
fun Context.appIconOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.applicationInfo?.loadIcon(packageManager)
|
||||
|
||||
/**
|
||||
* 获取 APP 是否为 DEBUG 版本
|
||||
* @param name APP 包名
|
||||
* @param packageName APP 包名
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun Context.isAppDebuggable(name: String) =
|
||||
safeOfFalse { (packageManager?.getPackageInfo(name, 0)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 }
|
||||
fun Context.isDebugApp(packageName: String) =
|
||||
safeOfFalse { (getPackageInfoCompat(packageName)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 }
|
||||
|
||||
/**
|
||||
* 获取 APP 是否为系统 APP
|
||||
* @param packageName APP 包名
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun Context.isSystemApp(packageName: String) =
|
||||
safeOfFalse { (getPackageInfoCompat(packageName)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM) ?: 0) != 0 }
|
||||
|
||||
/**
|
||||
* 对数值自动补零
|
||||
@@ -291,8 +439,11 @@ val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext).
|
||||
* 网络连接是否正常
|
||||
* @return [Boolean] 网络是否连接
|
||||
*/
|
||||
val isNetWorkSuccess
|
||||
get() = safeOfFalse { appContext.getSystemService<ConnectivityManager>()?.activeNetworkInfo != null }
|
||||
val Context.isNetWorkSuccess
|
||||
get() = safeOfFalse {
|
||||
@Suppress("DEPRECATION")
|
||||
getSystemService<ConnectivityManager>()?.activeNetworkInfo != null
|
||||
}
|
||||
|
||||
/**
|
||||
* dp 转换为 pxInt
|
||||
@@ -313,22 +464,25 @@ fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetr
|
||||
* @return [Int] Android < 12 返回 [wallpaperColor]
|
||||
*/
|
||||
val Context.systemAccentColor
|
||||
get() = safeOf(wallpaperColor) { if (isUpperOfAndroidS) resources.getColor(android.R.color.system_accent1_600) else wallpaperColor }
|
||||
@SuppressLint("InlinedApi")
|
||||
get() = safeOf(wallpaperColor) {
|
||||
if (isUpperOfAndroidS) resources.colorOf(android.R.color.system_accent1_600) else wallpaperColor
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统壁纸颜色
|
||||
* @return [Int] 无法获取时返回透明色
|
||||
* @return [Int] 无法获取时返回默认颜色
|
||||
*/
|
||||
val Context.wallpaperColor
|
||||
get() = safeOfNan {
|
||||
WallpaperManager.getInstance(this).getWallpaperColors(WallpaperManager.FLAG_SYSTEM)?.primaryColor?.toArgb() ?: 0
|
||||
}
|
||||
get() = runCatching {
|
||||
WallpaperManager.getInstance(this).getWallpaperColors(WallpaperManager.FLAG_SYSTEM)?.primaryColor?.toArgb()
|
||||
}.getOrNull() ?: (if (isSystemInDarkMode) 0xFFD8D8D8.toInt() else 0xFF707173.toInt())
|
||||
|
||||
/**
|
||||
* 获取较浅的颜色
|
||||
* @return [Int]
|
||||
*/
|
||||
val Int.brighter: Int
|
||||
val Int.brighterColor: Int
|
||||
get() {
|
||||
val hsv = FloatArray(3)
|
||||
Color.colorToHSV(this, hsv)
|
||||
@@ -341,7 +495,7 @@ val Int.brighter: Int
|
||||
* 是否为白色
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val Int.isWhite
|
||||
val Int.isWhiteColor
|
||||
get() = safeOfTrue {
|
||||
val r = this and 0xff0000 shr 16
|
||||
val g = this and 0x00ff00 shr 8
|
||||
@@ -390,7 +544,7 @@ val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||
* @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图
|
||||
*/
|
||||
fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
|
||||
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { out ->
|
||||
createBitmap(width, height).also { out ->
|
||||
Canvas(out).also { canvas ->
|
||||
Paint().also { paint ->
|
||||
paint.isAntiAlias = true
|
||||
@@ -410,18 +564,22 @@ fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
|
||||
* @param default 默认值
|
||||
* @return [String]
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
fun findPropString(key: String, default: String = "") = safeOf(default) {
|
||||
(classOf(name = "android.os.SystemProperties").method {
|
||||
"android.os.SystemProperties".toClassOrNull()?.method {
|
||||
name = "get"
|
||||
param(StringType, StringType)
|
||||
}.get().invoke(key, default)) ?: default
|
||||
param(StringClass, StringClass)
|
||||
}?.get()?.invoke(key, default) ?: default
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有 Root 权限
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
|
||||
val isRootAccess get() = safeOfFalse {
|
||||
@Suppress("DEPRECATION")
|
||||
Shell.rootAccess()
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
@@ -430,6 +588,7 @@ val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
|
||||
* @return [String] 执行结果
|
||||
*/
|
||||
fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
|
||||
@Suppress("DEPRECATION")
|
||||
(if (isSu) Shell.su(cmd) else Shell.sh(cmd)).exec().out.let {
|
||||
if (it.isNotEmpty()) it[0].trim() else ""
|
||||
}
|
||||
@@ -439,7 +598,11 @@ fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
|
||||
* 弹出 [Toast]
|
||||
* @param msg 提示内容
|
||||
*/
|
||||
fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show()
|
||||
fun toast(msg: String) {
|
||||
runCatching {
|
||||
Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show()
|
||||
}.onFailure { YLog.warn(msg) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到指定页面
|
||||
@@ -475,7 +638,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
|
||||
startActivity(Intent().apply {
|
||||
if (packageName.isNotBlank()) setPackage(packageName)
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(url)
|
||||
data = url.toUri()
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
@@ -490,7 +653,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
|
||||
* @param packageName 包名
|
||||
*/
|
||||
fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching {
|
||||
if (packageName.isInstall)
|
||||
if (isInstall(packageName))
|
||||
startActivity(Intent().apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
@@ -535,4 +698,30 @@ fun Long.stampToDate(format: String = "yyyy-MM-dd HH:mm:ss") =
|
||||
* @param ms 毫秒 - 默认:150
|
||||
* @param it 方法体
|
||||
*/
|
||||
fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe { Handler().postDelayed({ it() }, ms) }
|
||||
fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe {
|
||||
@Suppress("DEPRECATION")
|
||||
Handler().postDelayed({ it() }, ms)
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏或显示启动器图标
|
||||
*
|
||||
* - 你可能需要 LSPosed 的最新版本以开启高版本系统中隐藏 APP 桌面图标功能
|
||||
* @param isShow 是否显示
|
||||
*/
|
||||
fun Context.hideOrShowLauncherIcon(isShow: Boolean) {
|
||||
packageManager?.setComponentEnabledSetting(
|
||||
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home"),
|
||||
if (isShow) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启动器图标状态
|
||||
* @return [Boolean] 是否显示
|
||||
*/
|
||||
val Context.isLauncherIconShowing
|
||||
get() = packageManager?.getComponentEnabledSetting(
|
||||
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home")
|
||||
) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/4/17.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.utils.factory.appIconOf
|
||||
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
|
||||
|
||||
/**
|
||||
* 模块更新激活提醒通知工具类
|
||||
*/
|
||||
object ActivationPromptTool {
|
||||
|
||||
/** 当前模块的包名 */
|
||||
private const val MODULE_PACKAGE_NAME = BuildConfigWrapper.APPLICATION_ID
|
||||
|
||||
/** 推送通知的渠道名称 */
|
||||
private const val NOTIFY_CHANNEL = "activationPromptId"
|
||||
|
||||
/**
|
||||
* 推送提醒通知
|
||||
* @param context 当前实例
|
||||
* @param packageName 当前 APP 包名
|
||||
*/
|
||||
fun prompt(context: Context, packageName: String) {
|
||||
if (packageName != BuildConfigWrapper.APPLICATION_ID) return
|
||||
context.getSystemService(NotificationManager::class.java)?.apply {
|
||||
createNotificationChannel(
|
||||
NotificationChannel(
|
||||
NOTIFY_CHANNEL, "MIUI 原生通知图标 - 版本更新",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
).apply { enableLights(false) }
|
||||
)
|
||||
notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply {
|
||||
setShowWhen(true)
|
||||
setContentTitle("模块已更新")
|
||||
setContentText("点按通知打开模块以完成新版本激活。")
|
||||
setColor(0xFFE06818.toInt())
|
||||
setAutoCancel(true)
|
||||
setSmallIcon(Icon.createWithResource(MODULE_PACKAGE_NAME, R.drawable.ic_notify_update))
|
||||
setExtras(Bundle().apply {
|
||||
putParcelable("miui.appIcon", Icon.createWithBitmap(context.appIconOf(MODULE_PACKAGE_NAME)?.toBitmap()))
|
||||
})
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, packageName.hashCode(),
|
||||
Intent().apply {
|
||||
component = ComponentName(MODULE_PACKAGE_NAME, "$MODULE_PACKAGE_NAME.ui.activity.MainActivity")
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,16 +18,21 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/19.
|
||||
* This file is created by fankes on 2022/2/19.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.graphics.*
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.AnimationDrawable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.VectorDrawable
|
||||
import android.util.ArrayMap
|
||||
import androidx.core.graphics.createBitmap
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.fankes.miui.notify.utils.factory.safeOfFalse
|
||||
import kotlin.math.abs
|
||||
@@ -73,7 +78,7 @@ object BitmapCompatTool {
|
||||
var width = bitmap.width
|
||||
if (height > 64 || width > 64) {
|
||||
if (tempCompactBitmap == null) {
|
||||
tempCompactBitmap = Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888)
|
||||
tempCompactBitmap = createBitmap(64, 64)
|
||||
.also { tempCompactBitmapCanvas = Canvas(it) }
|
||||
tempCompactBitmapPaint = Paint(Paint.FILTER_BITMAP_FLAG).apply { isFilterBitmap = true }
|
||||
}
|
||||
@@ -87,11 +92,12 @@ object BitmapCompatTool {
|
||||
val size = height * width
|
||||
ensureBufferSize(size)
|
||||
tempCompactBitmap?.getPixels(tempBuffer, 0, width, 0, 0, width, height)
|
||||
for (i in 0 until size)
|
||||
for (i in 0 until size) {
|
||||
if (isGrayscaleColor(tempBuffer[i]).not()) {
|
||||
cachedBitmapGrayscales[bitmap.generationId] = false
|
||||
return@let false
|
||||
}
|
||||
}
|
||||
cachedBitmapGrayscales[bitmap.generationId] = true
|
||||
true
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/20.
|
||||
* This file is created by fankes on 2022/3/20.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
@@ -27,15 +27,23 @@ 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 com.fankes.miui.notify.utils.factory.isNetWorkSuccess
|
||||
import com.fankes.miui.notify.utils.factory.openBrowser
|
||||
import com.fankes.miui.notify.utils.factory.openSelfSetting
|
||||
import com.fankes.miui.notify.utils.factory.runInSafe
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 获取 Github Release 最新版本工具类
|
||||
* 获取 GitHub Release 最新版本工具类
|
||||
*/
|
||||
object GithubReleaseTool {
|
||||
|
||||
@@ -71,7 +79,7 @@ object GithubReleaseTool {
|
||||
fun showUpdate() = context.showDialog {
|
||||
title = "最新版本 $name"
|
||||
msg = "发布于 $date\n\n" +
|
||||
"更新日志\n\n" + content
|
||||
"更新日志\n\n" + content
|
||||
confirmButton(text = "更新") { context.openBrowser(htmlUrl) }
|
||||
cancelButton()
|
||||
}
|
||||
@@ -91,7 +99,7 @@ object GithubReleaseTool {
|
||||
* @param callback 已连接回调
|
||||
*/
|
||||
private fun checkingInternetConnect(context: Context, callback: () -> Unit) = runInSafe {
|
||||
if (isNetWorkSuccess)
|
||||
if (context.isNetWorkSuccess)
|
||||
OkHttpClient().newBuilder().build().newCall(
|
||||
Request.Builder()
|
||||
.url("https://www.baidu.com")
|
||||
@@ -102,7 +110,7 @@ object GithubReleaseTool {
|
||||
(context as? Activity?)?.runOnUiThread {
|
||||
context.showDialog {
|
||||
title = "网络不可用"
|
||||
msg = "模块的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
|
||||
msg = "应用的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
|
||||
confirmButton(text = "去开启") { context.openSelfSetting() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
@@ -120,16 +128,16 @@ object GithubReleaseTool {
|
||||
* 格式化时间为本地时区
|
||||
* @return [String] 本地时区时间
|
||||
*/
|
||||
private fun String.localTime() = replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "").let {
|
||||
private fun String.localTime() = replace("T", " ").replace("Z", "").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") }
|
||||
val local = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT).apply { timeZone = Calendar.getInstance().timeZone }
|
||||
val current = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT).apply { timeZone = TimeZone.getTimeZone("GMT") }
|
||||
local.format(current.parse(it))
|
||||
}.getOrNull() ?: it
|
||||
}
|
||||
|
||||
/**
|
||||
* Github Release bean
|
||||
* GitHub Release bean
|
||||
* @param name 版本名称
|
||||
* @param htmlUrl 网页地址
|
||||
* @param content 更新日志
|
||||
|
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2017 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 2023/2/3.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* I18n 适配警告提示工具类
|
||||
*/
|
||||
object I18nWarnTool {
|
||||
|
||||
/** 推广已读存储键值 */
|
||||
private val LOCALE_WARN_READED = PrefsData("locale_warn_readed", false)
|
||||
|
||||
/**
|
||||
* 检查并显示 I18n 适配警告对话框
|
||||
* @param context 实例
|
||||
*/
|
||||
fun checkingOrShowing(context: Context) {
|
||||
fun saveReaded() = context.prefs().edit { put(LOCALE_WARN_READED, value = true) }
|
||||
if (Locale.getDefault().language.startsWith("zh").not() && context.prefs().get(LOCALE_WARN_READED).not())
|
||||
context.showDialog {
|
||||
title = "Notice of I18n Support"
|
||||
msg = "This Xposed Module is only for Chinese and the Chinese region.\n\n" +
|
||||
"Currently, there will be no internationalization adaptation.\n\n" +
|
||||
"There may be plans for internationalization adaptation in the future, so stay tuned."
|
||||
confirmButton(text = "Got It") { saveReaded() }
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/21.
|
||||
* This file is created by fankes on 2022/3/21.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
@@ -29,13 +29,19 @@ import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.fankes.miui.notify.BuildConfig
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.hook.HookEntry
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.factory.appIconOf
|
||||
import com.fankes.miui.notify.utils.factory.appNameOf
|
||||
import com.fankes.miui.notify.utils.factory.isDebugApp
|
||||
import com.fankes.miui.notify.utils.factory.isSystemApp
|
||||
import com.fankes.miui.notify.utils.factory.runInSafe
|
||||
import com.fankes.miui.notify.utils.factory.stampToDate
|
||||
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
|
||||
|
||||
/**
|
||||
* 通知图标适配推送通知类
|
||||
@@ -45,73 +51,13 @@ import com.fankes.miui.notify.utils.factory.*
|
||||
object IconAdaptationTool {
|
||||
|
||||
/** 当前模块的包名 */
|
||||
private const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
|
||||
private const val MODULE_PACKAGE_NAME = BuildConfigWrapper.APPLICATION_ID
|
||||
|
||||
/** 推送通知的渠道名称 */
|
||||
private const val NOTIFY_CHANNEL = "notifyRuleSupportId"
|
||||
|
||||
/** 已过期的日期 */
|
||||
private val outDateLimits = HashSet<String>()
|
||||
|
||||
/**
|
||||
* 使用的小图标
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
private val smallIcon by lazy {
|
||||
("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAAG\n" +
|
||||
"x2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkP\n" +
|
||||
"SJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG\n" +
|
||||
"9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDYgNzkuZGF\n" +
|
||||
"iYWNiYiwgMjAyMS8wNC8xNC0wMDozOTo0NCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6\n" +
|
||||
"cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gP\n" +
|
||||
"HJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYW\n" +
|
||||
"RvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1\n" +
|
||||
"lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90\n" +
|
||||
"b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuM\n" +
|
||||
"C9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cG\n" +
|
||||
"UvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI\n" +
|
||||
"yLjQgKE1hY2ludG9zaCkiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTAzLTIzVDAyOjU1OjM2\n" +
|
||||
"KzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wMy0yM1QwMzowMDoyMSswODowMCIge\n" +
|
||||
"G1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0wMy0yM1QwMzowMDoyMSswODowMCIgZGM6Zm9ybW\n" +
|
||||
"F0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0N\n" +
|
||||
"Qcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlp\n" +
|
||||
"ZDpiZGY1YWY2NS1lYjYxLTRiOGUtOTk1NS01OTE5OThkN2ExNDAiIHhtcE1NOkRvY3VtZ\n" +
|
||||
"W50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo2MDFlYjQ1OC01ZTdlLWFjNDYtODA0Mi\n" +
|
||||
"1iNWJmYTFhYWQwNGMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjYTU\n" +
|
||||
"4YTA1ZS04OTU1LTQyNzItODg2NC0xNmI5MWI0YzcxMmUiPiA8eG1wTU06SGlzdG9yeT4g\n" +
|
||||
"PHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0Y\n" +
|
||||
"W5jZUlEPSJ4bXAuaWlkOmNhNThhMDVlLTg5NTUtNDI3Mi04ODY0LTE2YjkxYjRjNzEyZS\n" +
|
||||
"Igc3RFdnQ6d2hlbj0iMjAyMi0wMy0yM1QwMjo1NTozNiswODowMCIgc3RFdnQ6c29mdHd\n" +
|
||||
"hcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiLz4gPHJkZjps\n" +
|
||||
"aSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjg5Y\n" +
|
||||
"mIxNTI1LWVjYmMtNGY2NC1iZTRlLWU1N2EyNjQ1NDE1YyIgc3RFdnQ6d2hlbj0iMjAyMi\n" +
|
||||
"0wMy0yM1QwMjo1NzoxMCswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGh\n" +
|
||||
"vdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjps\n" +
|
||||
"aSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmJkZ\n" +
|
||||
"jVhZjY1LWViNjEtNGI4ZS05OTU1LTU5MTk5OGQ3YTE0MCIgc3RFdnQ6d2hlbj0iMjAyMi\n" +
|
||||
"0wMy0yM1QwMzowMDoyMSswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGh\n" +
|
||||
"vdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6\n" +
|
||||
"U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+I\n" +
|
||||
"DwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+QdGsggAAA35JREFUaIHtmE2IVW\n" +
|
||||
"Ucxn9z0Ukm7cMSo1AxUwjNIclLRVSL0CAoyD5oYwS1iogWGW0rwQpcJNjCRdKmTR+SBhF\n" +
|
||||
"BWWZlZllmOgsT/EqHKRuqMVv8XJy5zPGd95x75hyh03Ae+C/O//2/z3Oee97P26MyGdD6\n" +
|
||||
"r1/gQqExUjc0RuqGxkjd0BipGxojdcOkMTKlS/tCYBXQBvqBWcA/wI/AD8AW4NML9C79w\n" +
|
||||
"APAYmAOcCUwCBwCvgTeB37J7K3Goq1utRgG1NUZPEXibnVnQa231CUxnhjxmoKkId5WWx\n" +
|
||||
"M08XpJrSe7GXmlJHEH36l9oUgketRPKmqtS3P2OHaxWgO8HBl9vwPbgM+AU8B0YAnJ3Fk\n" +
|
||||
"Uqd8HLAfO5MyHz4HbIvkh4ENgJ/Dn6DxZCdxFfGF6GngtPUeuz3D9qnpZzi/7mDoS6fe9\n" +
|
||||
"Oi1SP0XdnqH1vDo9Q2eeujmj33WmhtbuSMFTOQbSsUg9Gem/3/HDbEuk7ox6c0GtZyP9d\n" +
|
||||
"3WMLIg0vlGQuBPz1cEIzx51aqouxN/qsglqvRnhWYj6UpAcVnsnSN75/MciIntTfC+m8r\n" +
|
||||
"+qi0vo9Kp/BBrrUD8KkutLkHdijvpbxMy3jn2Z1eoL6uUVdDYE/NtRjwfJ+yoIoF6rnoi\n" +
|
||||
"Y2VORNx33B9wHWsDMYEk7m7NsFsEhYBlwMsjfCOwFplbkBzgdPPe2gOEg2e38VQQnSMwM\n" +
|
||||
"BvmlwBfAtIr8FwXPIy1gf5BsVxS5ieTQd5zEzFDQvhzYBfRU0OgPnk/j+GPJYMlx26d+P\n" +
|
||||
"MpxNjXX5hlfmneYbJBltAYCrk2YnCZDnHeOKRAXqz8FHMOp9mtMltsQu0uYeTzC085yqL\n" +
|
||||
"qqIPFMdV+k/46gbr7xpflrz98086Kt/hv0P6JjR5RbIwKqz5h/NF/p+OVb9bA6O1I/N6P\n" +
|
||||
"+Z/WWLiYezXjHO9JGMBlOMRxW16r3mhwn7jS5D2Rdho6ps3JeKGuYaXKnedhkL5qhLlWf\n" +
|
||||
"UL/KqN/Y4Q1FNmd0KIqj6tU5JtJmjnThGu7S/k6aMyayvpSF5FfL+xJhXKF+U1JrU8iXJ\n" +
|
||||
"bLC7M8Z4pTJXJrIypOO59ShgloH1YdiPOkbYgy3A48ANwBXAZcCIyQ79gDwAfAe8FeFzQ\n" +
|
||||
"3gEuBB4B5gATAb6BvlPUpy63wX2JpF0M3I/waT5g+6xkjd0BipGxojdUNjpG5ojNQNjZG\n" +
|
||||
"64Rx5J7QeMy++3AAAAABJRU5ErkJggg==").bitmap
|
||||
}
|
||||
/** 已过期的时间 */
|
||||
private val outTimeLimits = HashSet<String>()
|
||||
|
||||
/**
|
||||
* 推送新 APP 安装适配通知
|
||||
@@ -119,7 +65,8 @@ object IconAdaptationTool {
|
||||
* @param packageName 安装的 APP 包名
|
||||
*/
|
||||
fun pushNewAppSupportNotify(context: Context, packageName: String) {
|
||||
if (context.isAppDebuggable(packageName)) return
|
||||
if (packageName.startsWith("com.google.android.trichromelibrary")) return
|
||||
if (context.isSystemApp(packageName) || context.isDebugApp(packageName)) return
|
||||
context.getSystemService(NotificationManager::class.java)?.apply {
|
||||
createNotificationChannel(
|
||||
NotificationChannel(
|
||||
@@ -129,24 +76,26 @@ object IconAdaptationTool {
|
||||
)
|
||||
notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply {
|
||||
setShowWhen(true)
|
||||
setContentTitle("您已安装 ${context.findAppName(packageName)}")
|
||||
setContentTitle("您已安装 ${context.appNameOf(packageName)}")
|
||||
setContentText("尚未适配此应用,点按打开在线规则。")
|
||||
setColor(0xFF2993F0.toInt())
|
||||
setAutoCancel(true)
|
||||
setSmallIcon(Icon.createWithBitmap(smallIcon))
|
||||
setLargeIcon(context.findAppIcon(packageName)?.toBitmap())
|
||||
setSmallIcon(Icon.createWithResource(MODULE_PACKAGE_NAME, R.drawable.ic_unsupported))
|
||||
setExtras(Bundle().apply {
|
||||
putParcelable("miui.appIcon", Icon.createWithBitmap(context.appIconOf(MODULE_PACKAGE_NAME)?.toBitmap()))
|
||||
})
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, packageName.hashCode(),
|
||||
Intent().apply {
|
||||
component = ComponentName(
|
||||
MODULE_PACKAGE_NAME,
|
||||
"${MODULE_PACKAGE_NAME}.ui.activity.ConfigureActivity"
|
||||
"$MODULE_PACKAGE_NAME.ui.activity.ConfigureActivity"
|
||||
)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}.apply {
|
||||
putExtra("isNewAppSupport", true)
|
||||
putExtra("appName", context.findAppName(packageName))
|
||||
putExtra("appName", context.appNameOf(packageName))
|
||||
putExtra("pkgName", packageName)
|
||||
}, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
@@ -166,27 +115,20 @@ object IconAdaptationTool {
|
||||
|
||||
/**
|
||||
* 自动更新通知图标优化在线规则
|
||||
*
|
||||
* 一天执行一次
|
||||
* @param context 实例
|
||||
* @param timeSet 设定的时间
|
||||
*/
|
||||
fun prepareAutoUpdateIconRule(context: Context, timeSet: String) = runInSafe {
|
||||
System.currentTimeMillis().also {
|
||||
if (it.stampToDate(format = "HH:mm") == timeSet && (outDateLimits.isEmpty() || outDateLimits.none { each ->
|
||||
each == it.stampToDate(format = "yyyy-MM-dd")
|
||||
})) {
|
||||
outDateLimits.add(it.stampToDate(format = "yyyy-MM-dd"))
|
||||
context.startActivity(
|
||||
Intent().apply {
|
||||
component = ComponentName(
|
||||
MODULE_PACKAGE_NAME,
|
||||
"${MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity"
|
||||
)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
)
|
||||
}
|
||||
val nowTime = it.stampToDate(format = "HH:mm")
|
||||
if (timeSet != nowTime || outTimeLimits.any { e -> e == nowTime }) return
|
||||
outTimeLimits.add(nowTime)
|
||||
context.startActivity(
|
||||
Intent().apply {
|
||||
component = ComponentName(MODULE_PACKAGE_NAME, "$MODULE_PACKAGE_NAME.ui.activity.auto.NotifyIconRuleUpdateActivity")
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,7 +18,7 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/25.
|
||||
* This file is created by fankes on 2022/2/25.
|
||||
*/
|
||||
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager", "IMPLICIT_CAST_TO_ANY")
|
||||
|
||||
@@ -39,24 +39,31 @@ import androidx.core.content.getSystemService
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.const.IconRuleSourceSyncType
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.databinding.DiaSourceFromBinding
|
||||
import com.fankes.miui.notify.databinding.DiaSourceFromStringBinding
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_1
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_2
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_3
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.ui.activity.ConfigureActivity
|
||||
import com.fankes.miui.notify.utils.factory.delayedRun
|
||||
import com.fankes.miui.notify.utils.factory.openBrowser
|
||||
import com.fankes.miui.notify.utils.factory.safeOfNull
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import okhttp3.*
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.net.ssl.*
|
||||
import javax.net.ssl.HostnameVerifier
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.TrustManager
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
/**
|
||||
* 通知图标在线规则管理类
|
||||
@@ -70,7 +77,28 @@ object IconRuleManagerTool {
|
||||
private const val OS_TAG = "MIUI"
|
||||
|
||||
/** 当前规则的通知图标颜色 */
|
||||
private const val OS_COLOR = 0xFFE06818
|
||||
private const val OS_COLOR = 0xFFE06818.toInt()
|
||||
|
||||
/** 同步地址 - GitHub Raw (直连) */
|
||||
private const val SYNC_DIRECT_URL = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main"
|
||||
|
||||
/** 同步地址 - GitHub Raw (代理 - GitHub Proxy) */
|
||||
private const val SYNC_PROXY_1_URL = "https://ghp.ci/$SYNC_DIRECT_URL"
|
||||
|
||||
/** 同步地址 - GitHub Raw (代理 - 7ED Services) */
|
||||
private const val SYNC_PROXY_2_URL = "https://raw.githubusercontentS.com/fankes/AndroidNotifyIconAdapt/main"
|
||||
|
||||
/** 云端规则展示地址 (OS) */
|
||||
private const val RULES_TRAVELER_OS_URL = "https://fankes.github.io/AndroidNotifyIconAdapt/?notify-rules-miui"
|
||||
|
||||
/** 云端规则展示地址 (APP) */
|
||||
private const val RULES_TRAVELER_APP_URL = "https://fankes.github.io/AndroidNotifyIconAdapt/?notify-rules-app"
|
||||
|
||||
/** 请求适配通知图标优化名单地址 */
|
||||
internal const val RULES_FEEDBACK_URL = "https://fankes.github.io/AndroidNotifyIconAdapt/?feedback"
|
||||
|
||||
/** 贡献通知图标优化名单地址 */
|
||||
internal const val RULES_CONTRIBUTING_URL = "https://fankes.github.io/AndroidNotifyIconAdapt/?contribute"
|
||||
|
||||
/**
|
||||
* 从在线地址手动同步规则
|
||||
@@ -80,8 +108,8 @@ object IconRuleManagerTool {
|
||||
fun syncByHand(context: Context, callback: () -> Unit) =
|
||||
context.showDialog<DiaSourceFromBinding> {
|
||||
title = "同步列表"
|
||||
var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY)
|
||||
var customUrl = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL)
|
||||
var sourceType = ConfigData.iconRuleSourceSyncType
|
||||
var customUrl = ConfigData.iconRuleSourceSyncCustomUrl
|
||||
binding.sourceUrlEdit.apply {
|
||||
if (customUrl.isNotBlank()) {
|
||||
setText(customUrl)
|
||||
@@ -89,31 +117,43 @@ object IconRuleManagerTool {
|
||||
}
|
||||
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.sourceFromTextLin.isVisible = sourceType == IconRuleSourceSyncType.CUSTOM_URL
|
||||
binding.sourceTravelerLin.isVisible = sourceType != IconRuleSourceSyncType.CUSTOM_URL
|
||||
binding.sourceRadio0.isChecked = sourceType == IconRuleSourceSyncType.GITHUB_RAW_PROXY_1
|
||||
binding.sourceRadio1.isChecked = sourceType == IconRuleSourceSyncType.GITHUB_RAW_PROXY_2
|
||||
binding.sourceRadio2.isChecked = sourceType == IconRuleSourceSyncType.GITHUB_RAW_DIRECT
|
||||
binding.sourceRadio3.isChecked = sourceType == IconRuleSourceSyncType.CUSTOM_URL
|
||||
binding.sourceRadio0.setOnClickListener {
|
||||
binding.sourceFromTextLin.isVisible = false
|
||||
binding.sourceTravelerLin.isVisible = true
|
||||
sourceType = IconRuleSourceSyncType.GITHUB_RAW_PROXY_1
|
||||
}
|
||||
binding.sourceRadio1.setOnClickListener {
|
||||
binding.sourceFromTextLin.isVisible = false
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_1
|
||||
binding.sourceTravelerLin.isVisible = true
|
||||
sourceType = IconRuleSourceSyncType.GITHUB_RAW_PROXY_2
|
||||
}
|
||||
binding.sourceRadio2.setOnClickListener {
|
||||
binding.sourceFromTextLin.isVisible = false
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_2
|
||||
binding.sourceTravelerLin.isVisible = true
|
||||
sourceType = IconRuleSourceSyncType.GITHUB_RAW_DIRECT
|
||||
}
|
||||
binding.sourceRadio3.setOnClickListener {
|
||||
binding.sourceFromTextLin.isVisible = true
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_3
|
||||
binding.sourceTravelerLin.isVisible = false
|
||||
sourceType = IconRuleSourceSyncType.CUSTOM_URL
|
||||
}
|
||||
binding.sourceTravelerOsButton.setOnClickListener { context.openBrowser(RULES_TRAVELER_OS_URL) }
|
||||
binding.sourceTravelerAppButton.setOnClickListener { context.openBrowser(RULES_TRAVELER_APP_URL) }
|
||||
confirmButton {
|
||||
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType)
|
||||
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL, customUrl)
|
||||
ConfigData.iconRuleSourceSyncType = sourceType
|
||||
ConfigData.iconRuleSourceSyncCustomUrl = customUrl
|
||||
sync(context, sourceType, customUrl, callback)
|
||||
}
|
||||
cancelButton()
|
||||
neutralButton(text = "自定义规则") {
|
||||
context.showDialog<DiaSourceFromStringBinding> {
|
||||
title = "自定义规则(调试)"
|
||||
title = "自定义规则 (调试)"
|
||||
binding.jsonRuleEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
@@ -165,16 +205,15 @@ object IconRuleManagerTool {
|
||||
*/
|
||||
fun sync(
|
||||
context: Context,
|
||||
sourceType: Int = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY),
|
||||
customUrl: String = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL),
|
||||
sourceType: Int = ConfigData.iconRuleSourceSyncType,
|
||||
customUrl: String = ConfigData.iconRuleSourceSyncCustomUrl,
|
||||
callback: () -> Unit
|
||||
) {
|
||||
when (sourceType) {
|
||||
TYPE_SOURCE_SYNC_WAY_1 ->
|
||||
onRefreshing(context, url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main", callback)
|
||||
TYPE_SOURCE_SYNC_WAY_2 ->
|
||||
onRefreshing(context, url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main", callback)
|
||||
TYPE_SOURCE_SYNC_WAY_3 ->
|
||||
IconRuleSourceSyncType.GITHUB_RAW_PROXY_1 -> onRefreshing(context, SYNC_PROXY_1_URL, callback)
|
||||
IconRuleSourceSyncType.GITHUB_RAW_PROXY_2 -> onRefreshing(context, SYNC_PROXY_2_URL, callback)
|
||||
IconRuleSourceSyncType.GITHUB_RAW_DIRECT -> onRefreshing(context, SYNC_DIRECT_URL, callback)
|
||||
IconRuleSourceSyncType.CUSTOM_URL ->
|
||||
if (customUrl.isNotBlank())
|
||||
if (customUrl.startsWith("http://") || customUrl.startsWith("https://"))
|
||||
onRefreshingCustom(context, customUrl, callback)
|
||||
@@ -206,11 +245,10 @@ object IconRuleManagerTool {
|
||||
context.snakeOrNotify(title = "同步错误", msg = "目标地址不是有效的 JSON 数据")
|
||||
params.isCompareDifferent(it) -> {
|
||||
params.save(it)
|
||||
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
|
||||
notifyRefresh(context)
|
||||
callback()
|
||||
}
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新") else Unit)
|
||||
}
|
||||
}
|
||||
context is AppCompatActivity ->
|
||||
@@ -246,6 +284,8 @@ object IconRuleManagerTool {
|
||||
fun doParse(result: () -> Unit = {}) {
|
||||
wait(context, url) { isDone, content ->
|
||||
result()
|
||||
/** 延迟重新回调防止对话框无法取消 */
|
||||
delayedRun { result() }
|
||||
IconPackParams(context).also { params ->
|
||||
when {
|
||||
isDone -> when {
|
||||
@@ -255,11 +295,10 @@ object IconRuleManagerTool {
|
||||
context.snakeOrNotify(title = "同步错误", msg = "目标地址不是有效的 JSON 数据")
|
||||
params.isCompareDifferent(content) -> {
|
||||
params.save(content)
|
||||
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
|
||||
notifyRefresh(context)
|
||||
callback()
|
||||
}
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新") else Unit)
|
||||
}
|
||||
context is AppCompatActivity ->
|
||||
context.showDialog {
|
||||
@@ -311,7 +350,7 @@ object IconRuleManagerTool {
|
||||
}
|
||||
}
|
||||
} else baseCheckingInternetConnect(context) { isDone ->
|
||||
if (isDone) callback() else pushNotify(context, title = "网络不可用", msg = "无法连接到互联网,无法更新通知图标规则")
|
||||
if (isDone) callback() else pushNotify(context, title = "网络不可用", msg = "网络连接失败,无法更新通知图标规则,点击重试", isRetry = true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,8 +393,8 @@ object IconRuleManagerTool {
|
||||
* @param context 实例
|
||||
*/
|
||||
private fun notifyRefresh(context: Context) {
|
||||
if (context !is AppCompatActivity) return
|
||||
SystemUITool.refreshSystemUI(context) { context.snake(msg = "通知图标优化名单已完成同步") }
|
||||
if (context !is AppCompatActivity) pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
|
||||
SystemUITool.refreshSystemUI(context) { if (context is AppCompatActivity) context.snake(msg = "已更新通知图标优化名单") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,8 +403,7 @@ object IconRuleManagerTool {
|
||||
* @param msg 消息内容
|
||||
*/
|
||||
private fun Context.snakeOrNotify(title: String, msg: String) {
|
||||
if (this !is AppCompatActivity)
|
||||
pushNotify(context = this, title, msg)
|
||||
if (this !is AppCompatActivity) pushNotify(context = this, title, msg)
|
||||
else snake(msg)
|
||||
}
|
||||
|
||||
@@ -374,8 +412,9 @@ object IconRuleManagerTool {
|
||||
* @param context 实例 - 类型为 [AppCompatActivity] 时将不会推送通知
|
||||
* @param title 通知标题
|
||||
* @param msg 通知消息
|
||||
* @param isRetry 是否发送重试动作 - 默认否
|
||||
*/
|
||||
private fun pushNotify(context: Context, title: String, msg: String) {
|
||||
private fun pushNotify(context: Context, title: String, msg: String, isRetry: Boolean = false) {
|
||||
if (context !is AppCompatActivity)
|
||||
context.getSystemService<NotificationManager>()?.apply {
|
||||
createNotificationChannel(
|
||||
@@ -387,7 +426,7 @@ object IconRuleManagerTool {
|
||||
notify(0, NotificationCompat.Builder(context, NOTIFY_CHANNEL).apply {
|
||||
setContentTitle(title)
|
||||
setContentText(msg)
|
||||
color = OS_COLOR.toInt()
|
||||
color = OS_COLOR
|
||||
setAutoCancel(true)
|
||||
setSmallIcon(R.drawable.ic_nf_icon_update)
|
||||
setSound(null)
|
||||
@@ -395,7 +434,9 @@ object IconRuleManagerTool {
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, msg.hashCode(),
|
||||
Intent(context, ConfigureActivity::class.java).apply { putExtra("isShowUpdDialog", false) },
|
||||
Intent(context, ConfigureActivity::class.java).apply {
|
||||
if (isRetry) putExtra("isDirectUpdate", true) else putExtra("isShowUpdDialog", false)
|
||||
},
|
||||
if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
@@ -436,11 +477,11 @@ object IconRuleManagerTool {
|
||||
get() = object : X509TrustManager {
|
||||
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||
loggerD(msg = "TrustX509 --> $authType")
|
||||
YLog.debug("TrustX509 --> $authType")
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||
loggerD(msg = "TrustX509 --> $authType")
|
||||
YLog.debug("TrustX509 --> $authType")
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,18 +18,34 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/8.
|
||||
* This file is created by fankes on 2022/2/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.fankes.miui.notify.const.PackageName
|
||||
import com.fankes.miui.notify.data.ConfigData
|
||||
import com.fankes.miui.notify.ui.activity.MainActivity
|
||||
import com.fankes.miui.notify.utils.factory.delayedRun
|
||||
import com.fankes.miui.notify.utils.factory.execShell
|
||||
import com.fankes.miui.notify.utils.factory.isMIOS
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.fankes.miui.notify.utils.factory.systemFullVersion
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.factory.dataChannel
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.log.data.YLogData
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 系统界面工具
|
||||
@@ -39,6 +55,12 @@ object SystemUITool {
|
||||
private val CALL_HOST_REFRESH_CACHING = ChannelData("call_host_refresh_caching", false)
|
||||
private val CALL_MODULE_REFRESH_RESULT = ChannelData("call_module_refresh_result", false)
|
||||
|
||||
/** 当前全部调试日志 */
|
||||
private var debugLogs = listOf<YLogData>()
|
||||
|
||||
/** 当前启动器实例 */
|
||||
private var launcher: ActivityResultLauncher<String>? = null
|
||||
|
||||
/**
|
||||
* 宿主注册监听
|
||||
*/
|
||||
@@ -59,27 +81,125 @@ object SystemUITool {
|
||||
* @param context 实例
|
||||
* @param result 成功后回调
|
||||
*/
|
||||
fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEMUI_PACKAGE_NAME).checkingVersionEquals(result)
|
||||
fun checkingActivated(context: Context, result: (Boolean) -> Unit) =
|
||||
context.dataChannel(PackageName.SYSTEMUI).checkingVersionEquals(result = result)
|
||||
|
||||
/**
|
||||
* 注册导出调试日志启动器到 [AppCompatActivity]
|
||||
* @param activity 实例
|
||||
*/
|
||||
fun registerExportDebugLogsLauncher(activity: AppCompatActivity) {
|
||||
launcher = activity.registerForActivityResult(ActivityResultContracts.CreateDocument("*/application")) { result ->
|
||||
runCatching {
|
||||
result?.let { e ->
|
||||
val content = "" +
|
||||
"================================================================\n" +
|
||||
" Generated by MIUINativeNotifyIcon\n" +
|
||||
" Project Url: https://github.com/fankes/MIUINativeNotifyIcon\n" +
|
||||
"================================================================\n\n" +
|
||||
"[Device Brand]: ${Build.BRAND}\n" +
|
||||
"[Device Model]: ${Build.MODEL}\n" +
|
||||
"[Display]: ${Build.DISPLAY}\n" +
|
||||
"[Android Version]: ${Build.VERSION.RELEASE}\n" +
|
||||
"[Android API Level]: ${Build.VERSION.SDK_INT}\n" +
|
||||
"[${if (isMIOS) "HyperOS" else "MIUI"} Version]: $systemFullVersion\n" +
|
||||
"[System Locale]: ${Locale.getDefault()}\n\n" + YLog.contents(debugLogs).trim()
|
||||
activity.contentResolver?.openOutputStream(e)?.apply { write(content.toByteArray()) }?.close()
|
||||
activity.snake(msg = "导出完成")
|
||||
} ?: activity.snake(msg = "已取消操作")
|
||||
}.onFailure { activity.snake(msg = "导出过程发生错误") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并导出全部调试日志
|
||||
* @param context 实例
|
||||
*/
|
||||
fun obtainAndExportDebugLogs(context: Context) {
|
||||
/** 执行导出操作 */
|
||||
fun doExport() {
|
||||
context.dataChannel(PackageName.SYSTEMUI).obtainLoggerInMemoryData {
|
||||
if (it.isNotEmpty()) {
|
||||
debugLogs = it
|
||||
runCatching { launcher?.launch("miui_notification_icons_processing_logs.log") }
|
||||
.onFailure { context.snake(msg = "启动系统文件选择器失败") }
|
||||
} else context.snake(msg = "暂无调试日志")
|
||||
}
|
||||
}
|
||||
if (YukiHookAPI.Status.isXposedModuleActive)
|
||||
context.showDialog {
|
||||
title = "导出全部调试日志"
|
||||
msg = "调试日志中会包含当前系统推送的全部通知内容,其中可能包含你的个人隐私," +
|
||||
"你可以在导出后的日志文件中选择将这些敏感信息模糊化处理再进行共享," +
|
||||
"开发者使用并查看你导出的调试日志仅为排查与修复问题,并且在之后会及时销毁这些日志。\n\n" +
|
||||
"继续导出即代表你已阅读并知悉上述内容。"
|
||||
confirmButton(text = "继续") { doExport() }
|
||||
cancelButton()
|
||||
}
|
||||
else context.snake(msg = "模块没有激活,请先激活模块")
|
||||
}
|
||||
|
||||
/** 当 Root 权限获取失败时显示对话框 */
|
||||
private fun Context.showWhenAccessRootFail() =
|
||||
showDialog {
|
||||
title = "获取 Root 权限失败"
|
||||
msg = "当前无法获取 Root 权限,请确认你的设备已经被 Root 且同意授予 Root 权限。\n" +
|
||||
"如果你正在使用 Magisk 并安装了 Shamiko 模块," +
|
||||
"请确认当前是否正处于白名单模式。 (白名单模式将导致无法申请 Root 权限)"
|
||||
confirmButton(text = "我知道了")
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开 MIUI 通知显示设置界面
|
||||
* @param context 实例
|
||||
*/
|
||||
fun openMiuiNotificationDisplaySettings(context: Context) {
|
||||
runCatching {
|
||||
context.startActivity(Intent().apply {
|
||||
component = ComponentName(
|
||||
"com.miui.notification",
|
||||
"miui.notification.management.activity.NotificationDisplaySettingsActivity"
|
||||
)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
}.onFailure {
|
||||
execShell(
|
||||
cmd = "am start -a" +
|
||||
"com.miui.notification " +
|
||||
"com.miui.notification/miui.notification.management.activity.NotificationDisplaySettingsActivity"
|
||||
).also {
|
||||
when {
|
||||
it.isBlank() -> context.showWhenAccessRootFail()
|
||||
else -> context.snake(msg = "已发送请求,如果未打开则是当前系统不支持此功能")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启系统界面
|
||||
* @param context 实例
|
||||
*/
|
||||
fun restartSystemUI(context: Context) =
|
||||
fun restartSystemUI(context: Context) {
|
||||
/** 动态刷新功能是否可用 */
|
||||
val isDynamicAvailable = ConfigData.isEnableModule && MainActivity.isModuleRegular && MainActivity.isModuleValied
|
||||
context.showDialog {
|
||||
title = "重启系统界面"
|
||||
msg = "你确定要立即重启系统界面吗?\n\n" +
|
||||
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
|
||||
"重启过程会黑屏并等待进入锁屏重新解锁。"
|
||||
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
|
||||
"重启过程会黑屏并等待进入锁屏重新解锁。" + (if (isDynamicAvailable)
|
||||
"\n\n你也可以选择“立即生效”来动态刷新系统界面并生效当前模块设置。" else "")
|
||||
confirmButton {
|
||||
execShell(cmd = "pgrep systemui").also { pid ->
|
||||
if (pid.isNotBlank())
|
||||
execShell(cmd = "kill -9 $pid")
|
||||
else toast(msg = "ROOT 权限获取失败")
|
||||
else context.showWhenAccessRootFail()
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
if (isDynamicAvailable) neutralButton(text = "立即生效") { refreshSystemUI(context) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新系统界面状态栏与通知图标
|
||||
@@ -87,40 +207,50 @@ object SystemUITool {
|
||||
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
|
||||
* @param callback 成功后回调
|
||||
*/
|
||||
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, callback: () -> Unit = {}) = runInSafe {
|
||||
if (YukiHookAPI.Status.isXposedModuleActive)
|
||||
context?.showDialog {
|
||||
title = "请稍后"
|
||||
progressContent = "正在等待系统界面刷新"
|
||||
/** 是否等待成功 */
|
||||
var isWaited = false
|
||||
/** 设置等待延迟 */
|
||||
delayedRun(ms = 5000) {
|
||||
if (isWaited) return@delayedRun
|
||||
cancel()
|
||||
context.snake(msg = "预计响应超时,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
checkingActivated(context) { isValied ->
|
||||
when {
|
||||
isValied.not() -> {
|
||||
cancel()
|
||||
isWaited = true
|
||||
context.snake(msg = "请重启系统界面以生效模块更新", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
else -> context.dataChannel(SYSTEMUI_PACKAGE_NAME).with {
|
||||
wait(CALL_MODULE_REFRESH_RESULT) {
|
||||
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, callback: () -> Unit = {}) {
|
||||
/**
|
||||
* 刷新系统界面
|
||||
* @param result 回调结果
|
||||
*/
|
||||
fun doRefresh(result: (Boolean) -> Unit) {
|
||||
context?.dataChannel(PackageName.SYSTEMUI)?.with {
|
||||
wait(CALL_MODULE_REFRESH_RESULT) { result(it) }
|
||||
put(CALL_HOST_REFRESH_CACHING, isRefreshCacheOnly)
|
||||
}
|
||||
}
|
||||
when {
|
||||
YukiHookAPI.Status.isXposedModuleActive && context is AppCompatActivity ->
|
||||
context.showDialog {
|
||||
title = "请稍后"
|
||||
progressContent = "正在等待系统界面刷新"
|
||||
/** 是否等待成功 */
|
||||
var isWaited = false
|
||||
/** 设置等待延迟 */
|
||||
delayedRun(ms = 5000) {
|
||||
if (isWaited) return@delayedRun
|
||||
cancel()
|
||||
context.snake(msg = "预计响应超时,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
checkingActivated(context) { isValied ->
|
||||
when {
|
||||
isValied.not() -> {
|
||||
cancel()
|
||||
isWaited = true
|
||||
context.snake(msg = "请重启系统界面以生效模块更新", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
else -> doRefresh {
|
||||
cancel()
|
||||
isWaited = true
|
||||
callback()
|
||||
if (it.not()) context.snake(msg = "刷新失败,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
put(CALL_HOST_REFRESH_CACHING, isRefreshCacheOnly)
|
||||
}
|
||||
}
|
||||
noCancelable()
|
||||
}
|
||||
noCancelable()
|
||||
}
|
||||
else context?.snake(msg = "模块没有激活,更改不会生效")
|
||||
YukiHookAPI.Status.isXposedModuleActive.not() && context is AppCompatActivity -> context.snake(msg = "模块没有激活,更改不会生效")
|
||||
else -> doRefresh { callback() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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/5/30.
|
||||
*/
|
||||
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
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 的自动推广工具类
|
||||
*/
|
||||
object YukiPromoteTool {
|
||||
|
||||
/** 推广已读存储键值 */
|
||||
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed_${BuildConfig.VERSION_NAME}", false)
|
||||
|
||||
/**
|
||||
* 显示推广对话框
|
||||
* @param context 实例
|
||||
*/
|
||||
fun promote(context: Context) {
|
||||
fun saveReaded() = context.modulePrefs.put(YUKI_PROMOTE_READED, value = true)
|
||||
if (context.modulePrefs.get(YUKI_PROMOTE_READED).not())
|
||||
context.showDialog {
|
||||
title = "面向开发者的推广"
|
||||
msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" +
|
||||
"快来体验 YukiHookAPI,这是一个使用 Kotlin 重新构建的高效 Xposed Hook API,助你的开发变得更轻松。"
|
||||
confirmButton(text = "去看看") {
|
||||
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
|
||||
saveReaded()
|
||||
}
|
||||
cancelButton(text = "我不是开发者") { saveReaded() }
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
@@ -18,18 +18,20 @@
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
* This file is created by fankes on 2023/9/17.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
@file:Suppress("unused")
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
package com.fankes.miui.notify.wrapper
|
||||
|
||||
abstract class DrawableWrapperBuilder<T: DrawableWrapperBuilder<T>> {
|
||||
import com.fankes.miui.notify.BuildConfig
|
||||
|
||||
protected var drawable: Drawable? = null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun drawable(drawable: Drawable): T = apply { this.drawable = drawable } as T
|
||||
|
||||
abstract fun build(): Drawable
|
||||
/**
|
||||
* 对 [BuildConfig] 的包装
|
||||
*/
|
||||
object BuildConfigWrapper {
|
||||
const val APPLICATION_ID = BuildConfig.APPLICATION_ID
|
||||
const val VERSION_NAME = BuildConfig.VERSION_NAME
|
||||
const val VERSION_CODE = BuildConfig.VERSION_CODE
|
||||
val isDebug = BuildConfig.DEBUG
|
||||
}
|
9
app/src/main/res/drawable/ic_about.xml
Normal file
9
app/src/main/res/drawable/ic_about.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150.1dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1025"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M983.8,314.4c-25.7,-60.8 -62.5,-115.4 -109.4,-162.3 -46.9,-46.9 -101.5,-83.7 -162.3,-109.4 -62.9,-26.7 -129.9,-40.2 -198.8,-40.2S377.5,16 314.5,42.7C253.8,68.4 199.1,105.2 152.3,152.2c-46.9,46.9 -83.7,101.5 -109.4,162.3 -26.7,62.9 -40.2,129.9 -40.2,198.8s13.5,135.8 40.2,198.8c25.7,60.8 62.5,115.4 109.4,162.3 46.9,46.9 101.5,83.7 162.3,109.4 62.9,26.7 129.9,40.2 198.8,40.2s135.8,-13.5 198.8,-40.2c60.8,-25.7 115.4,-62.5 162.3,-109.4 46.9,-46.9 83.7,-101.5 109.4,-162.3 26.7,-62.9 40.2,-129.9 40.2,-198.8s-13.6,-135.9 -40.3,-198.9zM550.5,768.2c0,21 -17,38 -38,38s-38,-17 -38,-38L474.5,395.6c0,-21 17,-38 38,-38s38,17 38,38v372.6zM510.8,305.5c-29.2,0 -52.7,-23.7 -52.7,-52.7 0,-29.2 23.7,-52.7 52.7,-52.7 29.2,0 52.7,23.7 52.7,52.7 0.1,29.2 -23.6,52.7 -52.7,52.7z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_back.xml
Normal file
9
app/src/main/res/drawable/ic_back.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="150.39165dp"
|
||||
android:viewportWidth="1307"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M268.7,566.5h929.6c36.3,0 72.6,-29 72.6,-72.6 0,-36.3 -29,-72.6 -72.6,-72.6H305l297.8,-297.8c29,-29 29,-72.6 0,-101.7 -29,-29 -72.6,-29 -101.7,0L72.6,450.3c-14.5,14.5 -21.8,36.3 -21.8,58.1 0,21.8 0,43.6 21.8,58.1l428.5,428.5c29,29 72.6,29 101.7,0 29,-29 29,-72.6 0,-101.7l-334.1,-326.8z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_filter.xml
Normal file
9
app/src/main/res/drawable/ic_filter.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="184.6dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1260"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M419.2,548.3L17,108.9C-23.6,64.4 13,0 79.7,0h846.5c66.6,0 103.3,64.4 62.8,108.9l-402.2,439.3v472.7c0,1.6 -1.3,2.9 -2.8,2.9a8.3,8.3 0,0 1,-5.2 -1.8l-154.3,-120a13.7,13.7 0,0 1,-5.3 -10.8L419.2,548.3zM838.2,511.9L1257.3,511.9L1257.3,597.2h-419.1L838.2,511.9zM838.2,682.5L1257.3,682.5v85.3h-419.1L838.2,682.5zM838.2,853.2L1257.3,853.2v85.3h-419.1v-85.3z" />
|
||||
</vector>
|
52
app/src/main/res/drawable/ic_function.xml
Normal file
52
app/src/main/res/drawable/ic_function.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M11,16V42"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,29V42"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,19V6"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M37,6V32"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M11,16C13.761,16 16,13.761 16,11C16,8.239 13.761,6 11,6C8.239,6 6,8.239 6,11C6,13.761 8.239,16 11,16Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,29C26.761,29 29,26.761 29,24C29,21.239 26.761,19 24,19C21.239,19 19,21.239 19,24C19,26.761 21.239,29 24,29Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M37,42C39.761,42 42,39.761 42,37C42,34.239 39.761,32 37,32C34.239,32 32,34.239 32,37C32,39.761 34.239,42 37,42Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_github.xml
Normal file
9
app/src/main/res/drawable/ic_github.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M512,12.6c-282.8,0 -512,229.2 -512,512 0,226.2 146.7,418.1 350.1,485.8 25.6,4.7 35,-11.1 35,-24.6 0,-12.2 -0.5,-52.5 -0.7,-95.3 -142.5,31 -172.5,-60.4 -172.5,-60.4 -23.3,-59.2 -56.8,-74.9 -56.8,-74.9 -46.5,-31.8 3.5,-31.1 3.5,-31.1 51.4,3.6 78.5,52.8 78.5,52.8 45.7,78.3 119.8,55.6 149,42.6 4.6,-33.1 17.9,-55.7 32.5,-68.5 -113.7,-12.9 -233.3,-56.9 -233.3,-253 0,-55.9 20,-101.6 52.8,-137.4 -5.3,-12.9 -22.8,-65 5,-135.5 0,0 43,-13.8 140.8,52.5 40.8,-11.4 84.6,-17 128.2,-17.2 43.5,0.2 87.3,5.9 128.3,17.2 97.7,-66.2 140.6,-52.5 140.6,-52.5 27.9,70.5 10.3,122.6 5,135.5 32.8,35.8 52.7,81.5 52.7,137.4 0,196.6 -119.8,239.9 -233.8,252.6 18.4,15.9 34.7,47 34.7,94.8 0,68.5 -0.6,123.6 -0.6,140.5 0,13.6 9.2,29.6 35.2,24.6 203.3,-67.8 349.9,-259.6 349.9,-485.8 0,-282.8 -229.2,-512 -512,-512z" />
|
||||
</vector>
|
25
app/src/main/res/drawable/ic_home.xml
Normal file
25
app/src/main/res/drawable/ic_home.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,18V42H39V18L24,6L9,18Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29V42H29V29H19Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,42H39"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round" />
|
||||
</vector>
|
30
app/src/main/res/drawable/ic_info.xml
Normal file
30
app/src/main/res/drawable/ic_info.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,44C29.523,44 34.523,41.761 38.142,38.142C41.761,34.523 44,29.523 44,24C44,18.477 41.761,13.477 38.142,9.858C34.523,6.239 29.523,4 24,4C18.477,4 13.477,6.239 9.858,9.858C6.239,13.477 4,18.477 4,24C4,29.523 6.239,34.523 9.858,38.142C13.477,41.761 18.477,44 24,44Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M24,11C25.381,11 26.5,12.119 26.5,13.5C26.5,14.881 25.381,16 24,16C22.619,16 21.5,14.881 21.5,13.5C21.5,12.119 22.619,11 24,11Z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24.5,34V20H23.5H22.5"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M21,34H28"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_message.xml
Normal file
10
app/src/main/res/drawable/ic_message.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m522.8,93.9c-244.2,0 -442.1,173.2 -442.1,386.9 0,122.1 64.9,230.9 165.8,301.7v195.7l193.7,-117.5c26.8,4.4 54.3,7 82.6,7 244.2,0 442.1,-173.2 442.1,-386.9C965,267.1 767.1,93.9 522.8,93.9Z"
|
||||
android:strokeWidth="1.10883" />
|
||||
</vector>
|
36
app/src/main/res/drawable/ic_modify.xml
Normal file
36
app/src/main/res/drawable/ic_modify.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M20.071,9.586L15.828,5.343C15.047,4.562 13.781,4.562 13,5.343L7.343,11C6.562,11.781 6.562,13.047 7.343,13.828L11.586,18.071"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M28.929,37.414L33.171,41.657C33.952,42.438 35.219,42.438 36,41.657L41.657,36C42.438,35.219 42.438,33.953 41.657,33.172L37.414,28.929"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M36.021,6.322L41.677,11.979A2,2 0,0 1,41.677 14.808L14.807,41.678A2,2 0,0 1,11.979 41.678L6.322,36.021A2,2 132.403,0 1,6.322 33.192L33.192,6.322A2,2 102.008,0 1,36.021 6.322z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M24,24m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M20,28m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M28,20m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
</vector>
|
@@ -4,8 +4,7 @@
|
||||
android:tint="@color/white"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="#ffffffff"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z" />
|
||||
</vector>
|
||||
</vector>
|
20
app/src/main/res/drawable/ic_notify.xml
Normal file
20
app/src/main/res/drawable/ic_notify.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M10,38V18C10,10.268 16.268,4 24,4C31.732,4 38,10.268 38,18V38M4,38H44"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,44C26.761,44 29,41.761 29,39V38H19V39C19,41.761 21.239,44 24,44Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
@@ -3,8 +3,7 @@
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
|
||||
<path
|
||||
android:fillColor="@color/white"
|
||||
android:fillColor="#ffffffff"
|
||||
android:pathData="M192,736 L192,416C192,261.2 302,132.1 448,102.4L448,64C448,28.6 476.6,0 512,0 547.4,0 576,28.6 576,64L576,102.4C722,132.1 832,261.2 832,416L832,736 864.1,736C899.4,736 928,764.4 928,800 928,835.4 899.4,864 864.1,864L159.9,864C124.6,864 96,835.6 96,800 96,764.6 124.6,736 159.9,736L192,736ZM608,928C608,981 565,1024 512,1024 459,1024 416,981 416,928L608,928Z" />
|
||||
</vector>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_notify_update.xml
Normal file
9
app/src/main/res/drawable/ic_notify_update.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="50dp"
|
||||
android:height="50dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M906.4,791.6a247.9,247.9 0,0 0,-98.1 -186.5L808.3,399.4c0,-118.8 -85.1,-218.9 -197.4,-242.5v-4.7c0,-54.2 -44.5,-98.6 -98.8,-98.6 -54.3,0 -98.8,44.4 -98.8,98.6v4.7C300.8,180.5 215.7,280.4 215.7,399.4v205.8a247.7,247.7 0,0 0,-98.1 186.5h98.1v0.6h592.5v-0.6h98.1v-0.1zM491.1,970.4h24.5c64.3,0 117.8,-48.5 125.6,-110.7L383,859.8a126.8,126.8 0,0 0,125.6 110.7h-17.5z" />
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_page_bottom.xml
Normal file
12
app/src/main/res/drawable/ic_page_bottom.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m563.5,143.3m-41,0v0q-41,0 -41,41v573.4q0,41 41,41v0q41,0 41,-41v-573.4q0,-41 -41,-41z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M521.5,796.2 L318.2,593a41,41 0,1 0,-57.9 57.9l231.7,231.7a41,41 0,0 0,58.4 0.5L782.2,651.4a41,41 0,1 0,-57.9 -57.9z" />
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_page_top.xml
Normal file
12
app/src/main/res/drawable/ic_page_top.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m563.5,895.1m-41,0v0q-41,0 -41,-41v-573.4q0,-41 41,-41v0q41,0 41,41v573.4q0,41 -41,41z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M521.5,242.2 L318.2,445.4a41,41 0,1 1,-57.9 -57.9l231.7,-231.7a41,41 0,0 1,58.4 -0.5l231.7,231.7a41,41 0,1 1,-57.9 57.9z" />
|
||||
</vector>
|
13
app/src/main/res/drawable/ic_preference.xml
Normal file
13
app/src/main/res/drawable/ic_preference.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M44,16C44,22.627 38.627,28 32,28C29.973,28 28.064,27.497 26.39,26.61L9,44L4,39L21.39,21.61C20.503,19.936 20,18.027 20,16C20,9.373 25.373,4 32,4C34.027,4 35.936,4.502 37.61,5.39L30,13L35,18L42.61,10.39C43.498,12.064 44,13.973 44,16Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
30
app/src/main/res/drawable/ic_restart.xml
Normal file
30
app/src/main/res/drawable/ic_restart.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="4800"
|
||||
android:viewportHeight="4800">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M2270.9,56.1L2527.1,56.1A200,307.5 0,0 1,2727.1 363.6L2727.1,1098.6A200,307.5 0,0 1,2527.1 1406.1L2270.9,1406.1A200,307.5 0,0 1,2070.9 1098.6L2070.9,363.6A200,307.5 0,0 1,2270.9 56.1z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M2270.9,3406.1L2527.1,3406.1A200,307.5 0,0 1,2727.1 3713.6L2727.1,4448.6A200,307.5 0,0 1,2527.1 4756.1L2270.9,4756.1A200,307.5 0,0 1,2070.9 4448.6L2070.9,3713.6A200,307.5 0,0 1,2270.9 3406.1z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M646.7,835L827.8,653.9A200,307.5 135,0 1,1186.7 729.9L1706.4,1249.6A200,307.5 135,0 1,1782.4 1608.5L1601.3,1789.6A307.5,200 45,0 1,1242.4 1713.6L722.7,1193.9A307.5,200 45,0 1,646.7 835z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M3015.5,3203.8L3196.7,3022.7A200,307.5 135,0 1,3555.5 3098.7L4075.2,3618.4A307.5,200 45,0 1,4151.3 3977.3L3970.1,4158.4A307.5,200 45,0 1,3611.3 4082.4L3091.5,3562.7A307.5,200 45,0 1,3015.5 3203.8z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M49,2534.2L49,2278A200,307.5 90,0 1,356.5 2078L1091.5,2078A200,307.5 90,0 1,1399 2278L1399,2534.2A200,307.5 90,0 1,1091.5 2734.2L356.5,2734.2A200,307.5 90,0 1,49 2534.2z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M3399,2534.2L3399,2278.1A200,307.5 90,0 1,3706.5 2078.1L4441.5,2078.1A200,307.5 90,0 1,4749 2278.1L4749,2534.2A200,307.5 90,0 1,4441.5 2734.2L3706.5,2734.2A200,307.5 90,0 1,3399 2534.2z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M827.8,4158.4L646.7,3977.3A307.5,200 135,0 1,722.7 3618.4L1242.4,3098.7A200,307.5 45,0 1,1601.3 3022.7L1782.4,3203.8A200,307.5 45,0 1,1706.4 3562.7L1186.7,4082.4A200,307.5 45,0 1,827.8 4158.4z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M3196.7,1789.6L3015.5,1608.4A307.5,200 135,0 1,3091.5 1249.6L3611.3,729.9A307.5,200 135,0 1,3970.1 653.9L4151.3,835A200,307.5 45,0 1,4075.2 1193.9L3555.5,1713.6A200,307.5 45,0 1,3196.7 1789.6z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_success.xml
Normal file
9
app/src/main/res/drawable/ic_success.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1008.7"
|
||||
android:viewportHeight="1008.7">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M504.4,0C226.3,0 0,226.3 0,504.4 0,782.5 226.3,1008.7 504.4,1008.7c278.1,0 504.4,-226.3 504.4,-504.4C1008.7,226.3 782.5,0 504.4,0ZM786.6,407.7 L458.6,743.9c-7.8,8 -18.6,12.6 -29.8,12.6h-0.2c-11.1,0 -21.8,-4.4 -29.7,-12.3L222.5,567.9c-16.4,-16.4 -16.4,-43 0,-59.4 16.4,-16.4 43,-16.4 59.4,0L428.2,654.8 726.5,348.9c16.3,-16.6 42.9,-16.9 59.4,-0.7 16.6,16.2 16.9,42.8 0.7,59.4z" />
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_sync.xml
Normal file
12
app/src/main/res/drawable/ic_sync.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M628.5,544a224,224 0,0 0,-96 116.5l60.2,21.8a160,160 0,0 1,68.8 -83.2,152.6 152.6,0 0,1 117.4,-16 154.9,154.9 0,0 1,92.5 69.8l-39.4,28.8 116.2,32 11.8,-121.6 -35.8,25.3A217.9,217.9 0,0 0,628.5 544zM810.9,875.5a150.4,150.4 0,0 1,-118.1 9.6,155.8 155.8,0 0,1 -88.6,-74.6l40,-25.3 -114.2,-39 -17.9,121.6 37.1,-23.4A217.9,217.9 0,0 0,672 946.2a224,224 0,0 0,67.8 10.9,215 215,0 0,0 99.5,-24.6 221.1,221.1 0,0 0,111.4 -136l-61.4,-17.9a155.2,155.2 0,0 1,-78.4 97z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M736,448a285.1,285.1 0,0 1,138.6 35.5L874.6,119a48,48 0,0 0,-48 -48h-640a48,48 0,0 0,-48 48v768a48,48 0,0 0,48 48h341.8A288,288 0,0 1,736 448zM314.6,311.4h320v64h-320zM314.6,439.4h192v64h-192z" />
|
||||
</vector>
|
@@ -4,8 +4,7 @@
|
||||
android:tint="@color/white"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="#ffffffff"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM15.29,16.71L11,12.41V7h2v4.59l3.71,3.71L15.29,16.71z" />
|
||||
</vector>
|
||||
</vector>
|
34
app/src/main/res/drawable/ic_theme.xml
Normal file
34
app/src/main/res/drawable/ic_theme.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M37,37C39.209,37 41,35.209 41,33C41,31.527 39.667,29.527 37,27C34.333,29.527 33,31.527 33,33C33,35.209 34.791,37 37,37Z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M20.854,5.504L24.389,9.04"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M23.682,8.333L8.125,23.889L19.439,35.203L34.995,19.646L23.682,8.333Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M12,20.073L28.961,25.65"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M4,43H44"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round" />
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_unsupported.xml
Normal file
12
app/src/main/res/drawable/ic_unsupported.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="52dp"
|
||||
android:viewportWidth="739.56"
|
||||
android:viewportHeight="739.56">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m207.74,575.04c-105.24,0 -192,-86.76 -192,-192 0,-105.24 86.76,-192 192,-192 36.98,0 72.53,9.96 103.82,29.87 12.8,8.53 17.07,25.6 8.53,39.82 -8.53,12.8 -25.6,17.07 -39.82,8.53 -21.33,-14.22 -46.93,-21.33 -72.53,-21.33 -73.96,0 -135.11,61.16 -135.11,135.11 0,73.96 61.16,135.11 135.11,135.11 73.96,0 135.11,-61.16 135.11,-135.11 0,-15.64 12.8,-28.44 28.44,-28.44 15.64,0 28.44,12.8 28.44,28.44 0,105.24 -86.76,192 -192,192z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m534.85,575.04c-39.82,0 -78.22,-11.38 -109.51,-34.13 -12.8,-8.53 -15.64,-27.02 -7.11,-39.82 8.53,-12.8 27.02,-15.64 39.82,-7.11 22.76,15.64 49.78,24.18 76.8,24.18 73.96,0 135.11,-61.16 135.11,-135.11 0,-73.96 -61.16,-135.11 -135.11,-135.11 -73.96,0 -135.11,61.16 -135.11,135.11 0,15.64 -12.8,28.44 -28.44,28.44 -15.64,0 -28.44,-12.8 -28.44,-28.44 0,-105.24 86.76,-192 192,-192 105.24,0 192,85.33 192,192 0,105.24 -86.76,192 -192,192z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_warn.xml
Normal file
9
app/src/main/res/drawable/ic_warn.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m512,794a44.8,44.8 0,1 1,44.8 -44.8,44.8 44.8,0 0,1 -44.8,44.8zM471.9,230.8a40.1,40.1 0,0 1,80.2 0v369.1a40.1,40.1 0,0 1,-79.8 0zM512,0A512,512 0,1 0,1024 512,512 512,0 0,0 512,0Z" />
|
||||
</vector>
|
@@ -25,7 +25,7 @@
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:src="@mipmap/ic_back"
|
||||
android:src="@drawable/ic_back"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="返回" />
|
||||
|
||||
@@ -59,19 +59,18 @@
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_up"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@mipmap/ic_page_top"
|
||||
android:layout_width="27dp"
|
||||
android:layout_height="27dp"
|
||||
android:src="@drawable/ic_page_top"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="滚动到顶部" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_down"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:src="@mipmap/ic_page_bottom"
|
||||
android:layout_width="27dp"
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginEnd="13dp"
|
||||
android:src="@drawable/ic_page_bottom"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="滚动到底部" />
|
||||
|
||||
@@ -80,7 +79,7 @@
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_filter"
|
||||
android:src="@drawable/ic_filter"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="按条件过滤" />
|
||||
|
||||
@@ -89,7 +88,7 @@
|
||||
android:layout_width="23dp"
|
||||
android:layout_height="23dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_sync"
|
||||
android:src="@drawable/ic_sync"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="同步列表" />
|
||||
</LinearLayout>
|
||||
@@ -111,7 +110,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_about"
|
||||
android:src="@drawable/ic_about"
|
||||
android:tint="@color/colorTextDark" />
|
||||
|
||||
<TextView
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user