diff --git a/.idea/misc.xml b/.idea/misc.xml index 0682c959..31799fa1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,8 +9,10 @@ + + diff --git a/README.md b/README.md index 3521350b..35e1e243 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # MIUI 原生通知图标 -![Eclipse Marketplace](https://img.shields.io/badge/build-pending-dbab09) +![Eclipse Marketplace](https://img.shields.io/badge/build-passing-brightgreen) ![Eclipse Marketplace](https://img.shields.io/badge/license-AGPL3.0-blue) -![Eclipse Marketplace](https://img.shields.io/badge/version-v1.36-green) +![Eclipse Marketplace](https://img.shields.io/badge/version-v1.5-green)


@@ -12,7 +12,7 @@ Fix the native notification bar icon function abandoned by the MIUI development # 开始使用 点击下载最新版本 -![Eclipse Marketplace](https://img.shields.io/badge/download-v1.36-green) +![Eclipse Marketplace](https://img.shields.io/badge/download-v1.5-green)

⚠️ 适配说明
diff --git a/app/build.gradle b/app/build.gradle index 3519878a..b98b7e93 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { defaultConfig { applicationId "com.fankes.miui.notify" - minSdk 23 + minSdk 28 targetSdk 31 versionCode rootProject.ext.appVersionCode versionName rootProject.ext.appVersionName @@ -42,6 +42,9 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + viewBinding true + } } /** 移除无效耗时 lint Task */ @@ -57,6 +60,9 @@ tasks.whenTaskAdded { dependencies { implementation "com.github.topjohnwu.libsu:core:3.1.2" + implementation 'androidx.annotation:annotation:1.3.0' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' compileOnly 'de.robv.android.xposed:api:82' implementation 'com.highcapable.yukihookapi:api:1.0.1' ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e84fd702..596c36e8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,43 +16,42 @@ - - - + - + android:targetActivity=".ui.MainActivity"> + + \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/data/LoginDataSource.kt b/app/src/main/java/com/fankes/miui/notify/data/LoginDataSource.kt new file mode 100644 index 00000000..b295bf62 --- /dev/null +++ b/app/src/main/java/com/fankes/miui/notify/data/LoginDataSource.kt @@ -0,0 +1,24 @@ +package com.fankes.miui.notify.data + +import com.fankes.miui.notify.data.model.LoggedInUser +import java.io.IOException + +/** + * Class that handles authentication w/ login credentials and retrieves user information. + */ +class LoginDataSource { + + fun login(username: String, password: String): Result { + try { + // TODO: handle loggedInUser authentication + val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe") + return Result.Success(fakeUser) + } catch (e: Throwable) { + return Result.Error(IOException("Error logging in", e)) + } + } + + fun logout() { + // TODO: revoke authentication + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/data/LoginRepository.kt b/app/src/main/java/com/fankes/miui/notify/data/LoginRepository.kt new file mode 100644 index 00000000..43dc2d9b --- /dev/null +++ b/app/src/main/java/com/fankes/miui/notify/data/LoginRepository.kt @@ -0,0 +1,46 @@ +package com.fankes.miui.notify.data + +import com.fankes.miui.notify.data.model.LoggedInUser + +/** + * Class that requests authentication and user information from the remote data source and + * maintains an in-memory cache of login status and user credentials information. + */ + +class LoginRepository(val dataSource: LoginDataSource) { + + // in-memory cache of the loggedInUser object + var user: LoggedInUser? = null + private set + + val isLoggedIn: Boolean + get() = user != null + + init { + // If user credentials will be cached in local storage, it is recommended it be encrypted + // @see https://developer.android.com/training/articles/keystore + user = null + } + + fun logout() { + user = null + dataSource.logout() + } + + fun login(username: String, password: String): Result { + // handle login + val result = dataSource.login(username, password) + + if (result is Result.Success) { + setLoggedInUser(result.data) + } + + return result + } + + private fun setLoggedInUser(loggedInUser: LoggedInUser) { + this.user = loggedInUser + // If user credentials will be cached in local storage, it is recommended it be encrypted + // @see https://developer.android.com/training/articles/keystore + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/data/Result.kt b/app/src/main/java/com/fankes/miui/notify/data/Result.kt new file mode 100644 index 00000000..01cbbeb0 --- /dev/null +++ b/app/src/main/java/com/fankes/miui/notify/data/Result.kt @@ -0,0 +1,18 @@ +package com.fankes.miui.notify.data + +/** + * A generic class that holds a value with its loading status. + * @param + */ +sealed class Result { + + data class Success(val data: T) : Result() + data class Error(val exception: Exception) : Result() + + override fun toString(): String { + return when (this) { + is Success<*> -> "Success[data=$data]" + is Error -> "Error[exception=$exception]" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/data/model/LoggedInUser.kt b/app/src/main/java/com/fankes/miui/notify/data/model/LoggedInUser.kt new file mode 100644 index 00000000..d2f3ff55 --- /dev/null +++ b/app/src/main/java/com/fankes/miui/notify/data/model/LoggedInUser.kt @@ -0,0 +1,9 @@ +package com.fankes.miui.notify.data.model + +/** + * Data class that captures user information for logged in users retrieved from LoginRepository + */ +data class LoggedInUser( + val userId: String, + val displayName: String +) \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/ui/ConfigureActivity.kt b/app/src/main/java/com/fankes/miui/notify/ui/ConfigureActivity.kt index 3e5acf99..9bb0623f 100644 --- a/app/src/main/java/com/fankes/miui/notify/ui/ConfigureActivity.kt +++ b/app/src/main/java/com/fankes/miui/notify/ui/ConfigureActivity.kt @@ -35,6 +35,7 @@ import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.constraintlayout.utils.widget.ImageFilterView +import androidx.core.view.isVisible import com.fankes.miui.notify.R import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf @@ -43,20 +44,58 @@ import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf import com.fankes.miui.notify.params.IconPackParams import com.fankes.miui.notify.ui.base.BaseActivity import com.fankes.miui.notify.utils.SystemUITool +import com.fankes.miui.notify.utils.showDialog import com.fankes.miui.notify.view.MaterialSwitch +import com.google.android.material.textfield.TextInputEditText class ConfigureActivity : BaseActivity() { + /** 当前筛选条件 */ + private var filterText = "" + + /** 回调适配器改变 */ + private var onChanged: (() -> Unit)? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_config) /** 返回按钮点击事件 */ findViewById(R.id.title_back_icon).setOnClickListener { onBackPressed() } - /** 设置标题个数文本 */ - findViewById(R.id.config_title_count_text).text = "已适配 ${IconPackParams.iconDatas.size} 个 APP 的通知图标" - /** 设置搜索按钮点击事件 */ - findViewById(R.id.config_title_search).setOnClickListener { - Toast.makeText(this, "后期开放", Toast.LENGTH_SHORT).show() + /** 刷新适配器结果相关 */ + refreshAdapterResult() + /** 设置过滤按钮点击事件 */ + findViewById(R.id.config_title_filter).setOnClickListener { + showDialog { + title = "按条件过滤" + var editText: TextInputEditText + addView(R.layout.dia_icon_filter).apply { + editText = findViewById(R.id.dia_icon_filter_input_edit).apply { + requestFocus() + invalidate() + if (filterText.isNotBlank()) { + setText(filterText) + setSelection(filterText.length) + } + } + } + confirmButton { + if (editText.text.toString().isNotBlank()) { + filterText = editText.text.toString().trim() + onChanged?.invoke() + refreshAdapterResult() + } else { + Toast.makeText(applicationContext, "条件不能为空", Toast.LENGTH_SHORT).show() + it.performClick() + } + } + cancelButton() + if (filterText.isNotBlank()) + neutralButton(text = "清除条件") { + filterText = "" + onChanged?.invoke() + refreshAdapterResult() + } + } } /** 设置列表元素和 Adapter */ findViewById(R.id.config_list_view).apply { @@ -64,9 +103,9 @@ class ConfigureActivity : BaseActivity() { private val inflater = LayoutInflater.from(context) - override fun getCount() = IconPackParams.iconDatas.size + override fun getCount() = iconDatas.size - override fun getItem(position: Int) = IconPackParams.iconDatas[position] + override fun getItem(position: Int) = iconDatas[position] override fun getItemId(position: Int) = position.toLong() @@ -118,7 +157,7 @@ class ConfigureActivity : BaseActivity() { lateinit var switchOpen: MaterialSwitch lateinit var switchAll: MaterialSwitch } - } + }.apply { onChanged = { notifyDataSetChanged() } } } /** 设置点击事件 */ findViewById(R.id.config_cbr_button).setOnClickListener { @@ -134,4 +173,22 @@ class ConfigureActivity : BaseActivity() { } } } + + /** 刷新适配器结果相关 */ + private fun refreshAdapterResult() { + findViewById(R.id.config_title_count_text).text = + if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标" + else "“${filterText}” 匹配到 ${iconDatas.size} 个结果" + findViewById(R.id.config_list_no_data_view).isVisible = iconDatas.isEmpty() + } + + /** + * 当前结果下的图标数组 + * @return [Array] + */ + private val iconDatas + get() = if (filterText.isBlank()) IconPackParams.iconDatas + else IconPackParams.iconDatas.filter { + it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase()) + }.toTypedArray() } \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/utils/DialogBuilder.kt b/app/src/main/java/com/fankes/miui/notify/utils/DialogBuilder.kt index 605ca663..5b98646f 100644 --- a/app/src/main/java/com/fankes/miui/notify/utils/DialogBuilder.kt +++ b/app/src/main/java/com/fankes/miui/notify/utils/DialogBuilder.kt @@ -20,7 +20,7 @@ * * This file is Created by fankes on 2022/1/7. */ -@file:Suppress("unused") +@file:Suppress("unused", "DEPRECATION") package com.fankes.miui.notify.utils @@ -28,7 +28,11 @@ import android.app.AlertDialog import android.content.Context import android.graphics.Color import android.graphics.drawable.GradientDrawable - +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import kotlin.math.round /** * 构造对话框 @@ -44,6 +48,8 @@ class DialogBuilder(private val context: Context) { private var instance: AlertDialog.Builder? = null // 实例对象 + private var customLayoutView: View? = null // 自定义布局 + init { instance = AlertDialog.Builder(context, android.R.style.Theme_Material_Light_Dialog) } @@ -65,6 +71,16 @@ class DialogBuilder(private val context: Context) { instance?.setMessage(value) } + /** + * 设置对话框自定义布局 + * @param resId 属性资源 Id + * @return [View] + */ + fun addView(resId: Int): View { + customLayoutView = LayoutInflater.from(context).inflate(resId, null) + return customLayoutView ?: error("Inflate $resId failed") + } + /** * 设置对话框确定按钮 * @param text 按钮文本内容 @@ -91,6 +107,9 @@ class DialogBuilder(private val context: Context) { /** 显示对话框 */ internal fun show() = instance?.create()?.apply { + val dm = DisplayMetrics() + (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(dm) + customLayoutView?.let { setView(it.apply { minimumWidth = round(dm.widthPixels / 1.3).toInt() }) } window?.setBackgroundDrawable(GradientDrawable( GradientDrawable.Orientation.TOP_BOTTOM, intArrayOf(Color.WHITE, Color.WHITE) diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml index c782c845..06908911 100644 --- a/app/src/main/res/layout/activity_config.xml +++ b/app/src/main/res/layout/activity_config.xml @@ -26,11 +26,13 @@ android:layout_marginStart="10dp" android:layout_marginEnd="25dp" android:src="@mipmap/back" - android:tint="@color/colorTextGray" /> + android:tint="@color/colorTextGray" + android:tooltipText="返回" /> @@ -56,12 +58,13 @@ + android:src="@mipmap/icon_filter" + android:tint="@color/colorTextGray" + android:tooltipText="按条件过滤" /> - + android:layout_weight="1"> + + + + + @@ -359,7 +359,7 @@ android:layout_marginBottom="10dp" android:alpha="0.8" android:lineSpacingExtra="6dp" - android:text="Q.这个模块是如何诞生的?\nA.这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块,这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI 选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏,通知中“setSmallIcon”不再有效,这个模块就是为了修复被 MIUI 开发组忽略的图标问题,并完美地给 MIUI 修复了黑白块图标的问题。" + android:text="Q.这个模块是如何诞生的?\nA.这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。\n这当然不是系统的错,而是国内 APP 和 MIPUSH 的通知极其不规范的通知图标设计。\n但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 2021-5-18 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。\n对于 Android 开发者来说,官方文档中的 “setSmallIcon” 不再适用于魔改后的 MIUI,这将会严重破坏非常多的状态图标。\n当然,国内的手机生态除了 MIPUSH 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。\n但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 MIUI 修复了黑白块图标的问题。" android:textColor="@color/colorTextDark" android:textSize="12sp" /> @@ -435,7 +435,7 @@ android:layout_height="wrap_content" android:alpha="0.8" android:lineSpacingExtra="6dp" - android:text="本软件是免费开源项目,遵循 GPL 协议,你可以点击这里前往 Github 查看源码以及获取模块更新。\n严禁以任何形式贩卖、商用本软件,否则开发者有权追究其法律责任。" + android:text="本软件是免费开源项目,遵循 AGPL3.0 协议,你可以点击这里前往 Github 查看源码以及获取模块更新。" android:textColor="@color/colorTextDark" android:textSize="12sp" /> diff --git a/app/src/main/res/layout/dia_icon_filter.xml b/app/src/main/res/layout/dia_icon_filter.xml new file mode 100644 index 00000000..dfdbfbba --- /dev/null +++ b/app/src/main/res/layout/dia_icon_filter.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/icon_search.png b/app/src/main/res/mipmap-xxhdpi/icon_search.png deleted file mode 100644 index 35ebe1d2..00000000 Binary files a/app/src/main/res/mipmap-xxhdpi/icon_search.png and /dev/null differ diff --git a/build.gradle b/build.gradle index 8c9ed4fa..11024061 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ plugins { } ext { - appVersionName = "1.36(pending)" - appVersionCode = 8 + appVersionName = "1.5" + appVersionCode = 9 } task clean(type: Delete) {