diff --git a/.gitmodules b/.gitmodules
index b12ee233..8135687b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
-[submodule "blockmiui"]
- path = blockmiui
- url = https://github.com/Block-Network/blockmiui.git
+[submodule "hyperx-compose"]
+ path = hyperx-compose
+ url = https://github.com/HowieHChen/hyperx-compose.git
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2dd1c1c6..9ff9e024 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -5,6 +5,7 @@ plugins {
autowire(libs.plugins.org.jetbrains.kotlin.android)
autowire(libs.plugins.org.jetbrains.kotlin.plugin.serialization)
autowire(libs.plugins.com.google.devtools.ksp)
+ autowire(libs.plugins.org.jetbrains.kotlin.plugin.compose)
}
android {
@@ -85,17 +86,19 @@ android {
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_17
- targetCompatibility = JavaVersion.VERSION_17
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
}
kotlinOptions {
- jvmTarget = JavaVersion.VERSION_17.majorVersion
+ jvmTarget = JavaVersion.VERSION_21.majorVersion
}
}
dependencies {
- implementation(projects.blockmiui)
+ implementation(projects.hyperxCompose)
+
+ implementation(org.jetbrains.kotlinx.kotlinx.serialization.json)
compileOnly(de.robv.android.xposed.api)
implementation(com.highcapable.yukihookapi.api)
ksp(com.highcapable.yukihookapi.ksp.xposed)
diff --git a/app/gradle.properties b/app/gradle.properties
index 9219fb6a..21427d79 100644
--- a/app/gradle.properties
+++ b/app/gradle.properties
@@ -5,5 +5,5 @@ project.compileSdk=${project.targetSdk}
project.targetSdk=35
project.minSdk=31
-project.versionCode = 3000
-project.versionName = "3.0"
\ No newline at end of file
+project.versionCode = 3100
+project.versionName = "3.1-compose"
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index f6e61d48..e358e55d 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -23,4 +23,4 @@
*** inflate(android.view.LayoutInflater);
}
-keep class kotlin.Unit
--keep class com.gswxxn.restoresplashscreen.ui.BaseActivity
\ No newline at end of file
+-keep class com.gswxxn.restoresplashscreen.ui.MainActivity
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index de85bc4c..248fac6d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,27 +19,12 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Starting">
-
-
-
-
-
+ android:windowSoftInputMode="adjustResize">
-
@@ -49,10 +34,9 @@
android:enabled="true"
android:exported="true"
android:label="@string/app_name"
- android:targetActivity=".ui.MainSettingsActivity">
+ android:targetActivity=".ui.MainActivity">
-
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/data/DataConst.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/data/DataConst.kt
index 51a7491a..ec6295b6 100644
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/data/DataConst.kt
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/data/DataConst.kt
@@ -56,4 +56,10 @@ object DataConst {
// 开发者设置
val ENABLE_DEV_SETTINGS = PrefsData("enable_dev_settings", false)
val DEV_ICON_ROUND_CORNER_RATE = PrefsData("dev_icon_round_corner", 25)
+ val HAZE_TINT_ALPHA_LIGHT = PrefsData("module_blur_tint_light", 60)
+ val HAZE_TINT_ALPHA_DARK = PrefsData("module_blur_tint_dark", 50)
+
+ // 模块应用设置
+ val BLUR = PrefsData("module_blur", true)
+ val SPLIT_VIEW = PrefsData("module_split", false)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/data/Pages.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/data/Pages.kt
new file mode 100644
index 00000000..06a63dc6
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/data/Pages.kt
@@ -0,0 +1,24 @@
+package com.gswxxn.restoresplashscreen.data
+
+object Pages {
+ const val MAIN = "MainPage"
+ const val ABOUT = "AboutPage"
+ const val BASIC_SETTINGS = "BasicPage"
+ const val SCOPE_SETTINGS = "ScopePage"
+ const val ICON_SETTINGS = "IconPage"
+ const val BOTTOM_SETTINGS = "BottomPage"
+ const val BACKGROUND_SETTINGS = "BackgroundPage"
+ const val DISPLAY_SETTINGS = "DisplayPage"
+ const val DEVELOPER_SETTINGS = "DevPage"
+
+ const val CONFIG_CUSTOM_SCOPE = "CCustomScopePage"
+ const val CONFIG_IGNORE_APP_ICON = "CIgnoreAppIconPage"
+ const val CONFIG_HIDE_SPLASH_ICON = "CHideIconPage"
+ const val CONFIG_REMOVE_BRANDING = "CRemoveBrandingPage"
+ const val CONFIG_BACKGROUND_EXCEPT = "CBackgroundExceptPage"
+ const val CONFIG_BACKGROUND_INDIVIDUALLY = "CBgIndividualPage"
+ const val CONFIG_MIN_DURATION = "CMinDurationPage"
+ const val CONFIG_FORCE_SHOW_SPLASH = "CForceSplashPage"
+
+ const val CONFIG_COLOR_PICKER = "CColorPickerPage"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/hook/systemui/IconHookHandler.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/hook/systemui/IconHookHandler.kt
index d2bb6e4a..eb5f2852 100644
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/hook/systemui/IconHookHandler.kt
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/hook/systemui/IconHookHandler.kt
@@ -1,6 +1,7 @@
package com.gswxxn.restoresplashscreen.hook.systemui
import android.content.ComponentName
+import android.content.Context
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.Outline
@@ -10,12 +11,12 @@ import android.graphics.Shader
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
+import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.FrameLayout
import android.widget.ImageView
-import cn.fkj233.ui.activity.dp2px
import com.gswxxn.restoresplashscreen.data.DataConst
import com.gswxxn.restoresplashscreen.hook.NewSystemUIHooker
import com.gswxxn.restoresplashscreen.hook.base.BaseHookHandler
@@ -348,4 +349,6 @@ object IconHookHandler : BaseHookHandler() {
}
return null
}
-}
\ No newline at end of file
+}
+
+fun dp2px(context: Context, dpValue: Float): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.resources.displayMetrics).toInt()
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/AboutPageActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/AboutPageActivity.kt
deleted file mode 100644
index d003f262..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/AboutPageActivity.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.net.Uri
-import android.widget.LinearLayout
-import android.widget.TextView
-import android.widget.Toast
-import cn.fkj233.ui.activity.dp2px
-import com.gswxxn.restoresplashscreen.BuildConfig
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.data.RoundDegree
-import com.gswxxn.restoresplashscreen.databinding.ActivityAboutPageBinding
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.utils.GraphicUtils.drawable2Bitmap
-import com.gswxxn.restoresplashscreen.utils.GraphicUtils.roundBitmapByShader
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 关于页面
- */
-class AboutPageActivity : BaseActivity() {
-
- override fun onCreate() {
- binding.apply {
- titleBackIcon.setOnClickListener { finishAfterTransition() }
-
- appIcon.setImageBitmap(
- roundBitmapByShader(
- getDrawable(R.mipmap.ic_launcher)?.let {
- drawable2Bitmap(
- it,
- it.intrinsicHeight * 2
- )
- }, RoundDegree.RoundCorner
- )
- )
-
- var count = 0
- var lastClickTime: Long = 0
- appIcon.setOnClickListener {
- val now = System.currentTimeMillis()
-
- if (now - lastClickTime < 500) count++
- else count = 1
-
- lastClickTime = now
-
- if (count != 5) return@setOnClickListener
- count = 0
-
- if (!prefs().get(DataConst.ENABLE_DEV_SETTINGS)) {
- prefs().edit { put(DataConst.ENABLE_DEV_SETTINGS, true) }
- Toast.makeText(
- this@AboutPageActivity,
- getString(R.string.enable_dev_settings),
- Toast.LENGTH_SHORT
- ).show()
- } else {
- Toast.makeText(
- this@AboutPageActivity,
- getString(R.string.enable_dev_settings),
- Toast.LENGTH_SHORT
- ).show()
- }
- }
-
- miluIcon.setImageBitmap(
- roundBitmapByShader(
- getDrawable(R.mipmap.img_developer)?.let {
- drawable2Bitmap(
- it,
- it.intrinsicHeight
- )
- }, RoundDegree.Circle
- )
- )
-
- version.text = getString(R.string.version, BuildConfig.VERSION_NAME)
-
- developerMilu.setOnClickListener {
- toast(getString(R.string.follow_me))
- try {
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("coolmarket://u/1189245")))
- } catch (e: Exception) {
- startActivity(
- Intent(
- Intent.ACTION_VIEW,
- Uri.parse("https://www.coolapk.com/u/1189245")
- )
- )
- }
- }
-
- githubRepo.setOnClickListener {
- toast(getString(R.string.star_project))
- startActivity(
- Intent(
- Intent.ACTION_VIEW,
- Uri.parse("https://github.com/GSWXXN/RestoreSplashScreen")
- )
- )
- }
-
- iconfont.setOnClickListener {
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://www.iconfont.cn")))
- }
-
- licenseLayout.apply {
- addLicenseV(
- "MIUINativeNotifyIcon",
- "fankes",
- "https://github.com/fankes/MIUINativeNotifyIcon",
- "GNU Affero General Public License v3.0"
- )
- addLicenseV(
- "Hide-My-Applist",
- "Dr-TSNG",
- "https://github.com/Dr-TSNG/Hide-My-Applist",
- "GNU Affero General Public License v3.0"
- )
- addLicenseV(
- "YukiHookAPI",
- "fankes",
- "https://github.com/fankes/YukiHookAPI",
- "MIT License"
- )
- addLicenseV(
- "MiuiHomeR",
- "YuKongA",
- "https://github.com/qqlittleice/MiuiHome_R",
- "GNU General Public License v3.0"
- )
- addLicenseV(
- "BlockMIUI",
- "577fkj",
- "https://github.com/Block-Network/blockmiui",
- "GNU Lesser General Public License v2.1"
- )
- }
- }
- }
-
- @SuppressLint("SetTextI18n")
- private fun LinearLayout.addLicenseV(
- projectName: String,
- author: String,
- url: String,
- licenseName: String
- ) {
- addView(LinearLayout(this@AboutPageActivity).apply {
- layoutParams = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- ).apply {
- setMargins(
- 0,
- dp2px(this@AboutPageActivity, 10F),
- 0,
- dp2px(this@AboutPageActivity, 15F),
- )
- orientation = LinearLayout.VERTICAL
- }
- addView(
- TextView(this@AboutPageActivity).apply {
- text = "$projectName - $author"
- textSize = 15F
- setTextColor(getColor(R.color.colorTextGray))
- }
- )
- addView(
- TextView(this@AboutPageActivity).apply {
- text = "$url\n$licenseName"
- textSize = 12F
- setTextColor(getColor(R.color.colorTextDark))
- setLineSpacing(dp2px(this@AboutPageActivity, 3F).toFloat(), 1F)
- }
- )
- setOnClickListener {
- toast(getString(R.string.thanks_to, author))
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
- }
- }
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/BaseActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/BaseActivity.kt
deleted file mode 100644
index 44ef1e37..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/BaseActivity.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.app.Activity
-import android.graphics.Color
-import android.os.Bundle
-import android.view.View
-import androidx.core.view.WindowCompat
-import androidx.viewbinding.ViewBinding
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.isDarkMode
-import com.highcapable.yukihookapi.hook.factory.method
-import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
-import java.lang.reflect.ParameterizedType
-
-/**
- * 改自 [MIUINativeNotifyIcon](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/java/com/fankes/miui/notify/ui/activity/base/BaseActivity.kt)
- */
-abstract class BaseActivity : Activity() {
- lateinit var binding: VB
-
- /**
- * 批量显示或隐藏 [View]
- *
- * @param isShow [Boolean]
- * @param views [View]
- */
- open fun showView(isShow: Boolean = true, vararg views: View?) {
- for (element in views) {
- element?.visibility = if (isShow) View.VISIBLE else View.GONE
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // 安卓 15 以下仍需要
- window.statusBarColor = Color.TRANSPARENT
- window.navigationBarColor = Color.TRANSPARENT
- window.isNavigationBarContrastEnforced = false
- WindowCompat.setDecorFitsSystemWindows(window, false)
- WindowCompat.getInsetsController(window, window.decorView).apply {
- isAppearanceLightStatusBars = !isDarkMode(this@BaseActivity)
- isAppearanceLightNavigationBars = !isDarkMode(this@BaseActivity)
- }
-
- // 通过反射绑定布局
- javaClass.genericSuperclass.also { type ->
- if (type is ParameterizedType) {
- binding = (type.actualTypeArguments[0] as Class<*>).method {
- name = "inflate"
- param(LayoutInflaterClass)
- }.get().invoke(layoutInflater) ?: error("binding failed")
- setContentView(binding.root)
- } else error("binding but got wrong type")
- }
-
- /** 装载子类 */
- onCreate()
- }
-
- /** 回调 [onCreate] 方法 */
- abstract fun onCreate()
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ColorSelectActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ColorSelectActivity.kt
deleted file mode 100644
index 293284ef..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ColorSelectActivity.kt
+++ /dev/null
@@ -1,427 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.content.res.Configuration
-import android.graphics.Bitmap
-import android.graphics.BitmapShader
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Shader
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.ColorDrawable
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.LayerDrawable
-import android.os.Build
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.Gravity
-import android.view.MotionEvent
-import android.view.View
-import android.view.ViewGroup
-import android.widget.EditText
-import android.widget.LinearLayout
-import android.widget.Magnifier
-import android.widget.SeekBar
-import android.widget.TextView
-import androidx.palette.graphics.Palette
-import cn.fkj233.ui.activity.data.LayoutPair
-import cn.fkj233.ui.activity.data.Padding
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.view.LinearContainerV
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import cn.fkj233.ui.dialog.MIUIDialog
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivityColorSelectBinding
-import com.gswxxn.restoresplashscreen.utils.BlockMIUIHelper.addBlockMIUIView
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.utils.GraphicUtils.drawable2Bitmap
-import com.gswxxn.restoresplashscreen.utils.GraphicUtils.getBgColor
-import com.gswxxn.restoresplashscreen.utils.IconPackManager
-import com.highcapable.yukihookapi.hook.factory.method
-import com.highcapable.yukihookapi.hook.factory.prefs
-import java.util.Locale
-import java.util.regex.Pattern
-
-/**
- * 选择颜色的 Activity
- */
-class ColorSelectActivity : BaseActivity() {
- companion object {
- lateinit var huePanel: Drawable
-
- /** 判断 [huePanel] 是否被初始化 */
- fun isHuePanelInitialized() = ::huePanel.isInitialized
- }
-
- private var currentColor: Int? = null
- private var isSettingOverallBgColor = false
- private lateinit var pkgName: String
- private var resetColor = false
- private var selectedColor = false
-
- private var isDarkMode = false
-
- private lateinit var seekBarR: SeekBar
- private lateinit var seekBarG: SeekBar
- private lateinit var seekBarB: SeekBar
- private lateinit var seekBarH: SeekBar
- private lateinit var seekBarS: SeekBar
- private lateinit var seekBarV: SeekBar
-
- private lateinit var statusR: TextView
- private lateinit var statusG: TextView
- private lateinit var statusB: TextView
- private lateinit var statusH: TextView
- private lateinit var statusS: TextView
- private lateinit var statusV: TextView
-
- private var hsvColor = floatArrayOf(0f, 0f, 0f)
- private var color = 0
- @SuppressLint("SetTextI18n")
- set(value) {
- field = value
- resetColor = false
- seekBarR.progress = Color.red(color)
- seekBarG.progress = Color.green(color)
- seekBarB.progress = Color.blue(color)
- binding.colorString.text = "#${Integer.toHexString(value).substring(2).uppercase(Locale.ROOT)}"
- binding.demoImage.background = ColorDrawable(value)
-
- statusR.text = "${Color.red(color)} / 255"
- statusG.text = "${Color.green(color)} / 255"
- statusB.text = "${Color.blue(color)} / 255"
- statusH.text = "${hsvColor[0].toInt()} / 360"
- statusS.text = "%.2f / 100".format(hsvColor[1] * 100)
- statusV.text = "%.2f / 100".format(hsvColor[2] * 100)
- }
-
- @SuppressLint("ClickableViewAccessibility")
- override fun onCreate() {
- isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
-
- drawHuePanel()
-
- if (intent.getBooleanExtra(ConstValue.EXTRA_MESSAGE_OVERALL_BG_COLOR, false)) {
- isSettingOverallBgColor = true
- pkgName = packageName
- currentColor = Color.parseColor(
- prefs().get(
- if (isDarkMode)
- DataConst.OVERALL_BG_COLOR_NIGHT
- else
- DataConst.OVERALL_BG_COLOR
- )
- )
- } else {
- pkgName = intent.getStringExtra(ConstValue.EXTRA_MESSAGE_PACKAGE_NAME)!!
- currentColor = intent.getStringExtra(ConstValue.EXTRA_MESSAGE_CURRENT_COLOR)?.let { Color.parseColor(it) }
- }
-
- seekBarR = createSeekBar(255, 0xFFF36060.toInt()) {
- Color.valueOf(color).apply { setRGBColor(Color.valueOf(((it - 0.5) / 255).toFloat(), green(), blue()).toArgb()) }
- }
- seekBarG = createSeekBar(255, 0xFF5FF25F.toInt()) {
- Color.valueOf(color).apply { setRGBColor(Color.valueOf(red(), ((it - 0.5) / 255).toFloat(), blue()).toArgb()) }
- }
- seekBarB = createSeekBar(255, 0xFF5F5FF3.toInt()) {
- Color.valueOf(color).apply { setRGBColor(Color.valueOf(red(), green(), ((it - 0.5) / 255).toFloat()).toArgb()) }
- }
- seekBarH = createSeekBar(360, 0) { setHsvColor(0, it.toFloat()) }
- seekBarS = createSeekBar(10000) { setHsvColor(1, it.toFloat() / 10000) }
- seekBarV = createSeekBar(10000) { setHsvColor(2, it.toFloat() / 10000) }
-
- fun textV() = TextV("", textSize = 13.75f, colorId = cn.fkj233.ui.R.color.author_tips, padding = Padding(0, 0, 0, 0)).create(this, null) as TextView
- statusR = textV()
- statusG = textV()
- statusB = textV()
- statusH = textV()
- statusS = textV()
- statusV = textV()
-
- // 配置中间图标
- val icon = (
- IconPackManager(this, prefs().get(DataConst.ICON_PACK_PACKAGE_NAME))
- .getIconByPackageName(pkgName) // 优先获取图标包中的图标
- ?: packageManager.getApplicationIcon(pkgName) // 使用默认方式获取图标
- ).let {
- binding.demoIcon.setImageDrawable(it)
- drawable2Bitmap(it, 48)
- }
-
- val magnifierSize = dp2px(this@ColorSelectActivity, 100f)
- val magnifier = Magnifier.Builder(binding.demoLayout)
- .setDefaultSourceToMagnifierOffset(0, -dp2px(this@ColorSelectActivity, 80f))
- .setInitialZoom(5f)
- .setOverlay(getDrawable(R.drawable.ic_collimation))
- .setSize(magnifierSize, magnifierSize)
- .setCornerRadius((magnifierSize / 2).toFloat())
- .build()
-
- binding.demoIcon.setOnTouchListener { v, event ->
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
- val viewPosition = IntArray(2)
- binding.demoLayout.getLocationOnScreen(viewPosition)
- magnifier.show(event.rawX - viewPosition[0], event.rawY - viewPosition[1])
- val iconX = event.x / v.width * icon.width
- val iconY = event.y / v.height * icon.height
- if (iconX >= 0 && iconX < icon.width && iconY >= 0 && iconY < icon.height) {
- selectedColor = true
- setRGBColor(icon.getPixel(iconX.toInt(), iconY.toInt()))
- }
- }
-
- MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
- magnifier.dismiss()
- }
- }
- true
- }
- val palette = Palette.from(icon).maximumColorCount(8).generate()
- val defaultColor = when {
- !isSettingOverallBgColor -> getBgColor(icon, !isDarkMode)
- isDarkMode -> Color.parseColor("#000000")
- else -> Color.parseColor("#FFFFFF")
- }
-
- setRGBColor(currentColor ?: defaultColor)
-
- // 返回按钮点击事件
- binding.titleBackIcon.setOnClickListener { finishAfterTransition() }
- binding.settingItems.addBlockMIUIView(this) {
- TextSummaryArrow(TextSummaryV(textId = R.string.manual_input) {
- MIUIDialog(this@ColorSelectActivity) {
- setTitle(R.string.manual_input)
- setMessage(R.string.manual_input_hint)
- setEditText(
- Integer.toHexString(color).substring(2).uppercase(Locale.ROOT),
- "",
- config = { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) it.isLocalePreferredLineHeightForMinimumUsed = false }
- )
- this.javaClass.method {
- emptyParam()
- returnType = EditText::class.java
- }.get(this).invoke()?.apply {
- addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
- override fun afterTextChanged(s: Editable?) {}
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
- val checkedText = Pattern.compile("[^a-fA-F0-9]").matcher(getEditText())
- .replaceAll("").trim()
- .run { if (this.length > 6) substring(0, 6) else this }
- if (checkedText != getEditText()) {
- setText(checkedText); setSelection(checkedText.length)
- }
- }
- })
- }
- setRButton(R.string.button_okay) {
- try {
- setRGBColor(Color.parseColor("#${getEditText()}"))
- selectedColor = true
- dismiss()
- } catch (_: IllegalArgumentException) {
- toast(getString(R.string.color_input_invalid))
- }
- }
- setLButton(R.string.button_cancel) { dismiss() }
- }.show()
- })
- Line()
- TitleText(textId = R.string.rgb_color_space)
- CustomView(createTextWithStatusV(R.string.rgb_r, statusR))
- CustomView(seekBarR)
- CustomView(createTextWithStatusV(R.string.rgb_g, statusG))
- CustomView(seekBarG)
- CustomView(createTextWithStatusV(R.string.rgb_b, statusB))
- CustomView(seekBarB)
- Line()
- TitleText(textId = R.string.hsv_color_space)
- CustomView(createTextWithStatusV(R.string.hue, statusH))
- CustomView(seekBarH)
- CustomView(createTextWithStatusV(R.string.saturation, statusS))
- CustomView(seekBarS)
- CustomView(createTextWithStatusV(R.string.value, statusV))
- CustomView(seekBarV)
- Line()
- Text(textId = R.string.undo_modification, colorInt = 0xFF3A7FF7.toInt()) { setRGBColor(currentColor ?: defaultColor); finishAfterTransition() }
- Text(textId = R.string.reset, colorInt = 0xFFD73E37.toInt()) { setRGBColor(defaultColor); resetColor = true; finishAfterTransition() }
- }
-
- binding.title.text = if (isSettingOverallBgColor) getString(R.string.set_custom_bg_color)
- else packageManager.run { getApplicationInfo(pkgName, 0).loadLabel(this).toString() }
-
- val colors = listOf(
- palette.getDominantColor(0),
- palette.getLightVibrantColor(0),
- palette.getVibrantColor(0),
- palette.getDarkVibrantColor(0),
- palette.getLightMutedColor(0),
- palette.getMutedColor(0),
- palette.getDarkMutedColor(0)
- ).distinct()
-
- repeat(colors.size) { i ->
- if (colors[i] != 0)
- binding.sampleColor.addView(
- TextView(this).apply {
- gravity = Gravity.CENTER
- background = GradientDrawable().apply { setColor(colors[i]); cornerRadius = dp2px(this@ColorSelectActivity, 15f).toFloat() }
- layoutParams = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- dp2px(this@ColorSelectActivity, 30f)
- ).apply {
- topMargin = dp2px(this@ColorSelectActivity, 10f)
- }
- setOnClickListener { setRGBColor(colors[i]); selectedColor = true }
- }
- )
- }
- }
-
- private fun setHsvColor(index: Int, value: Float) {
- hsvColor[index] = value
- color = Color.HSVToColor(hsvColor)
- }
-
- private fun setRGBColor(colorInt: Int) {
- if (colorInt == 0) setRGBColor(0xFFFFFFFF.toInt())
- else {
- val hsv = FloatArray(3).also { Color.colorToHSV(colorInt, it) }.also { hsvColor = it }
- seekBarH.progress = hsv[0].toInt()
- seekBarS.progress = (hsv[1] * 10000).toInt()
- seekBarV.progress = (hsv[2] * 10000).toInt()
- color = colorInt
- }
- }
-
- private fun drawHuePanel() {
- if (isHuePanelInitialized()) return
- val bitmap = Bitmap.createBitmap(resources.displayMetrics.widthPixels - dp2px(this, 60f) + 1, dp2px(this, 31f), Bitmap.Config.ARGB_8888)
- val canvas = Canvas(bitmap)
- val hueColors = IntArray(bitmap.width)
- val paint = Paint().apply { strokeWidth = 0.0f }
-
- var h = 0f
- for (i in hueColors.indices) {
- hueColors[i] = Color.HSVToColor(floatArrayOf(h, 1.0f, 1.0f))
- h += 360.0f / hueColors.size.toFloat()
- }
-
- for (i in hueColors.indices) {
- paint.color = hueColors[i]
- canvas.drawLine(
- i.toFloat(),
- 0f,
- i.toFloat(),
- bitmap.height.toFloat(),
- paint
- )
- }
-
- val roundCornerBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
- canvas.apply { setBitmap(roundCornerBitmap) }.drawRoundRect(
- 0f,
- 0f,
- bitmap.width.toFloat(),
- bitmap.height.toFloat(),
- bitmap.height.toFloat() / 2,
- bitmap.height.toFloat() / 2,
- paint.apply {
- isAntiAlias = true
- shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
- }
- )
- huePanel = BitmapDrawable(resources, roundCornerBitmap)
- }
-
- private fun createSeekBar(max: Int, progressColor: Int = 0xFF0d7AEC.toInt(), callBacks: ((value: Int) -> Unit)?) =
- SeekBar(this).also { view ->
- view.thumb = if (progressColor == 0) getDrawable(R.drawable.thumb_seek) else null
- view.splitTrack = false
- view.maxHeight = dp2px(this, 30f)
- view.minHeight = dp2px(this, 30f)
- view.background = null
- view.isIndeterminate = false
-
- view.progressDrawable = (getDrawable(cn.fkj233.ui.R.drawable.seekbar_progress_drawable) as LayerDrawable).apply {
- if (progressColor == 0) setDrawable(0, huePanel)
- ((getDrawable(1) as ClipDrawable).drawable as GradientDrawable).setColor(progressColor)
- }
- view.min = 0
- view.max = max
- view.layoutParams = ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- view.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
- if (p2) callBacks?.let { it(p1); selectedColor = true }
- }
-
- override fun onStartTrackingTouch(p0: SeekBar?) {}
- override fun onStopTrackingTouch(seekBar: SeekBar?) {}
- })
- view.setPadding(0, 0, 0, 0)
- view.invalidate()
- }
-
- private fun createTextWithStatusV(titleID: Int, status: TextView): View {
- return LinearContainerV(LinearContainerV.HORIZONTAL, arrayOf(
- LayoutPair(
- TextSummaryV(getString(titleID)).apply { notShowMargins(true) }.create(this, null),
- LinearLayout.LayoutParams(
- 0,
- LinearLayout.LayoutParams.WRAP_CONTENT,
- 1f
- )
- ),
- LayoutPair(
- status,
- LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
- .also { it.gravity = Gravity.CENTER_VERTICAL }
- )
- ), layoutParams = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- ).also {
- it.setMargins(0, dp2px(this, 17.75f), 0, dp2px(this, 10f))
- }).create(this, null)
- }
-
- override fun finishAfterTransition() {
- if (!isSettingOverallBgColor)
- setResult(
- when {
- resetColor -> ConstValue.DEFAULT_COLOR
- color == currentColor || !selectedColor -> ConstValue.UNDO_MODIFY
- else -> ConstValue.SELECTED_COLOR
- },
- Intent().apply {
- putExtra(ConstValue.EXTRA_MESSAGE_SELECTED_COLOR, binding.colorString.text)
- putExtra(ConstValue.EXTRA_MESSAGE_PACKAGE_NAME, pkgName)
- putExtra(ConstValue.EXTRA_MESSAGE_APP_INDEX, intent.getIntExtra(ConstValue.EXTRA_MESSAGE_APP_INDEX, -1))
- })
- else {
- prefs().edit {
- put(
- if (isDarkMode)
- DataConst.OVERALL_BG_COLOR_NIGHT
- else
- DataConst.OVERALL_BG_COLOR,
- binding.colorString.text.toString()
- )
- }
- }
-
-
- super.finishAfterTransition()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ConfigAppsActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ConfigAppsActivity.kt
deleted file mode 100644
index 9cdb2823..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/ConfigAppsActivity.kt
+++ /dev/null
@@ -1,228 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.content.Context
-import android.content.Intent
-import android.content.res.Configuration
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.inputmethod.InputMethodManager
-import android.widget.BaseAdapter
-import cn.fkj233.ui.dialog.MIUIDialog
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.databinding.ActivityConfigAppsBinding
-import com.gswxxn.restoresplashscreen.databinding.AdapterConfigBinding
-import com.gswxxn.restoresplashscreen.ui.configapps.BGColorIndividualConfig
-import com.gswxxn.restoresplashscreen.ui.configapps.BackgroundExcept
-import com.gswxxn.restoresplashscreen.ui.configapps.BrandingImage
-import com.gswxxn.restoresplashscreen.ui.configapps.CustomScope
-import com.gswxxn.restoresplashscreen.ui.configapps.DefaultStyle
-import com.gswxxn.restoresplashscreen.ui.configapps.ForceShowSplashScreen
-import com.gswxxn.restoresplashscreen.ui.configapps.HideSplashScreenIcon
-import com.gswxxn.restoresplashscreen.ui.configapps.MinDuration
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.utils.AppInfoHelper
-import com.gswxxn.restoresplashscreen.utils.BlockMIUIHelper.addBlockMIUIView
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.notEqualsTo
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toMap
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toSet
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.highcapable.yukihookapi.hook.factory.prefs
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-
-/**
- * 配置应用列表 Activity
- */
-class ConfigAppsActivity : BaseActivity(), CoroutineScope by MainScope() {
- companion object {
- var isDarkMode: Boolean = false
- }
-
- lateinit var appInfo: AppInfoHelper
- lateinit var configMap: MutableMap
- lateinit var checkedList: MutableSet
- lateinit var appInfoFilter: List
- lateinit var instance: IConfigApps
- var onRefreshList: (() -> Unit)? = null
-
- override fun onCreate() {
- isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
-
- instance = when (intent.getIntExtra(ConstValue.EXTRA_MESSAGE, 0)) {
- ConstValue.CUSTOM_SCOPE -> CustomScope
- ConstValue.DEFAULT_STYLE -> DefaultStyle
- ConstValue.BACKGROUND_EXCEPT -> BackgroundExcept
- ConstValue.BRANDING_IMAGE -> BrandingImage
- ConstValue.FORCE_SHOW_SPLASH_SCREEN -> ForceShowSplashScreen
- ConstValue.MIN_DURATION -> MinDuration
- ConstValue.BACKGROUND_INDIVIDUALLY_CONFIG -> BGColorIndividualConfig
- ConstValue.HIDE_SPLASH_SCREEN_ICON -> HideSplashScreenIcon
- else -> {
- object : IConfigApps {
- override val titleID: Int get() = R.string.unavailable
- override val submitSet: Boolean
- get() = false
- }
- }
- }
-
- // 已勾选的应用包名 Set
- checkedList = prefs().get(instance.checkedListPrefs).toMutableSet()
- // 应用配置信息
- configMap = prefs().get(instance.configMapPrefs).toMap()
- // AppInfoHelper 实例
- appInfo = AppInfoHelper(this, checkedList, configMap)
- // 在列表中的条目
- appInfoFilter = listOf()
-
- fun searchEvent() {
- val content = binding.searchEditText.text.toString()
- appInfoFilter = if (content.isBlank()) {
- appInfo.getAppInfoList()
- } else {
- appInfo.getAppInfoList().filter { it.appName.contains(content) or it.packageName.contains(content) }
- }
- onRefreshList?.invoke()
- }
-
- launch {
- appInfoFilter = withContext(Dispatchers.Default) { appInfo.getAppInfoList() }
-
- showView(false, binding.configListLoadingView)
- showView(true, binding.configListView)
-
- // 搜索栏内容改变事件
- binding.searchEditText.addTextChangedListener(object : TextWatcher {
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
- searchEvent()
- }
-
- override fun afterTextChanged(s: Editable?) {}
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
- })
- searchEvent()
- }
-
- // 返回按钮点击事件
- binding.titleBackIcon.setOnClickListener { finishAfterTransition() }
-
- // 标题名称
- binding.appListTitle.text = getString(instance.titleID)
- binding.subSettingHint.text = getString(instance.subSettingHint)
-
- // 搜索按钮点击事件
- binding.configTitleFilter.setOnClickListener {
- binding.searchEditText.apply {
- visibility = View.VISIBLE
- requestFocus()
- }
- }
-
- // 搜索栏事件监听
- binding.searchEditText.apply {
- // 焦点事件
- setOnFocusChangeListener { v, hasFocus ->
- val imm = v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
- if (hasFocus) {
- showView(false, binding.appListTitle, binding.configDescription, binding.configTitleFilter, binding.overallSettings)
- // 弹出软键盘
- imm.showSoftInput(binding.searchEditText, InputMethodManager.SHOW_FORCED)
- } else {
- // 隐藏软键盘
- imm.hideSoftInputFromWindow(this.windowToken, 0)
- }
- }
- }
-
- // 总体设置
- binding.overallSettings.addBlockMIUIView(this@ConfigAppsActivity, itemData = instance.blockMIUIView(this@ConfigAppsActivity))
-
- // 列表
- binding.configListView.apply {
- adapter = object : BaseAdapter() {
- override fun getCount() = appInfoFilter.size
-
- override fun getItem(position: Int) = appInfoFilter[position]
-
- override fun getItemId(position: Int) = position.toLong()
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
- var cView = convertView
- val holder: AdapterConfigBinding
- if (convertView == null) {
- holder = AdapterConfigBinding.inflate(LayoutInflater.from(context))
- cView = holder.root
- cView.tag = holder
- } else {
- holder = cView?.tag as AdapterConfigBinding
- }
- getItem(position).also { item ->
- // 设置图标
- holder.adpAppIcon.setImageDrawable(item.icon)
- // 设置应用名
- holder.adpAppName.text = item.appName
- // 设置包名
- holder.adpAppPkgName.text = item.packageName
- // 设置 TextView
- holder.adpAppTextView.apply(instance.adpTextView(this@ConfigAppsActivity, holder, item))
- // 设置复选框
- holder.adpAppCheckBox.apply(instance.adpCheckBox(this@ConfigAppsActivity, holder, item))
- // 设置 LinearLayout 单击事件
- holder.adapterLayout.setOnClickListener(instance.adpLinearLayout(this@ConfigAppsActivity, holder, item))
- }
- return cView
- }
- }.apply { onRefreshList = { notifyDataSetChanged() } }
- }
-
- // 保存按钮点击事件
- binding.configSaveButton.setOnClickListener {
- prefs().edit {
- if (instance.submitSet)
- put(instance.checkedListPrefs, checkedList)
- if (instance.submitMap)
- put(instance.configMapPrefs, configMap.toSet())
- }
- toast(getString(R.string.save_successful))
- finish()
- }
-
- // 菜单栏事件
- binding.moreOptions.apply(instance.moreOptions(this))
- }
-
- override fun finishAfterTransition() {
- fun isNeedSavePrompt() = (instance.submitSet && prefs().get(instance.checkedListPrefs) notEqualsTo checkedList) ||
- (instance.submitMap && prefs().get(instance.configMapPrefs) notEqualsTo configMap.toSet())
-
- if (binding.searchEditText.isFocused) {
- binding.searchEditText.apply {
- clearFocus()
- visibility = View.GONE
- text = null
- }
- showView(true, binding.appListTitle, binding.configDescription, binding.configTitleFilter, binding.overallSettings)
- } else if (isNeedSavePrompt()) {
- MIUIDialog(this) {
- setTitle(getString(R.string.not_saved_title))
- setMessage(getString(R.string.not_saved_hint))
- setRButton(getString(R.string.button_abandonment)) { this@ConfigAppsActivity.cancel(); super.finishAfterTransition() }
- setLButton(getString(R.string.button_reedit)) { dismiss() }
- }.show()
- } else {
- cancel()
- super.finishAfterTransition()
- }
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) =
- instance.onActivityResult(this, requestCode, resultCode, data)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt
new file mode 100644
index 00000000..7ddc9c73
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt
@@ -0,0 +1,150 @@
+package com.gswxxn.restoresplashscreen.ui
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableFloatState
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.compose.composable
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.apppage.BackgroundExceptPage
+import com.gswxxn.restoresplashscreen.ui.apppage.BgIndividualPage
+import com.gswxxn.restoresplashscreen.ui.page.AboutPage
+import com.gswxxn.restoresplashscreen.ui.page.BackgroundPage
+import com.gswxxn.restoresplashscreen.ui.page.BasicPage
+import com.gswxxn.restoresplashscreen.ui.page.BottomPage
+import com.gswxxn.restoresplashscreen.ui.apppage.CustomScopePage
+import com.gswxxn.restoresplashscreen.ui.apppage.ForceSplashPage
+import com.gswxxn.restoresplashscreen.ui.apppage.HideIconPage
+import com.gswxxn.restoresplashscreen.ui.apppage.IgnoreAppIconPage
+import com.gswxxn.restoresplashscreen.ui.apppage.MinDurationPage
+import com.gswxxn.restoresplashscreen.ui.apppage.RemoveBrandingPage
+import com.gswxxn.restoresplashscreen.ui.component.ColorPickerPage
+import com.gswxxn.restoresplashscreen.ui.component.ColorPickerPageArgs
+import com.gswxxn.restoresplashscreen.ui.page.DevPage
+import com.gswxxn.restoresplashscreen.ui.page.DisplayPage
+import com.gswxxn.restoresplashscreen.ui.page.IconPage
+import com.gswxxn.restoresplashscreen.ui.page.MainPage
+import com.gswxxn.restoresplashscreen.ui.page.ScopePage
+import com.gswxxn.restoresplashscreen.utils.YukiHelper.isXiaomiPad
+import com.highcapable.yukihookapi.YukiHookAPI
+import com.highcapable.yukihookapi.hook.factory.dataChannel
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.HyperXApp
+import top.yukonga.miuix.kmp.basic.Box
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+
+class MainActivity : HyperXActivity() {
+ companion object {
+ val moduleActive: MutableState = mutableStateOf(false)
+ val devMode: MutableState = mutableStateOf(false)
+ val blurEnabled: MutableState = mutableStateOf(true)
+ val blurTintAlphaLight: MutableFloatState = mutableFloatStateOf(0.6f)
+ val blurTintAlphaDark: MutableFloatState = mutableFloatStateOf(0.5f)
+ val splitEnabled: MutableState = mutableStateOf(true)
+ val systemUIRestartNeeded = mutableStateOf(true)
+ val androidRestartNeeded = mutableStateOf(null)
+ }
+
+ @SuppressLint("WorldReadableFiles")
+ @SuppressWarnings("deprecation")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ try {
+ SafeSP.setSP(
+ getSharedPreferences("${context.packageName ?: "unknown"}_preferences", MODE_WORLD_READABLE)
+ )
+ devMode.value = SafeSP.getBoolean(DataConst.ENABLE_DEV_SETTINGS.key, DataConst.ENABLE_DEV_SETTINGS.value)
+ blurEnabled.value = SafeSP.getBoolean(DataConst.BLUR.key, DataConst.BLUR.value)
+ blurTintAlphaLight.floatValue =
+ SafeSP.getInt(DataConst.HAZE_TINT_ALPHA_LIGHT.key, DataConst.HAZE_TINT_ALPHA_LIGHT.value) / 100f
+ blurTintAlphaDark.floatValue =
+ SafeSP.getInt(DataConst.HAZE_TINT_ALPHA_DARK.key, DataConst.HAZE_TINT_ALPHA_DARK.value) / 100f
+ splitEnabled.value = SafeSP.getBoolean(DataConst.SPLIT_VIEW.key, isXiaomiPad)
+ } catch (exception: SecurityException) {
+ devMode.value = false
+ blurEnabled.value = true
+ blurTintAlphaLight.floatValue = 0.6f
+ blurTintAlphaDark.floatValue = 0.5f
+ splitEnabled.value = isXiaomiPad
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ moduleActive.value = YukiHookAPI.Status.isXposedModuleActive
+ dataChannel("com.android.systemui").checkingVersionEquals {
+ systemUIRestartNeeded.value = !it
+ }
+ dataChannel("android").checkingVersionEquals {
+ androidRestartNeeded.value = !it
+ }
+ }
+
+ @Composable
+ override fun AppContent() {
+ HyperXApp(
+ autoSplitView = splitEnabled,
+ mainPageContent = { navController, adjustPadding, mode ->
+ MainPage(navController, adjustPadding, mode)
+ },
+ emptyPageContent = {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Image(
+ modifier = Modifier.size(256.dp),
+ painter = painterResource(R.drawable.ic_launcher_foreground),
+ contentDescription = null,
+ colorFilter = ColorFilter.tint(MiuixTheme.colorScheme.secondary)
+ )
+ }
+ },
+ otherPageBuilder = { navController, adjustPadding, mode ->
+ composable(Pages.ABOUT) { AboutPage(navController, adjustPadding, mode) }
+ composable(Pages.BASIC_SETTINGS) { BasicPage(navController, adjustPadding, mode) }
+ composable(Pages.SCOPE_SETTINGS) { ScopePage(navController, adjustPadding, mode) }
+ composable(Pages.ICON_SETTINGS) { IconPage(navController, adjustPadding, mode) }
+ composable(Pages.BOTTOM_SETTINGS) { BottomPage(navController, adjustPadding, mode) }
+ composable(Pages.BACKGROUND_SETTINGS) { BackgroundPage(navController, adjustPadding, mode) }
+ composable(Pages.DISPLAY_SETTINGS) { DisplayPage(navController, adjustPadding, mode) }
+ composable(Pages.DEVELOPER_SETTINGS) { DevPage(navController, adjustPadding, mode) }
+
+ composable(Pages.CONFIG_CUSTOM_SCOPE) { CustomScopePage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_IGNORE_APP_ICON) { IgnoreAppIconPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_HIDE_SPLASH_ICON) { HideIconPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_REMOVE_BRANDING) { RemoveBrandingPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_BACKGROUND_EXCEPT) { BackgroundExceptPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_BACKGROUND_INDIVIDUALLY) { BgIndividualPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_MIN_DURATION) { MinDurationPage(navController, adjustPadding, mode) }
+ composable(Pages.CONFIG_FORCE_SHOW_SPLASH) { ForceSplashPage(navController, adjustPadding, mode) }
+
+ composable(
+ "${Pages.CONFIG_COLOR_PICKER}?" +
+ "${ColorPickerPageArgs.PACKAGE_NAME}={${ColorPickerPageArgs.PACKAGE_NAME}}," +
+ "${ColorPickerPageArgs.KEY_LIGHT}={${ColorPickerPageArgs.KEY_LIGHT}}," +
+ "${ColorPickerPageArgs.KEY_DARK}={${ColorPickerPageArgs.KEY_DARK}}"
+ ) {
+ val pkgName = it.arguments?.getString(ColorPickerPageArgs.PACKAGE_NAME) ?: ""
+ val keyLight = it.arguments?.getString(ColorPickerPageArgs.KEY_LIGHT) ?: DataConst.OVERALL_BG_COLOR.key
+ val keyDark = it.arguments?.getString(ColorPickerPageArgs.KEY_DARK) ?: DataConst.OVERALL_BG_COLOR_NIGHT.key
+ ColorPickerPage(navController, adjustPadding, pkgName, keyLight, keyDark, mode)
+ }
+ }
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainSettingsActivity.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainSettingsActivity.kt
deleted file mode 100644
index 2c3cf8c4..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainSettingsActivity.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.content.Intent
-import android.net.Uri
-import android.view.View
-import android.view.ViewTreeObserver
-import android.widget.LinearLayout
-import androidx.core.view.WindowInsetsCompat
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.view.ImageTextV
-import cn.fkj233.ui.activity.view.LineV
-import com.gswxxn.restoresplashscreen.BuildConfig
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivityMainSettingsBinding
-import com.gswxxn.restoresplashscreen.utils.BlockMIUIHelper.addBlockMIUIView
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.execShell
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.utils.GraphicUtils.shrinkIcon
-import com.gswxxn.restoresplashscreen.view.NewMIUIDialog
-import com.highcapable.yukihookapi.YukiHookAPI
-import com.highcapable.yukihookapi.YukiHookAPI.Status.Executor
-import com.highcapable.yukihookapi.hook.factory.dataChannel
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/** 主界面 */
-class MainSettingsActivity : BaseActivity() {
- private var systemUIRestartNeeded: Boolean = true
- private var androidRestartNeeded: Boolean? = null
- private var isReady = false
-
- private var devSettingsView: View? = null
-
- override fun onCreate() {
- binding.root.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
- override fun onPreDraw(): Boolean {
- if (isReady) binding.root.viewTreeObserver.removeOnPreDrawListener(this)
- return isReady
- }
- })
-
- Thread.sleep(400)
- isReady = true
-
- // 显示版本号
- binding.mainTextVersion.text = getString(R.string.module_version, BuildConfig.VERSION_NAME)
-
- // 重启UI
- binding.titleRestartIcon.setOnClickListener {
- NewMIUIDialog(this) {
- setTitle(R.string.restart_title)
- setMessage(R.string.restart_message)
- Button(getString(R.string.reboot)) {
- execShell("reboot")
- Thread.sleep(300)
- toast(getString(R.string.no_root))
- }
- Button(getString(R.string.restart_system_ui)) {
- execShell("pkill -f com.android.systemui && pkill -f com.gswxxn.restoresplashscreen")
- Thread.sleep(300)
- toast(getString(R.string.no_root))
- }
- Button(getString(R.string.button_cancel), cancelStyle = true) {
- dismiss()
- }
- }.show()
- }
-
- // 关于页面
- binding.titleAboutPage.setOnClickListener {
- val intent = Intent(this, AboutPageActivity::class.java)
- startActivity(intent)
- }
-
- binding.settingsEntry.addBlockMIUIView(this) {
- fun line() = CustomView(LineV().create(this@MainSettingsActivity, null).apply {
- layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dp2px(context, 0.9f))
- .apply {
- setMargins(dp2px(context, 20f), dp2px(context, 23f), 0, dp2px(context, 23f))
- }
- })
-
- Author(shrinkIcon(R.drawable.ic_setting), getString(R.string.basic_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BASIC_SETTINGS)
- })
- })
-
- line()
-
- Author(shrinkIcon(R.drawable.ic_app), getString(R.string.custom_scope_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.CUSTOM_SCOPE_SETTINGS)
- })
- })
-
- Author(shrinkIcon(R.drawable.ic_picture), getString(R.string.icon_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.ICON_SETTINGS)
- })
- })
-
- Author(shrinkIcon(R.drawable.ic_bottom), getString(R.string.bottom_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BOTTOM_SETTINGS)
- })
- })
-
- Author(shrinkIcon(R.drawable.ic_color), getString(R.string.background_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BACKGROUND_SETTINGS)
- })
- })
-
- Author(shrinkIcon(R.drawable.ic_monitor), getString(R.string.display_settings), null, 0f, {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.DISPLAY_SETTINGS)
- })
- })
-
- CustomView(
- ImageTextV(shrinkIcon(R.drawable.ic_lab), getString(R.string.dev_settings), null, 0f)
- .create(this@MainSettingsActivity, null)
- .also {
- it.setOnClickListener {
- startActivity(Intent(this@MainSettingsActivity, SubSettings::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.DEV_SETTINGS)
- })
- }
- devSettingsView = it
- }
- )
-
- line()
-
- Author(shrinkIcon(R.drawable.ic_help), getString(R.string.faq), null, 0f, {
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.faq_url))))
- })
- }
- }
-
- private fun refreshState() {
- val takeAction = androidRestartNeeded == true || systemUIRestartNeeded
- binding.mainStatus.setBackgroundResource(
- when {
- YukiHookAPI.Status.isXposedModuleActive && takeAction -> 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 && !takeAction -> R.drawable.ic_success
- else -> R.drawable.ic_warn
- }
- )
- binding.mainTextStatus.text =
- when {
- YukiHookAPI.Status.isXposedModuleActive && takeAction ->
- getString(R.string.module_is_updated, getString(if (androidRestartNeeded == true) R.string.phone else R.string.system_ui))
-
- YukiHookAPI.Status.isXposedModuleActive -> getString(R.string.module_is_active)
- else -> getString(R.string.module_is_not_active)
- }
- showView(YukiHookAPI.Status.isXposedModuleActive, binding.mainTextApiWay)
- binding.mainTextApiWay.text = getString(
- R.string.xposed_framework_version,
- Executor.name,
- Executor.apiLevel
- )
- }
-
- override fun onResume() {
- super.onResume()
- refreshState()
-
- dataChannel("com.android.systemui").checkingVersionEquals {
- systemUIRestartNeeded = !it
- refreshState()
- }
- dataChannel("android").checkingVersionEquals {
- androidRestartNeeded = !it
- refreshState()
- }
-
- devSettingsView?.visibility =
- if (prefs().get(DataConst.ENABLE_DEV_SETTINGS)) View.VISIBLE else View.GONE
- }
-}
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/SubSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/SubSettings.kt
deleted file mode 100644
index 4de23861..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/SubSettings.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui
-
-import android.content.Intent
-import android.view.View
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.BackgroundSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.BasicSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.BottomSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.CustomScopeSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.DevSettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.DisplaySettings
-import com.gswxxn.restoresplashscreen.ui.subsettings.HookInfo
-import com.gswxxn.restoresplashscreen.ui.subsettings.IconSettings
-import com.gswxxn.restoresplashscreen.utils.BlockMIUIHelper.addBlockMIUIView
-
-/** 子界面 */
-class SubSettings : BaseActivity() {
- private lateinit var instance: ISubSettings
-
- override fun onCreate() {
- val message = intent.getIntExtra(ConstValue.EXTRA_MESSAGE, 0)
-
- //返回按钮点击事件
- binding.titleBackIcon.setOnClickListener { finishAfterTransition() }
-
- when (message) {
- // 基础设置
- ConstValue.BASIC_SETTINGS -> BasicSettings
- // 作用域
- ConstValue.CUSTOM_SCOPE_SETTINGS -> CustomScopeSettings
- // 图标
- ConstValue.ICON_SETTINGS -> IconSettings
- // 底部
- ConstValue.BOTTOM_SETTINGS -> BottomSettings
- // 背景
- ConstValue.BACKGROUND_SETTINGS -> BackgroundSettings
- // 显示设置
- ConstValue.DISPLAY_SETTINGS -> DisplaySettings
- // Hook 信息
- ConstValue.HOOK_INFO -> HookInfo
- // 开发者选项
- ConstValue.DEV_SETTINGS -> DevSettings
-
- else -> null
- }?.apply {
- instance = this
- binding.appListTitle.text = getString(titleID)
- demoImageID?.let { binding.demoImage.setImageDrawable(getDrawable(it)) }
- ?: run {
- binding.demoImageLayout.visibility = View.GONE
- binding.mainStatus.background = null
- }
- binding.settingItems.addBlockMIUIView(this@SubSettings, itemData = create(this@SubSettings, binding))
- }
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) =
- instance.onActivityResult(this, requestCode, resultCode, data)
-}
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt
new file mode 100644
index 00000000..d8efed45
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt
@@ -0,0 +1,24 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+
+/**
+ * 背景 - 替换背景颜色 - 排除列表
+ */
+@Composable
+fun BackgroundExceptPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.background_except_title),
+ DataConst.BG_EXCEPT_LIST.key,
+ mode
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt
new file mode 100644
index 00000000..d4dcfb52
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt
@@ -0,0 +1,309 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import android.content.pm.ApplicationInfo
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.add
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.displayCutout
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableFloatState
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toBitmap
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.ColorPickerPageArgs
+import com.gswxxn.restoresplashscreen.ui.component.MyAppInfo
+import com.gswxxn.restoresplashscreen.ui.component.SpliceCard
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toMap
+import dev.chrisbanes.haze.HazeStyle
+import dev.chrisbanes.haze.HazeTint
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.HazeScaffold
+import dev.lackluster.hyperx.compose.base.IconSize
+import dev.lackluster.hyperx.compose.base.ImageIcon
+import dev.lackluster.hyperx.compose.icon.Back
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.TextPreference
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.CardDefaults
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.basic.InputField
+import top.yukonga.miuix.kmp.basic.LazyColumn
+import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
+import top.yukonga.miuix.kmp.basic.SearchBar
+import top.yukonga.miuix.kmp.basic.SmallTitle
+import top.yukonga.miuix.kmp.basic.TopAppBar
+import top.yukonga.miuix.kmp.basic.rememberTopAppBarState
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.icons.Info
+import top.yukonga.miuix.kmp.icon.icons.Search
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.utils.getWindowSize
+
+/**
+ * 单独配置背景颜色
+ */
+@Composable
+fun BgIndividualPage(
+ navController: NavController,
+ adjustPadding: PaddingValues,
+ mode: BasePageDefaults.Mode,
+ blurEnabled: MutableState = MainActivity.blurEnabled,
+ blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight,
+ blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark
+) {
+ val topAppBarBackground = MiuixTheme.colorScheme.background
+ val scrollBehavior = MiuixScrollBehavior(rememberTopAppBarState())
+ val listState = rememberLazyListState()
+ val topBarBlurState by remember {
+ derivedStateOf {
+ blurEnabled.value &&
+ scrollBehavior.state.collapsedFraction >= 1.0f &&
+ (listState.isScrollInProgress || listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 12)
+ }
+ }
+ val topBarBlurTintAlpha = remember { mutableFloatStateOf(
+ if (topAppBarBackground.luminance() >= 0.5f) blurTintAlphaLight.floatValue
+ else blurTintAlphaDark.floatValue
+ ) }
+
+ var queryString by remember { mutableStateOf("") }
+
+ // 完整应用列表
+ var appInfoList by remember { mutableStateOf>(emptyList()) }
+
+ // 在列表中的条目
+ var appInfoFilter by remember { mutableStateOf>(emptyList()) }
+
+ var queryJob: Job? = null
+ var isLoading by remember { mutableStateOf(true) }
+ val deviceDarkMode = isSystemInDarkTheme()
+
+ LaunchedEffect(Unit) {
+ launch {
+ isLoading = true
+ delay(500)
+ val key = if (deviceDarkMode) DataConst.INDIVIDUAL_BG_COLOR_APP_MAP_DARK.key else DataConst.INDIVIDUAL_BG_COLOR_APP_MAP.key
+ val tmpCheckedList = mutableMapOf().apply {
+ clear()
+ putAll((SafeSP.mSP?.getStringSet(key, emptySet())?: emptySet()).toMap())
+ }
+ val pm = HyperXActivity.context.packageManager
+ appInfoList = pm.getInstalledApplications(0).map {
+ MyAppInfo(
+ it.loadLabel(pm).toString(),
+ it.packageName,
+ it.loadIcon(pm),
+ mutableStateOf(it.packageName in tmpCheckedList.keys),
+ it.flags and ApplicationInfo.FLAG_SYSTEM != 0
+ )
+ }.toList()
+ isLoading = false
+ }
+ }
+
+ LaunchedEffect(appInfoList, queryString) {
+ if (appInfoList.isEmpty()) return@LaunchedEffect
+ appInfoFilter = emptyList()
+ queryJob?.cancel()
+ queryJob = launch {
+ if (queryString.isBlank()) {
+ delay(100)
+ appInfoFilter = appInfoList.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ } else {
+ delay(300)
+ appInfoFilter = appInfoList.filter {
+ it.appName.contains(queryString, true) or it.packageName.contains(queryString, true)
+ }.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ }
+ }
+ }
+ val layoutDirection = LocalLayoutDirection.current
+ val systemBarInsets = WindowInsets.systemBars.add(WindowInsets.displayCutout).only(WindowInsetsSides.Horizontal).asPaddingValues()
+ val navigationIconPadding = PaddingValues.Absolute(
+ left = if (mode != BasePageDefaults.Mode.SPLIT_RIGHT) systemBarInsets.calculateLeftPadding(layoutDirection) else 0.dp
+ )
+
+ HazeScaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = { contentPadding ->
+ TopAppBar(
+ color = topAppBarBackground.copy(
+ if (topBarBlurState) 0f else 1f
+ ),
+ title = stringResource(R.string.configure_bg_colors_individually),
+ scrollBehavior = scrollBehavior,
+ navigationIcon = {
+ IconButton(
+ modifier = Modifier
+ .padding(navigationIconPadding)
+ .padding(start = 21.dp)
+ .size(40.dp),
+ onClick = {
+ navController.popBackStack()
+ }
+ ) {
+ Icon(
+ modifier = Modifier.size(26.dp),
+ imageVector = MiuixIcons.Back,
+ contentDescription = "Back",
+ tint = MiuixTheme.colorScheme.onSurfaceSecondary
+ )
+ }
+ },
+ defaultWindowInsetsPadding = false,
+ horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current)
+ )
+ },
+ blurTopBar = blurEnabled.value,
+ blurBottomBar = blurEnabled.value,
+ hazeStyle = HazeStyle(
+ blurRadius = 66.dp,
+ backgroundColor = topAppBarBackground,
+ tint = HazeTint(
+ topAppBarBackground.copy(alpha = topBarBlurTintAlpha.floatValue),
+ )
+ ),
+ adjustPadding = adjustPadding,
+ ) { paddingValues ->
+ LazyColumn(
+ modifier = Modifier
+ .height(getWindowSize().height.dp)
+ .background(MiuixTheme.colorScheme.background),
+ state = listState,
+ contentPadding = paddingValues,
+ topAppBarScrollBehavior = scrollBehavior
+ ) {
+ item {
+ SearchBar(
+ modifier = Modifier
+ .padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 6.dp),
+ inputField = {
+ InputField(
+ query = queryString,
+ onQueryChange = { queryString = it },
+ onSearch = { },
+ expanded = false,
+ onExpandedChange = { },
+ label = stringResource(R.string.search_hint),
+ leadingIcon = {
+ Icon(
+ modifier = Modifier.padding(start = 12.dp, end = 8.dp),
+ imageVector = MiuixIcons.Search,
+ tint = MiuixTheme.colorScheme.onSurfaceContainer,
+ contentDescription = "Search"
+ )
+ },
+ )
+ },
+ expanded = false,
+ onExpandedChange = { },
+ content = { }
+ )
+ }
+ item {
+ PreferenceGroup {
+ BasicComponent(
+ insideMargin = PaddingValues(16.dp),
+ summary = stringResource(R.string.custom_bg_color_sub_setting_hint),
+ leftAction = {
+ Image(
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .size(28.dp),
+ imageVector = MiuixIcons.Info,
+ contentDescription = null,
+ colorFilter = ColorFilter.tint(MiuixTheme.colorScheme.onSurfaceVariantSummary)
+ )
+ }
+ )
+ }
+ }
+ if (isLoading) {
+ item {
+ SmallTitle(
+ text = stringResource(R.string.loading),
+ modifier = Modifier.padding(top = 6.dp),
+ textColor = MiuixTheme.colorScheme.onBackgroundVariant
+ )
+ }
+ } else {
+ itemsIndexed(appInfoFilter, key = { index, item ->
+ item.packageName + item.isChecked + index + appInfoFilter.size
+ }) { index, item ->
+ val topCornerRadius = if (index == 0) CardDefaults.ConorRadius else 0.dp
+ val bottomCornerRadius = if (index == appInfoFilter.size - 1) CardDefaults.ConorRadius else 0.dp
+ SpliceCard(
+ topCornerRadius,
+ bottomCornerRadius
+ ) {
+ TextPreference(
+ icon = ImageIcon(
+ iconBitmap = item.icon.toBitmap().asImageBitmap(),
+ iconSize = IconSize.App
+ ),
+ title = item.appName,
+ summary = item.packageName
+ ) {
+ navController.navigateTo(
+ "${Pages.CONFIG_COLOR_PICKER}?" +
+ "${ColorPickerPageArgs.PACKAGE_NAME}=${item.packageName}," +
+ "${ColorPickerPageArgs.KEY_LIGHT}=${DataConst.INDIVIDUAL_BG_COLOR_APP_MAP.key}," +
+ "${ColorPickerPageArgs.KEY_DARK}=${DataConst.INDIVIDUAL_BG_COLOR_APP_MAP_DARK.key}"
+ )
+ }
+ }
+ }
+ }
+ item {
+ Spacer(
+ modifier = Modifier.height(6.dp)
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt
new file mode 100644
index 00000000..da5b760a
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt
@@ -0,0 +1,51 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+
+/**
+ * 作用域 - 自定义模块作用域 - 配置应用列表
+ */
+@Composable
+fun CustomScopePage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var exceptionMode by remember { mutableStateOf(SafeSP.getBoolean(DataConst.IS_CUSTOM_SCOPE_EXCEPTION_MODE.key)) }
+ val exceptionSummary = stringResource(
+ R.string.custom_scope_exception_mode_message,
+ if (exceptionMode)
+ stringResource(R.string.will_not)
+ else
+ stringResource(R.string.will_only)
+ )
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.custom_scope_title),
+ DataConst.CUSTOM_SCOPE_LIST.key,
+ mode
+ ) {
+ item {
+ PreferenceGroup {
+ SwitchPreference(
+ title = stringResource(R.string.exception_mode),
+ summary = exceptionSummary,
+ key = DataConst.IS_CUSTOM_SCOPE_EXCEPTION_MODE.key
+ ) {
+ exceptionMode = it
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt
new file mode 100644
index 00000000..cc75c668
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt
@@ -0,0 +1,24 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+
+/**
+ * 实验功能 - 强制显示遮罩 - 配置应用列表
+ */
+@Composable
+fun ForceSplashPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.force_show_splash_screen_title),
+ DataConst.FORCE_SHOW_SPLASH_SCREEN_LIST.key,
+ mode
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt
new file mode 100644
index 00000000..13be267d
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt
@@ -0,0 +1,51 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+
+/**
+ * 图标 - 不显示图标
+ */
+@Composable
+fun HideIconPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var exceptionMode by remember { mutableStateOf(SafeSP.getBoolean(DataConst.IS_HIDE_SPLASH_SCREEN_ICON_EXCEPTION_MODE.key)) }
+ val exceptionSummary = stringResource(
+ R.string.exception_mode_message,
+ if (exceptionMode)
+ stringResource(R.string.not_chosen)
+ else
+ stringResource(R.string.chosen)
+ )
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.hide_splash_screen_icon_title),
+ DataConst.HIDE_SPLASH_SCREEN_ICON_LIST.key,
+ mode
+ ) {
+ item {
+ PreferenceGroup {
+ SwitchPreference(
+ title = stringResource(R.string.exception_mode),
+ summary = exceptionSummary,
+ key = DataConst.IS_HIDE_SPLASH_SCREEN_ICON_EXCEPTION_MODE.key
+ ) {
+ exceptionMode = it
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt
new file mode 100644
index 00000000..61a03919
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt
@@ -0,0 +1,51 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+
+/**
+ * 图标 - 忽略应用主动谁知的图标 - 配置应用列表
+ */
+@Composable
+fun IgnoreAppIconPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var exceptionMode by remember { mutableStateOf(SafeSP.getBoolean(DataConst.IS_DEFAULT_STYLE_LIST_EXCEPTION_MODE.key)) }
+ val exceptionSummary = stringResource(
+ R.string.exception_mode_message,
+ if (exceptionMode)
+ stringResource(R.string.not_chosen)
+ else
+ stringResource(R.string.chosen)
+ )
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.default_style_title),
+ DataConst.DEFAULT_STYLE_LIST.key,
+ mode
+ ) {
+ item {
+ PreferenceGroup {
+ SwitchPreference(
+ title = stringResource(R.string.exception_mode),
+ summary = exceptionSummary,
+ key = DataConst.IS_DEFAULT_STYLE_LIST_EXCEPTION_MODE.key
+ ) {
+ exceptionMode = it
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt
new file mode 100644
index 00000000..039d7d43
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt
@@ -0,0 +1,555 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import android.graphics.drawable.Drawable
+import android.widget.Toast
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.add
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.captionBar
+import androidx.compose.foundation.layout.displayCutout
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableFloatState
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.core.content.edit
+import androidx.core.graphics.drawable.toBitmap
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.SpliceCard
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.notEqualsTo
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toMap
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toSet
+import dev.chrisbanes.haze.HazeStyle
+import dev.chrisbanes.haze.HazeTint
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.AlertDialog
+import dev.lackluster.hyperx.compose.base.AlertDialogMode
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.DrawableResIcon
+import dev.lackluster.hyperx.compose.base.HazeScaffold
+import dev.lackluster.hyperx.compose.base.IconSize
+import dev.lackluster.hyperx.compose.base.ImageIcon
+import dev.lackluster.hyperx.compose.icon.Back
+import dev.lackluster.hyperx.compose.preference.EditTextDataType
+import dev.lackluster.hyperx.compose.preference.EditTextDialog
+import dev.lackluster.hyperx.compose.preference.EditTextPreference
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.ButtonDefaults
+import top.yukonga.miuix.kmp.basic.CardDefaults
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.basic.InputField
+import top.yukonga.miuix.kmp.basic.LazyColumn
+import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
+import top.yukonga.miuix.kmp.basic.SearchBar
+import top.yukonga.miuix.kmp.basic.SmallTitle
+import top.yukonga.miuix.kmp.basic.Surface
+import top.yukonga.miuix.kmp.basic.Switch
+import top.yukonga.miuix.kmp.basic.Text
+import top.yukonga.miuix.kmp.basic.TextButton
+import top.yukonga.miuix.kmp.basic.TopAppBar
+import top.yukonga.miuix.kmp.basic.rememberTopAppBarState
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.icons.Info
+import top.yukonga.miuix.kmp.icon.icons.Search
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.utils.BackHandler
+import top.yukonga.miuix.kmp.utils.HorizontalDivider
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog
+import top.yukonga.miuix.kmp.utils.getWindowSize
+
+/**
+ * 基础设置 - 遮罩最小持续时长
+ */
+@Composable
+fun MinDurationPage(
+ navController: NavController,
+ adjustPadding: PaddingValues,
+ mode: BasePageDefaults.Mode,
+ blurEnabled: MutableState = MainActivity.blurEnabled,
+ blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight,
+ blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark,
+) {
+ val checkedListKey = DataConst.MIN_DURATION_LIST.key
+ val configMapKey = DataConst.MIN_DURATION_CONFIG_MAP.key
+ val topAppBarBackground = MiuixTheme.colorScheme.background
+ val scrollBehavior = MiuixScrollBehavior(rememberTopAppBarState())
+ val listState = rememberLazyListState()
+ val topBarBlurState by remember {
+ derivedStateOf {
+ blurEnabled.value &&
+ scrollBehavior.state.collapsedFraction >= 1.0f &&
+ (listState.isScrollInProgress || listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 12)
+ }
+ }
+ val topBarBlurTintAlpha = remember { mutableFloatStateOf(
+ if (topAppBarBackground.luminance() >= 0.5f) blurTintAlphaLight.floatValue
+ else blurTintAlphaDark.floatValue
+ ) }
+ val modifiedDialogVisibility = remember { mutableStateOf(false) }
+
+ val dialogMessage = stringResource(R.string.set_min_duration) + "\n" + stringResource(R.string.set_min_duration_unit)
+ var queryString by remember { mutableStateOf("") }
+
+ val emptyMapString = stringResource(R.string.not_set_min_duration)
+
+ // 完整应用列表
+ var appInfoList by remember { mutableStateOf>(emptyList()) }
+
+ // 在列表中的条目
+ var appInfoFilter by remember { mutableStateOf>(emptyList()) }
+
+ // 保存前的配置
+ val tmpCheckedList = mutableSetOf().apply {
+ clear()
+ addAll(checkedListKey.let { SafeSP.mSP?.getStringSet(it, emptySet()) } ?: emptySet())
+ }
+ val tmpConfigMap = mutableMapOf().apply {
+ clear()
+ putAll((SafeSP.mSP?.getStringSet(checkedListKey, emptySet())?: emptySet()).toMap())
+ }
+
+ val coroutineScope = rememberCoroutineScope()
+ var queryJob: Job? = null
+ var isLoading by remember { mutableStateOf(true) }
+
+ BackHandler(true) {
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ val currentConfigMap = appInfoList.filter {
+ it.config.value != null && it.config.value != emptyMapString
+ }.map {
+ "${it.packageName}_${it.config.value}"
+ }.toSet()
+ if (currentCheckedList.notEqualsTo(tmpCheckedList) || currentConfigMap.notEqualsTo(tmpConfigMap.toSet())) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+
+ LaunchedEffect(Unit) {
+ launch {
+ isLoading = true
+ delay(500)
+ val pm = HyperXActivity.context.packageManager
+ appInfoList = pm.getInstalledApplications(0).map {
+ DurationAppInfo(
+ it.loadLabel(pm).toString(),
+ it.packageName,
+ it.loadIcon(pm),
+ mutableStateOf(it.packageName in tmpCheckedList),
+ mutableStateOf(tmpConfigMap[it.packageName])
+ )
+ }.toList()
+ isLoading = false
+ }
+ }
+
+ LaunchedEffect(appInfoList, queryString) {
+ if (appInfoList.isEmpty()) return@LaunchedEffect
+ appInfoFilter = emptyList()
+ queryJob?.cancel()
+ queryJob = launch {
+ if (queryString.isBlank()) {
+ delay(100)
+ appInfoFilter = appInfoList.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.config.value != null}
+ sortByDescending { it.isChecked.value }
+ }
+ } else {
+ delay(300)
+ appInfoFilter = appInfoList.filter {
+ it.appName.contains(queryString, true) or it.packageName.contains(queryString, true)
+ }.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.config.value != null }
+ sortByDescending { it.isChecked.value }
+ }
+ }
+ }
+ }
+ val layoutDirection = LocalLayoutDirection.current
+ val systemBarInsets = WindowInsets.systemBars.add(WindowInsets.displayCutout).only(WindowInsetsSides.Horizontal).asPaddingValues()
+ val navigationIconPadding = PaddingValues.Absolute(
+ left = if (mode != BasePageDefaults.Mode.SPLIT_RIGHT) systemBarInsets.calculateLeftPadding(layoutDirection) else 0.dp
+ )
+
+ HazeScaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = { contentPadding ->
+ TopAppBar(
+ color = topAppBarBackground.copy(
+ if (topBarBlurState) 0f else 1f
+ ),
+ title = stringResource(R.string.min_duration_title),
+ scrollBehavior = scrollBehavior,
+ navigationIcon = {
+ IconButton(
+ modifier = Modifier
+ .padding(navigationIconPadding)
+ .padding(start = 21.dp)
+ .size(40.dp),
+ onClick = {
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ val currentConfigMap = appInfoList.filter {
+ it.config.value != null && it.config.value != emptyMapString
+ }.map {
+ "${it.packageName}_${it.config.value}"
+ }.toSet()
+ if (currentCheckedList.notEqualsTo(tmpCheckedList) || currentConfigMap.notEqualsTo(tmpConfigMap.toSet())) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+ ) {
+ Icon(
+ modifier = Modifier.size(26.dp),
+ imageVector = MiuixIcons.Back,
+ contentDescription = "Back",
+ tint = MiuixTheme.colorScheme.onSurfaceSecondary
+ )
+ }
+ },
+ defaultWindowInsetsPadding = false,
+ horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current)
+ )
+ },
+ bottomBar = { contentPadding ->
+ val captionBarBottomPadding by rememberUpdatedState(
+ WindowInsets.captionBar.only(WindowInsetsSides.Bottom).asPaddingValues().calculateBottomPadding()
+ )
+ val buttonPaddingValues = with(LocalLayoutDirection.current) {
+ PaddingValues(
+ start = contentPadding.calculateStartPadding(this) + 16.dp,
+ top = 12.dp,
+ end = contentPadding.calculateEndPadding(this) + 16.dp,
+ bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + captionBarBottomPadding + 12.dp
+ )
+ }
+ Surface(
+ color = MiuixTheme.colorScheme.background.copy(
+ if (blurEnabled.value) 0f else 1f
+ ),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(Color.Transparent)
+ ) {
+ HorizontalDivider(
+ thickness = 0.75.dp,
+ color = MiuixTheme.colorScheme.dividerLine
+ )
+ TextButton(
+ modifier = Modifier
+ .padding(buttonPaddingValues)
+ .fillMaxWidth(),
+ text = stringResource(R.string.save),
+ colors = ButtonDefaults.textButtonColorsPrimary(),
+ minHeight = 50.dp,
+ onClick = {
+ CoroutineScope(Dispatchers.Default).launch {
+ SafeSP.mSP?.let { sp ->
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ val currentConfigMap = appInfoList.filter {
+ it.config.value != null && it.config.value != emptyMapString
+ }.map {
+ "${it.packageName}_${it.config.value}"
+ }.toSet()
+ sp.edit {
+ putStringSet(checkedListKey, currentCheckedList)
+ putStringSet(configMapKey, currentConfigMap)
+ commit()
+ }
+ tmpCheckedList.apply {
+ clear()
+ addAll(checkedListKey.let { SafeSP.mSP?.getStringSet(it, emptySet()) } ?: emptySet())
+ }
+ tmpConfigMap.apply {
+ clear()
+ putAll((SafeSP.mSP?.getStringSet(checkedListKey, emptySet())?: emptySet()).toMap())
+ }
+ coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_successful), Toast.LENGTH_SHORT).show()
+ }
+ }
+ } ?: coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_failed), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ }
+ )
+ }
+ }
+ },
+ blurTopBar = blurEnabled.value,
+ blurBottomBar = blurEnabled.value,
+ hazeStyle = HazeStyle(
+ blurRadius = 66.dp,
+ backgroundColor = topAppBarBackground,
+ tint = HazeTint(
+ topAppBarBackground.copy(alpha = topBarBlurTintAlpha.floatValue),
+ )
+ ),
+ adjustPadding = adjustPadding,
+ ) { paddingValues ->
+ LazyColumn(
+ modifier = Modifier
+ .height(getWindowSize().height.dp)
+ .background(MiuixTheme.colorScheme.background),
+ state = listState,
+ contentPadding = paddingValues,
+ topAppBarScrollBehavior = scrollBehavior
+ ) {
+ item {
+ SearchBar(
+ modifier = Modifier
+ .padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 6.dp),
+ inputField = {
+ InputField(
+ query = queryString,
+ onQueryChange = { queryString = it },
+ onSearch = { },
+ expanded = false,
+ onExpandedChange = { },
+ label = stringResource(R.string.search_hint),
+ leadingIcon = {
+ Icon(
+ modifier = Modifier.padding(start = 12.dp, end = 8.dp),
+ imageVector = MiuixIcons.Search,
+ tint = MiuixTheme.colorScheme.onSurfaceContainer,
+ contentDescription = "Search"
+ )
+ },
+ )
+ },
+ expanded = false,
+ onExpandedChange = { },
+ content = { }
+ )
+ }
+ item {
+ PreferenceGroup {
+ BasicComponent(
+ insideMargin = PaddingValues(16.dp),
+ summary = stringResource(R.string.min_duration_sub_setting_hint),
+ leftAction = {
+ Image(
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .size(28.dp),
+ imageVector = MiuixIcons.Info,
+ contentDescription = null,
+ colorFilter = ColorFilter.tint(MiuixTheme.colorScheme.onSurfaceVariantSummary)
+ )
+ }
+ )
+ }
+ }
+ item {
+ PreferenceGroup {
+ EditTextPreference(
+ title = stringResource(R.string.set_default_min_duration),
+ key = DataConst.MIN_DURATION.key,
+ dataType = EditTextDataType.INT,
+ dialogMessage = stringResource(R.string.set_min_duration_unit),
+ isValueValid = { (it as? Int) in 0..1000}
+ )
+ }
+ }
+ if (isLoading) {
+ item {
+ SmallTitle(
+ text = stringResource(R.string.loading),
+ modifier = Modifier.padding(top = 6.dp),
+ textColor = MiuixTheme.colorScheme.onBackgroundVariant
+ )
+ }
+ } else {
+ item {
+ SmallTitle(
+ text = stringResource(R.string.min_duration_separate_configuration),
+ modifier = Modifier.padding(top = 6.dp),
+ textColor = MiuixTheme.colorScheme.onBackgroundVariant
+ )
+ }
+ itemsIndexed(appInfoFilter, key = { index, item ->
+ item.packageName + item.isChecked + index + appInfoFilter.size
+ }) { index, item ->
+ val topCornerRadius = if (index == 0) CardDefaults.ConorRadius else 0.dp
+ val bottomCornerRadius = if (index == appInfoFilter.size - 1) CardDefaults.ConorRadius else 0.dp
+ SpliceCard(
+ topCornerRadius,
+ bottomCornerRadius
+ ) {
+ MinDurationPreference(
+ icon = ImageIcon(
+ iconBitmap = item.icon.toBitmap().asImageBitmap(),
+ iconSize = IconSize.App
+ ),
+ title = item.appName,
+ summary = item.packageName,
+ checked = item.isChecked,
+ defValue = item.config.value?.toIntOrNull() ?: 0,
+ dialogMessage = dialogMessage
+ ) { text, value ->
+ if (value == 0) {
+ item.config.value = null
+ } else {
+ item.config.value = text
+ }
+ }
+ }
+ }
+ }
+ item {
+ Spacer(
+ modifier = Modifier.height(6.dp)
+ )
+ }
+ }
+ }
+ AlertDialog(
+ visibility = modifiedDialogVisibility,
+ title = stringResource(R.string.not_saved_title),
+ message = stringResource(R.string.not_saved_hint),
+ cancelable = false,
+ mode = AlertDialogMode.NegativeAndPositive,
+ negativeText = stringResource(R.string.button_abandonment),
+ positiveText = stringResource(R.string.button_reedit),
+ onNegativeButton = {
+ dismissDialog(modifiedDialogVisibility)
+ navController.popBackStack()
+ }
+ )
+}
+
+@Composable
+fun MinDurationPreference(
+ icon: ImageIcon? = null,
+ title: String,
+ summary: String? = null,
+ checked: MutableState,
+ defValue: Int = 0,
+ dialogMessage: String? = null,
+ onValueChange: ((String, Int) -> Unit)? = null,
+) {
+ val emptyString = stringResource(R.string.not_set_min_duration)
+ val dialogVisibility = remember { mutableStateOf(false) }
+ val spValue = remember { mutableIntStateOf(defValue) }
+ val stringValue = if (spValue.intValue != 0) spValue.intValue.toString() else emptyString
+ val doOnInputConfirm: (String) -> Unit = { newString: String ->
+ val oldValue = spValue.intValue
+ val newValue = newString.toIntOrNull()
+ if (newValue != null && (newValue in 0..1000) && oldValue != newValue) {
+ spValue.intValue = newValue
+ onValueChange?.let { it(newString, newValue) }
+ }
+ }
+ BasicComponent(
+ title = title,
+ summary = summary,
+ leftAction = {
+ icon?.let {
+ DrawableResIcon(it)
+ }
+ },
+ rightActions = {
+ Text(
+ modifier = Modifier.widthIn(max = 130.dp).padding(end = 12.dp),
+ text = stringValue,
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantActions,
+ textAlign = TextAlign.End,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 2
+ )
+ Switch(
+ checked = checked.value,
+ onCheckedChange = { newValue ->
+ checked.value = newValue
+ }
+ )
+ },
+ insideMargin = PaddingValues((icon?.getHorizontalPadding() ?: 16.dp), 16.dp, 16.dp, 16.dp),
+ onClick = {
+ dialogVisibility.value = true
+ }
+ )
+ EditTextDialog(
+ visibility = dialogVisibility,
+ title = title,
+ message = dialogMessage,
+ value = spValue.intValue.toString(),
+ onInputConfirm = { newString ->
+ doOnInputConfirm(newString)
+ }
+ )
+}
+
+data class DurationAppInfo(
+ val appName: String,
+ val packageName: String,
+ val icon: Drawable,
+ // 该 isChecked 用于存储应用是否被勾选, 0 为未勾选, 1 为勾选
+ var isChecked: MutableState,
+ var config: MutableState,
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt
new file mode 100644
index 00000000..f0653104
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt
@@ -0,0 +1,51 @@
+package com.gswxxn.restoresplashscreen.ui.apppage
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.component.AppListPage
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+
+/**
+ * 底部 - 移除底部图片 - 配置移除列表
+ */
+@Composable
+fun RemoveBrandingPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var exceptionMode by remember { mutableStateOf(SafeSP.getBoolean(DataConst.IS_REMOVE_BRANDING_IMAGE_EXCEPTION_MODE.key)) }
+ val exceptionSummary = stringResource(
+ R.string.exception_mode_message,
+ if (exceptionMode)
+ stringResource(R.string.not_chosen)
+ else
+ stringResource(R.string.chosen)
+ )
+ AppListPage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.background_image_title),
+ DataConst.REMOVE_BRANDING_IMAGE_LIST.key,
+ mode
+ ) {
+ item {
+ PreferenceGroup {
+ SwitchPreference(
+ title = stringResource(R.string.exception_mode),
+ summary = exceptionSummary,
+ key = DataConst.IS_REMOVE_BRANDING_IMAGE_EXCEPTION_MODE.key
+ ) {
+ exceptionMode = it
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt
new file mode 100644
index 00000000..53d6cec1
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt
@@ -0,0 +1,559 @@
+package com.gswxxn.restoresplashscreen.ui.component
+
+import android.content.pm.ApplicationInfo
+import android.graphics.drawable.Drawable
+import android.widget.Toast
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.add
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.captionBar
+import androidx.compose.foundation.layout.displayCutout
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.lazy.LazyListScope
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableFloatState
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.core.content.edit
+import androidx.core.graphics.drawable.toBitmap
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.notEqualsTo
+import dev.chrisbanes.haze.HazeStyle
+import dev.chrisbanes.haze.HazeTint
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.AlertDialog
+import dev.lackluster.hyperx.compose.base.AlertDialogMode
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.HazeScaffold
+import dev.lackluster.hyperx.compose.base.IconSize
+import dev.lackluster.hyperx.compose.base.ImageIcon
+import dev.lackluster.hyperx.compose.icon.Back
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.ButtonDefaults
+import top.yukonga.miuix.kmp.basic.CardDefaults
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.basic.InputField
+import top.yukonga.miuix.kmp.basic.LazyColumn
+import top.yukonga.miuix.kmp.basic.ListPopup
+import top.yukonga.miuix.kmp.basic.ListPopupColumn
+import top.yukonga.miuix.kmp.basic.ListPopupDefaults
+import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
+import top.yukonga.miuix.kmp.basic.PopupPositionProvider
+import top.yukonga.miuix.kmp.basic.SearchBar
+import top.yukonga.miuix.kmp.basic.SmallTitle
+import top.yukonga.miuix.kmp.basic.Surface
+import top.yukonga.miuix.kmp.basic.TextButton
+import top.yukonga.miuix.kmp.basic.TopAppBar
+import top.yukonga.miuix.kmp.basic.rememberTopAppBarState
+import top.yukonga.miuix.kmp.extra.DropdownImpl
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.icons.ImmersionMore
+import top.yukonga.miuix.kmp.icon.icons.Info
+import top.yukonga.miuix.kmp.icon.icons.Search
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.utils.BackHandler
+import top.yukonga.miuix.kmp.utils.HorizontalDivider
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissPopup
+import top.yukonga.miuix.kmp.utils.SmoothRoundedCornerShape
+import top.yukonga.miuix.kmp.utils.getWindowSize
+
+@Composable
+fun AppListPage(
+ navController: NavController,
+ adjustPadding: PaddingValues,
+ title: String,
+ checkedListKey: String?,
+ mode: BasePageDefaults.Mode,
+ blurEnabled: MutableState = MainActivity.blurEnabled,
+ blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight,
+ blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark,
+ extraContent: (LazyListScope.() -> Unit)? = null
+) {
+ val topAppBarBackground = MiuixTheme.colorScheme.background
+ val scrollBehavior = MiuixScrollBehavior(rememberTopAppBarState())
+ val listState = rememberLazyListState()
+ val topBarBlurState by remember {
+ derivedStateOf {
+ blurEnabled.value &&
+ scrollBehavior.state.collapsedFraction >= 1.0f &&
+ (listState.isScrollInProgress || listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 12)
+ }
+ }
+ val topBarBlurTintAlpha = remember { mutableFloatStateOf(
+ if (topAppBarBackground.luminance() >= 0.5f) blurTintAlphaLight.floatValue
+ else blurTintAlphaDark.floatValue
+ ) }
+ val isTopPopupExpanded = remember { mutableStateOf(false) }
+ val showTopPopup = remember { mutableStateOf(false) }
+ val modifiedDialogVisibility = remember { mutableStateOf(false) }
+
+ var selectSystemAppRequest by remember { mutableStateOf(false) }
+ var clearSelectedRequest by remember { mutableStateOf(false) }
+ var queryString by remember { mutableStateOf("") }
+
+ // 完整应用列表
+ var appInfoList by remember { mutableStateOf>(emptyList()) }
+
+ // 在列表中的条目
+ var appInfoFilter by remember { mutableStateOf>(emptyList()) }
+
+ // 保存前的配置
+ val tmpCheckedList = mutableSetOf().apply {
+ clear()
+ addAll(checkedListKey?.let { SafeSP.mSP?.getStringSet(it, emptySet()) } ?: emptySet())
+ }
+
+ val coroutineScope = rememberCoroutineScope()
+ var queryJob: Job? = null
+ var isLoading by remember { mutableStateOf(true) }
+
+ BackHandler(true) {
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ if (currentCheckedList.notEqualsTo(tmpCheckedList)) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+
+ LaunchedEffect(Unit) {
+ launch {
+ isLoading = true
+ delay(500)
+ val pm = HyperXActivity.context.packageManager
+ appInfoList = pm.getInstalledApplications(0).map {
+ MyAppInfo(
+ it.loadLabel(pm).toString(),
+ it.packageName,
+ it.loadIcon(pm),
+ mutableStateOf(it.packageName in tmpCheckedList),
+ it.flags and ApplicationInfo.FLAG_SYSTEM != 0
+ )
+ }.toList()
+ isLoading = false
+ }
+ }
+
+ if (selectSystemAppRequest) {
+ selectSystemAppRequest = false
+ appInfoList.filter{ it.isSystemApp }.forEach {
+ it.isChecked.value = true
+ }
+ appInfoFilter = appInfoList.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ }
+
+ if (clearSelectedRequest) {
+ clearSelectedRequest = false
+ appInfoList.forEach {
+ it.isChecked.value = false
+ }
+ appInfoFilter = appInfoList.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ }
+
+ LaunchedEffect(appInfoList, queryString) {
+ if (appInfoList.isEmpty()) return@LaunchedEffect
+ appInfoFilter = emptyList()
+ queryJob?.cancel()
+ queryJob = launch {
+ if (queryString.isBlank()) {
+ delay(100)
+ appInfoFilter = appInfoList.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ } else {
+ delay(300)
+ appInfoFilter = appInfoList.filter {
+ it.appName.contains(queryString, true) or it.packageName.contains(queryString, true)
+ }.toMutableList().apply {
+ sortBy { it.appName }
+ sortByDescending { it.isChecked.value }
+ }
+ }
+ }
+ }
+ val layoutDirection = LocalLayoutDirection.current
+ val systemBarInsets = WindowInsets.systemBars.add(WindowInsets.displayCutout).only(WindowInsetsSides.Horizontal).asPaddingValues()
+ val navigationIconPadding = PaddingValues.Absolute(
+ left = if (mode != BasePageDefaults.Mode.SPLIT_RIGHT) systemBarInsets.calculateLeftPadding(layoutDirection) else 0.dp
+ )
+ val actionsPadding = PaddingValues.Absolute(
+ right = if (mode != BasePageDefaults.Mode.SPLIT_LEFT) systemBarInsets.calculateRightPadding(layoutDirection) else 0.dp
+ )
+
+ HazeScaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = { contentPadding ->
+ TopAppBar(
+ color = topAppBarBackground.copy(
+ if (topBarBlurState) 0f else 1f
+ ),
+ title = title,
+ scrollBehavior = scrollBehavior,
+ navigationIcon = {
+ IconButton(
+ modifier = Modifier
+ .padding(navigationIconPadding)
+ .padding(start = 21.dp)
+ .size(40.dp),
+ onClick = {
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ if (currentCheckedList.notEqualsTo(tmpCheckedList)) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+ ) {
+ Icon(
+ modifier = Modifier.size(26.dp),
+ imageVector = MiuixIcons.Back,
+ contentDescription = "Back",
+ tint = MiuixTheme.colorScheme.onSurfaceSecondary
+ )
+ }
+ },
+ actions = {
+ if (isTopPopupExpanded.value) {
+ ListPopup(
+ show = showTopPopup,
+ popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
+ alignment = PopupPositionProvider.Align.TopRight,
+ onDismissRequest = {
+ isTopPopupExpanded.value = false
+ }
+ ) {
+ ListPopupColumn {
+ DropdownImpl(
+ text = stringResource(R.string.select_system_apps),
+ optionSize = 2,
+ isSelected = false,
+ onSelectedIndexChange = {
+ selectSystemAppRequest = true
+ dismissPopup(showTopPopup)
+ isTopPopupExpanded.value = false
+ },
+ index = 0
+ )
+ DropdownImpl(
+ text = stringResource(R.string.clear_selected_apps),
+ optionSize = 2,
+ isSelected = false,
+ onSelectedIndexChange = {
+ clearSelectedRequest = true
+ dismissPopup(showTopPopup)
+ isTopPopupExpanded.value = false
+ },
+ index = 1
+ )
+ }
+ }
+ showTopPopup.value = true
+ }
+ AnimatedVisibility(
+ queryString.isBlank()
+ ) {
+ IconButton(
+ modifier = Modifier
+ .padding(actionsPadding)
+ .padding(end = 21.dp)
+ .size(40.dp),
+ onClick = {
+ isTopPopupExpanded.value = true
+ }
+ ) {
+ Icon(
+ imageVector = MiuixIcons.ImmersionMore,
+ contentDescription = "Menu"
+ )
+ }
+ }
+ },
+ defaultWindowInsetsPadding = false,
+ horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current)
+ )
+ },
+ bottomBar = { contentPadding ->
+ val captionBarBottomPadding by rememberUpdatedState(
+ WindowInsets.captionBar.only(WindowInsetsSides.Bottom).asPaddingValues().calculateBottomPadding()
+ )
+ val buttonPaddingValues = with(LocalLayoutDirection.current) {
+ PaddingValues(
+ start = contentPadding.calculateStartPadding(this) + 16.dp,
+ top = 12.dp,
+ end = contentPadding.calculateEndPadding(this) + 16.dp,
+ bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + captionBarBottomPadding + 12.dp
+ )
+ }
+ Surface(
+ color = MiuixTheme.colorScheme.background.copy(
+ if (blurEnabled.value) 0f else 1f
+ ),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(Color.Transparent)
+ ) {
+ HorizontalDivider(
+ thickness = 0.75.dp,
+ color = MiuixTheme.colorScheme.dividerLine
+ )
+ TextButton(
+ modifier = Modifier
+ .padding(buttonPaddingValues)
+ .fillMaxWidth(),
+ text = stringResource(R.string.save),
+ colors = ButtonDefaults.textButtonColorsPrimary(),
+ minHeight = 50.dp,
+ onClick = {
+ CoroutineScope(Dispatchers.Default).launch {
+ SafeSP.mSP?.let { sp ->
+ val currentCheckedList = appInfoList.filter { it.isChecked.value }.map {
+ it.packageName
+ }.toSet()
+ sp.edit {
+ checkedListKey?.let { key ->
+ putStringSet(key, currentCheckedList)
+ }
+ commit()
+ }
+ tmpCheckedList.apply {
+ clear()
+ addAll(checkedListKey?.let { SafeSP.mSP?.getStringSet(it, emptySet()) } ?: emptySet())
+ }
+ coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_successful), Toast.LENGTH_SHORT).show()
+ }
+ }
+ } ?: coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_failed), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ }
+ )
+ }
+ }
+ },
+ blurTopBar = blurEnabled.value,
+ blurBottomBar = blurEnabled.value,
+ hazeStyle = HazeStyle(
+ blurRadius = 66.dp,
+ backgroundColor = topAppBarBackground,
+ tint = HazeTint(
+ topAppBarBackground.copy(alpha = topBarBlurTintAlpha.floatValue),
+ )
+ ),
+ adjustPadding = adjustPadding,
+ ) { paddingValues ->
+ LazyColumn(
+ modifier = Modifier
+ .height(getWindowSize().height.dp)
+ .background(MiuixTheme.colorScheme.background),
+ state = listState,
+ contentPadding = paddingValues,
+ topAppBarScrollBehavior = scrollBehavior
+ ) {
+ item {
+ SearchBar(
+ modifier = Modifier
+ .padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 6.dp),
+ inputField = {
+ InputField(
+ query = queryString,
+ onQueryChange = { queryString = it },
+ onSearch = { },
+ expanded = false,
+ onExpandedChange = { },
+ label = stringResource(R.string.search_hint),
+ leadingIcon = {
+ Icon(
+ modifier = Modifier.padding(start = 12.dp, end = 8.dp),
+ imageVector = MiuixIcons.Search,
+ tint = MiuixTheme.colorScheme.onSurfaceContainer,
+ contentDescription = "Search"
+ )
+ },
+ )
+ },
+ expanded = false,
+ onExpandedChange = { },
+ content = { }
+ )
+ }
+ item {
+ PreferenceGroup {
+ BasicComponent(
+ insideMargin = PaddingValues(16.dp),
+ summary = stringResource(R.string.save_hint),
+ leftAction = {
+ Image(
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .size(28.dp),
+ imageVector = MiuixIcons.Info,
+ contentDescription = null,
+ colorFilter = ColorFilter.tint(MiuixTheme.colorScheme.onSurfaceVariantSummary)
+ )
+ }
+ )
+ }
+ }
+ extraContent?.let { it1 -> it1() }
+ if (isLoading) {
+ item {
+ SmallTitle(
+ text = stringResource(R.string.loading),
+ modifier = Modifier.padding(top = 6.dp),
+ textColor = MiuixTheme.colorScheme.onBackgroundVariant
+ )
+ }
+ } else {
+ itemsIndexed(appInfoFilter, key = { index, item ->
+ item.packageName + item.isChecked + index + appInfoFilter.size
+ }) { index, item ->
+ val topCornerRadius = if (index == 0) CardDefaults.ConorRadius else 0.dp
+ val bottomCornerRadius = if (index == appInfoFilter.size - 1) CardDefaults.ConorRadius else 0.dp
+ SpliceCard(
+ topCornerRadius,
+ bottomCornerRadius
+ ) {
+ SwitchPreference(
+ icon = ImageIcon(
+ iconBitmap = item.icon.toBitmap().asImageBitmap(),
+ iconSize = IconSize.App
+ ),
+ title = item.appName,
+ summary = item.packageName,
+ checked = item.isChecked
+ )
+ }
+ }
+ }
+ item {
+ Spacer(
+ modifier = Modifier.height(6.dp)
+ )
+ }
+ }
+ }
+ AlertDialog(
+ visibility = modifiedDialogVisibility,
+ title = stringResource(R.string.not_saved_title),
+ message = stringResource(R.string.not_saved_hint),
+ cancelable = false,
+ mode = AlertDialogMode.NegativeAndPositive,
+ negativeText = stringResource(R.string.button_abandonment),
+ positiveText = stringResource(R.string.button_reedit),
+ onNegativeButton = {
+ dismissDialog(modifiedDialogVisibility)
+ navController.popBackStack()
+ }
+ )
+}
+
+@Composable
+fun SpliceCard(
+ topCornerRadius: Dp,
+ bottomCornerRadius: Dp,
+ content: @Composable ColumnScope.() -> Unit
+) {
+ val shape = remember {
+ if (topCornerRadius == 0.dp && bottomCornerRadius == 0.dp)
+ RectangleShape
+ else
+ SmoothRoundedCornerShape(
+ topStart = topCornerRadius, topEnd = topCornerRadius,
+ bottomStart = bottomCornerRadius, bottomEnd = bottomCornerRadius
+ )
+ }
+
+ Surface(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(
+ top = if (topCornerRadius != 0.dp) 6.dp else 0.dp,
+ bottom = if (bottomCornerRadius != 0.dp) 6.dp else 0.dp,
+ start = 12.dp,
+ end = 12.dp
+ ),
+ shape = shape,
+ color = CardDefaults.DefaultColor(),
+ ) {
+ Column(
+ modifier = Modifier.padding(CardDefaults.InsideMargin),
+ content = content
+ )
+ }
+}
+
+data class MyAppInfo(
+ val appName: String,
+ val packageName: String,
+ val icon: Drawable,
+ // 该 isChecked 用于存储应用是否被勾选, 0 为未勾选, 1 为勾选
+ var isChecked: MutableState,
+ val isSystemApp: Boolean
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt
new file mode 100644
index 00000000..22ea2e6b
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt
@@ -0,0 +1,1139 @@
+package com.gswxxn.restoresplashscreen.ui.component
+
+import android.graphics.Bitmap
+import android.widget.Toast
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.detectDragGestures
+import androidx.compose.foundation.gestures.detectHorizontalDragGestures
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.add
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.captionBar
+import androidx.compose.foundation.layout.displayCutout
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.magnifier
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableFloatState
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.TileMode
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.colorspace.ColorSpaces
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalHapticFeedback
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.core.content.edit
+import androidx.core.graphics.drawable.toBitmap
+import androidx.navigation.NavController
+import androidx.palette.graphics.Palette
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toMap
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toSet
+import com.gswxxn.restoresplashscreen.utils.GraphicUtils.getBgColor
+import com.gswxxn.restoresplashscreen.utils.IconPackManager
+import dev.chrisbanes.haze.HazeStyle
+import dev.chrisbanes.haze.HazeTint
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.AlertDialog
+import dev.lackluster.hyperx.compose.base.AlertDialogMode
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.HazeScaffold
+import dev.lackluster.hyperx.compose.icon.Back
+import dev.lackluster.hyperx.compose.preference.DropDownEntry
+import dev.lackluster.hyperx.compose.preference.EditTextDialog
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import top.yukonga.miuix.kmp.basic.BasicComponent
+import top.yukonga.miuix.kmp.basic.Box
+import top.yukonga.miuix.kmp.basic.Card
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.basic.LazyColumn
+import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
+import top.yukonga.miuix.kmp.basic.Slider
+import top.yukonga.miuix.kmp.basic.SliderColors
+import top.yukonga.miuix.kmp.basic.Surface
+import top.yukonga.miuix.kmp.basic.Text
+import top.yukonga.miuix.kmp.basic.TextButton
+import top.yukonga.miuix.kmp.basic.TextButtonColors
+import top.yukonga.miuix.kmp.basic.TopAppBar
+import top.yukonga.miuix.kmp.basic.rememberTopAppBarState
+import top.yukonga.miuix.kmp.extra.SpinnerEntry
+import top.yukonga.miuix.kmp.extra.SpinnerMode
+import top.yukonga.miuix.kmp.extra.SuperArrow
+import top.yukonga.miuix.kmp.extra.SuperSpinner
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.utils.BackHandler
+import top.yukonga.miuix.kmp.utils.HorizontalDivider
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog
+import top.yukonga.miuix.kmp.utils.SmoothRoundedCornerShape
+import top.yukonga.miuix.kmp.utils.getWindowSize
+import kotlin.math.max
+import kotlin.math.pow
+import kotlin.math.round
+
+@Composable
+fun ColorPickerPage(
+ navController: NavController,
+ adjustPadding: PaddingValues,
+ pkgName: String,
+ keyLight: String,
+ keyDark: String,
+ mode: BasePageDefaults.Mode,
+ blurEnabled: MutableState = MainActivity.blurEnabled,
+ blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight,
+ blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark
+) {
+ val topAppBarBackground = MiuixTheme.colorScheme.background
+ val scrollBehavior = MiuixScrollBehavior(rememberTopAppBarState())
+ val listState = rememberLazyListState()
+ val topBarBlurState by remember {
+ derivedStateOf {
+ blurEnabled.value &&
+ scrollBehavior.state.collapsedFraction >= 1.0f &&
+ (listState.isScrollInProgress || listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 12)
+ }
+ }
+ val topBarBlurTintAlpha = remember { mutableFloatStateOf(
+ if (topAppBarBackground.luminance() >= 0.5f) blurTintAlphaLight.floatValue
+ else blurTintAlphaDark.floatValue
+ ) }
+ val modifiedDialogVisibility = remember { mutableStateOf(false) }
+ val dropdownDialogVisibility = remember { mutableStateOf(false) }
+ val colorModeEntries = listOf(
+ DropDownEntry(title = stringResource(R.string.target_color_mode_light)),
+ DropDownEntry(title = stringResource(R.string.target_color_mode_dark))
+ )
+ val deviceDarkMode = isSystemInDarkTheme()
+ val currentDarkMode = remember { mutableStateOf(deviceDarkMode) }
+ var magnifierCenter by remember { mutableStateOf(Offset.Unspecified) }
+
+ val appName: String
+ val appIcon: Bitmap
+ with(HyperXActivity.context) {
+ val pm = this.packageManager
+ val realPkgName: String
+ if (pkgName.isNotBlank()) {
+ realPkgName = pkgName
+ appName = pm.getApplicationInfo(realPkgName, 0).loadLabel(pm).toString()
+ } else {
+ realPkgName = packageName
+ appName = stringResource(R.string.set_custom_bg_color)
+ }
+ val iconPackPkg = SafeSP.getString(DataConst.ICON_PACK_PACKAGE_NAME.key, DataConst.ICON_PACK_PACKAGE_NAME.value)
+ appIcon = (IconPackManager(this, iconPackPkg).getIconByPackageName(realPkgName) ?: pm.getApplicationIcon(realPkgName)).toBitmap()
+ }
+
+ var defaultColorLight = pkgName.let {
+ if (it.isNotBlank()) {
+ val value = (SafeSP.mSP?.getStringSet(keyLight, emptySet()) ?: emptySet()).toMap()[pkgName]
+ if (value.isNullOrBlank())
+ Color(getBgColor(appIcon, true))
+ else
+ Color(android.graphics.Color.parseColor(value))
+ } else {
+ val value = SafeSP.getString(keyLight, "")
+ if (value.isBlank())
+ Color.White
+ else
+ Color(android.graphics.Color.parseColor(value))
+ }
+ }
+ var defaultColorDark = pkgName.let {
+ if (it.isNotBlank()) {
+ val value = (SafeSP.mSP?.getStringSet(keyDark, emptySet()) ?: emptySet()).toMap()[pkgName]
+ if (value.isNullOrBlank())
+ Color(getBgColor(appIcon, false))
+ else
+ Color(android.graphics.Color.parseColor(value))
+ } else {
+ val value = SafeSP.getString(keyDark, "")
+ if (value.isBlank())
+ Color.Black
+ else
+ Color(android.graphics.Color.parseColor(value))
+ }
+ }
+ val selectedColor = remember { mutableStateOf(if (currentDarkMode.value) defaultColorDark else defaultColorLight) }
+ val paletteColors = remember { mutableStateListOf() }
+ val colorR = selectedColor.value.r
+ val colorG = selectedColor.value.g
+ val colorB = selectedColor.value.b
+ val hueColor = remember { mutableStateOf(
+ (if (currentDarkMode.value) defaultColorDark else defaultColorLight).let {
+ Triple(it.h, it.s, it.v)
+ }
+ ) }
+ val colorH: Float = hueColor.value.first
+ val colorS: Float = hueColor.value.second
+ val colorV: Float = hueColor.value.third
+
+ val coroutineScope = rememberCoroutineScope()
+
+ BackHandler(true) {
+ val defColor = if (currentDarkMode.value) defaultColorDark else defaultColorLight
+ if (defColor != selectedColor.value) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+
+ LaunchedEffect(Unit) {
+ launch {
+ paletteColors.clear()
+ delay(500)
+ val palette = Palette.from(appIcon).maximumColorCount(8).generate()
+ val colors = listOf(
+ palette.getDominantColor(0),
+ palette.getLightVibrantColor(0),
+ palette.getVibrantColor(0),
+ palette.getDarkVibrantColor(0),
+ palette.getLightMutedColor(0),
+ palette.getMutedColor(0),
+ palette.getDarkMutedColor(0)
+ ).distinct().map {
+ Color(it)
+ }.filter {
+ it.alpha == 1.0f
+ }
+ paletteColors.addAll(colors)
+ }
+ }
+ val layoutDirection = LocalLayoutDirection.current
+ val systemBarInsets = WindowInsets.systemBars.add(WindowInsets.displayCutout).only(WindowInsetsSides.Horizontal).asPaddingValues()
+ val navigationIconPadding = PaddingValues.Absolute(
+ left = if (mode != BasePageDefaults.Mode.SPLIT_RIGHT) systemBarInsets.calculateLeftPadding(layoutDirection) else 0.dp
+ )
+
+ HazeScaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = { contentPadding ->
+ TopAppBar(
+ color = topAppBarBackground.copy(
+ if (topBarBlurState) 0f else 1f
+ ),
+ title = appName,
+ scrollBehavior = scrollBehavior,
+ navigationIcon = {
+ IconButton(
+ modifier = Modifier
+ .padding(navigationIconPadding)
+ .padding(start = 21.dp)
+ .size(40.dp),
+ onClick = {
+ val defColor = if (currentDarkMode.value) defaultColorDark else defaultColorLight
+ if (defColor != selectedColor.value) {
+ modifiedDialogVisibility.value = true
+ } else {
+ navController.popBackStack()
+ }
+ }
+ ) {
+ Icon(
+ modifier = Modifier.size(26.dp),
+ imageVector = MiuixIcons.Back,
+ contentDescription = "Back",
+ tint = MiuixTheme.colorScheme.onSurfaceSecondary
+ )
+ }
+ },
+ defaultWindowInsetsPadding = false,
+ horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current)
+ )
+ },
+ bottomBar = { contentPadding ->
+ val captionBarBottomPadding by rememberUpdatedState(
+ WindowInsets.captionBar.only(WindowInsetsSides.Bottom).asPaddingValues().calculateBottomPadding()
+ )
+ val buttonPaddingValues = with(LocalLayoutDirection.current) {
+ PaddingValues(
+ start = contentPadding.calculateStartPadding(this) + 16.dp,
+ top = 12.dp,
+ end = contentPadding.calculateEndPadding(this) + 16.dp,
+ bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + captionBarBottomPadding + 12.dp
+ )
+ }
+ Surface(
+ color = MiuixTheme.colorScheme.background.copy(
+ if (blurEnabled.value) 0f else 1f
+ ),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(Color.Transparent)
+ ) {
+ HorizontalDivider(
+ thickness = 0.75.dp,
+ color = MiuixTheme.colorScheme.dividerLine
+ )
+ Row(
+ modifier = Modifier
+ .padding(buttonPaddingValues)
+ .fillMaxWidth()
+ ) {
+ TextButton(
+ modifier = Modifier.weight(1.0f),
+ text = stringResource(R.string.undo_modification),
+ minHeight = 50.dp,
+ onClick = {
+ (if (currentDarkMode.value) defaultColorDark else defaultColorLight).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ )
+ Spacer(modifier = Modifier.width(12.dp))
+ TextButton(
+ modifier = Modifier.weight(1.0f),
+ text = stringResource(R.string.save),
+ colors = selectedColor.value.let {
+ TextButtonColors(
+ color = it,
+ disabledColor = it,
+ textColor = if (it.luminance() > 0.5f) Color.Black else Color.White,
+ disabledTextColor = it
+ )
+ },
+ minHeight = 50.dp,
+ onClick = {
+ CoroutineScope(Dispatchers.Default).launch {
+ SafeSP.mSP?.let { sp ->
+ val targetKey = if (currentDarkMode.value) {
+ keyDark
+ } else {
+ keyLight
+ }
+ val colorHexString = "#" + "%08X".format(selectedColor.value.toArgb()).substring(2)
+ if (pkgName.isNotBlank()) {
+ val tmpConfigMap = (SafeSP.mSP?.getStringSet(targetKey, emptySet()) ?: emptySet()).toMap()
+ tmpConfigMap[pkgName] = colorHexString
+ sp.edit {
+ putStringSet(targetKey, tmpConfigMap.toSet())
+ commit()
+ }
+ } else {
+ sp.edit {
+ putString(targetKey, colorHexString)
+ }
+ }
+ defaultColorLight = pkgName.let {
+ if (it.isNotBlank()) {
+ val value = (SafeSP.mSP?.getStringSet(keyLight, emptySet()) ?: emptySet()).toMap()[pkgName]
+ if (value.isNullOrBlank())
+ Color(getBgColor(appIcon, true))
+ else
+ Color(android.graphics.Color.parseColor(value))
+ } else {
+ val value = SafeSP.getString(keyLight, "")
+ if (value.isBlank())
+ Color.White
+ else
+ Color(android.graphics.Color.parseColor(value))
+ }
+ }
+ defaultColorDark = pkgName.let {
+ if (it.isNotBlank()) {
+ val value = (SafeSP.mSP?.getStringSet(keyDark, emptySet()) ?: emptySet()).toMap()[pkgName]
+ if (value.isNullOrBlank())
+ Color(getBgColor(appIcon, false))
+ else
+ Color(android.graphics.Color.parseColor(value))
+ } else {
+ val value = SafeSP.getString(keyDark, "")
+ if (value.isBlank())
+ Color.Black
+ else
+ Color(android.graphics.Color.parseColor(value))
+ }
+ }
+ coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_successful), Toast.LENGTH_SHORT).show()
+ }
+ }
+ } ?: coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.save_failed), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+ },
+ blurTopBar = blurEnabled.value,
+ blurBottomBar = blurEnabled.value,
+ hazeStyle = HazeStyle(
+ blurRadius = 66.dp,
+ backgroundColor = topAppBarBackground,
+ tint = HazeTint(
+ topAppBarBackground.copy(alpha = topBarBlurTintAlpha.floatValue),
+ )
+ ),
+ adjustPadding = adjustPadding,
+ ) { paddingValues ->
+ LazyColumn(
+ modifier = Modifier
+ .height(getWindowSize().height.dp)
+ .background(MiuixTheme.colorScheme.background),
+ state = listState,
+ contentPadding = paddingValues,
+ topAppBarScrollBehavior = scrollBehavior
+ ) {
+ item {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 12.dp)
+ .padding(bottom = 6.dp, top = 12.dp),
+ color = colorResource(R.color.colorDemoBackground)
+ ) {
+ Layout(
+ content = {
+ Image(
+ modifier = Modifier.drawBehind {
+ drawRect(selectedColor.value)
+ },
+ painter = painterResource(R.drawable.demo_transparency),
+ contentDescription = null
+ )
+ val dp100px = with(LocalDensity.current) { 100.dp.toPx() }
+ Image(
+ modifier = Modifier
+ .magnifier(
+ sourceCenter = { magnifierCenter },
+ magnifierCenter = { magnifierCenter - Offset(0f, dp100px) },
+ zoom = 5f,
+ size = DpSize(100.dp, 100.dp),
+ cornerRadius = 50.dp
+ )
+ .pointerInput(Unit) {
+ detectDragGestures(
+ // Show the magnifier at the original pointer position.
+ onDragStart = {
+ magnifierCenter = it
+ Color(
+ appIcon.getColor(
+ (appIcon.width * magnifierCenter.x / size.width).toInt().coerceIn(0, appIcon.width - 1),
+ (appIcon.height * magnifierCenter.y / size.height).toInt().coerceIn(0, appIcon.height - 1)
+ ).toArgb()
+ ).copy(1.0f).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ },
+ // Make the magnifier follow the finger while dragging.
+ onDrag = { _, delta ->
+ magnifierCenter += delta
+ Color(
+ appIcon.getColor(
+ (appIcon.width * magnifierCenter.x / size.width).toInt().coerceIn(0, appIcon.width - 1),
+ (appIcon.height * magnifierCenter.y / size.height).toInt().coerceIn(0, appIcon.height - 1)
+ ).toArgb()
+ ).copy(1.0f).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ },
+ // Hide the magnifier when the finger lifts.
+ onDragEnd = { magnifierCenter = Offset.Unspecified },
+ onDragCancel = { magnifierCenter = Offset.Unspecified }
+ )
+ }
+ ,
+ bitmap = appIcon.asImageBitmap(),
+ contentDescription = null
+ )
+ Text(
+ text = stringResource(R.string.please_select),
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
+ )
+ for (color in paletteColors) {
+ Surface(
+ border = BorderStroke(2.dp, MiuixTheme.colorScheme.dividerLine),
+ shape = CircleShape,
+ color = color,
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ color.let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ )
+ }
+ }
+ }
+ ) { measurables, constraints ->
+ if (measurables.size < 3) {
+ layout(0, 0) { }
+ }
+ val px16dp = 16.dp.roundToPx()
+ val px32dp = 32.dp.roundToPx()
+ val px48dp = 48.dp.roundToPx()
+ val px250dp = 250.dp.roundToPx()
+
+ val image = measurables[0].measure(constraints.copy(
+ minHeight = px250dp, maxHeight = px250dp
+ ))
+ val icon = measurables[1].measure(constraints.copy(
+ minHeight = px48dp, maxHeight = px48dp,
+ minWidth = px48dp, maxWidth = px48dp
+ ))
+ val rightWidth = constraints.maxWidth - image.width - px48dp
+ val text = measurables[2].measure(constraints.copy(
+ maxWidth = rightWidth
+ ))
+ val colorCount = measurables.size - 3
+ var colorPerRow = 1
+ val colorLines: Int
+ val colors: List?
+ if (colorCount > 0) {
+ val colorConstraints = constraints.copy(
+ minHeight = px32dp, maxHeight = px32dp,
+ minWidth = px32dp, maxWidth = px32dp
+ )
+ colors = measurables.subList(3, measurables.size).map {
+ it.measure(colorConstraints)
+ }
+ while (px48dp * (colorPerRow + 1) - px16dp < rightWidth) {
+ colorPerRow++
+ }
+ colorLines = colorCount / colorPerRow + if (colorCount % colorPerRow > 0) 1 else 0
+ } else {
+ colorLines = 0
+ colors = null
+ }
+ val rightHeight = text.height + (colorLines + 1) * px32dp + colorLines * px16dp
+ val totalHeight = max(image.height, rightHeight) + px32dp
+ layout(constraints.maxWidth, totalHeight) {
+ image.place(px16dp, (totalHeight - image.height) / 2)
+ icon.place(
+ px16dp + image.width / 2 - icon.width / 2,
+ totalHeight / 2 - icon.height / 2
+ )
+ val rightCenterX = px16dp + image.width + (constraints.maxWidth - px16dp - image.width) / 2
+ val textY = (totalHeight - rightHeight) / 2
+ text.place(rightCenterX - text.width / 2, textY)
+ if (colors != null) {
+ var line = 0
+ val colorX = rightCenterX - (px48dp * colorPerRow - px16dp) / 2
+ while (colorCount >= colorPerRow * (line + 1)) {
+ val colorY = textY + text.height + px16dp + px48dp * line
+ for (i in 0 until colorPerRow) {
+ colors[line * colorPerRow + i].place(
+ colorX + px48dp * i, colorY
+ )
+ }
+ line++
+ }
+ val lastLineCount = colorCount % colorPerRow
+ if (lastLineCount > 0) {
+ val lastLineWidth = px48dp * lastLineCount - px16dp
+ var lastColorX = rightCenterX - lastLineWidth / 2
+ val colorY = textY + text.height + px16dp + px48dp * line
+ for (i in line * colorPerRow until colorCount) {
+ colors[i].place(lastColorX, colorY)
+ lastColorX += px48dp
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ ColorModePreference(
+ title = stringResource(R.string.target_color_mode),
+ summary = stringResource(R.string.target_color_mode_tips),
+ entries = colorModeEntries,
+ darkMode = currentDarkMode
+ ) {
+ val defColor = if (currentDarkMode.value) defaultColorDark else defaultColorLight
+ if (defColor != selectedColor.value) {
+ dropdownDialogVisibility.value = true
+ } else {
+ currentDarkMode.value = !currentDarkMode.value
+ (if (currentDarkMode.value) defaultColorDark else defaultColorLight).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ }
+ ColorStringPreference(
+ title = stringResource(R.string.manual_input),
+ colorValue = selectedColor,
+ hueColor = hueColor,
+ dialogMessage = stringResource(R.string.manual_input_hint)
+ )
+ }
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.rgb_color_space)
+ ) {
+ IntColorSeekBar(
+ title = stringResource(R.string.rgb_r),
+ value = colorR,
+ min = 0,
+ max = 255,
+ colors = SliderColors(
+ foregroundColor = Color(0xFFF36060),
+ disabledForegroundColor = Color(0x7FF36060),
+ backgroundColor = MiuixTheme.colorScheme.tertiaryContainerVariant
+ )
+ ) {
+ Color(it, colorG, colorB).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ IntColorSeekBar(
+ title = stringResource(R.string.rgb_g),
+ value = colorG,
+ min = 0,
+ max = 255,
+ colors = SliderColors(
+ foregroundColor = Color(0xFF5FF25F),
+ disabledForegroundColor = Color(0x7F5FF25F),
+ backgroundColor = MiuixTheme.colorScheme.tertiaryContainerVariant
+ )
+ ) {
+ Color(colorR, it, colorB).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ IntColorSeekBar(
+ title = stringResource(R.string.rgb_b),
+ value = colorB,
+ min = 0,
+ max = 255,
+ colors = SliderColors(
+ foregroundColor = Color(0xFF5F5FF3),
+ disabledForegroundColor = Color(0x7F5F5FF3),
+ backgroundColor = MiuixTheme.colorScheme.tertiaryContainerVariant
+ )
+ ) {
+ Color(colorR, colorG, it).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.hsv_color_space)
+ ) {
+ HueSeekBar(
+ title = stringResource(R.string.hue),
+ value = colorH
+ ) {
+ selectedColor.value = Color.hsv(it, colorS, colorV)
+ hueColor.value = hueColor.value.copy(
+ first = it
+ )
+ }
+ FloatColorSeekBar(
+ title = stringResource(R.string.saturation),
+ value = colorS,
+ min = 0.0f,
+ max = 1.0f,
+ ) {
+ selectedColor.value = Color.hsv(colorH, it, colorV)
+ hueColor.value = hueColor.value.copy(
+ second = it
+ )
+ }
+ FloatColorSeekBar(
+ title = stringResource(R.string.value),
+ value = colorV,
+ min = 0.0f,
+ max = 1.0f
+ ) {
+ selectedColor.value = Color.hsv(colorH, colorS, it)
+ hueColor.value = hueColor.value.copy(
+ third = it
+ )
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ first = true,
+ last = true
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ CoroutineScope(Dispatchers.Default).launch {
+ SafeSP.mSP?.let { sp ->
+ val targetKey = if (currentDarkMode.value) {
+ keyDark
+ } else {
+ keyLight
+ }
+ if (pkgName.isNotBlank()) {
+ val tmpConfigMap =
+ (SafeSP.mSP?.getStringSet(targetKey, emptySet())
+ ?: emptySet()).toMap()
+ tmpConfigMap.remove(pkgName)
+ sp.edit {
+ putStringSet(targetKey, tmpConfigMap.toSet())
+ commit()
+ }
+ defaultColorLight = Color(getBgColor(appIcon, true))
+ defaultColorDark = Color(getBgColor(appIcon, false))
+ } else {
+ sp.edit {
+ remove(targetKey)
+ commit()
+ }
+ defaultColorLight = Color.White
+ defaultColorDark = Color.Black
+ }
+ coroutineScope.launch {
+ selectedColor.value =
+ if (currentDarkMode.value) defaultColorDark
+ else defaultColorLight
+ HyperXActivity.context.let {
+ Toast.makeText(
+ it,
+ it.getString(R.string.save_successful),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ } ?: coroutineScope.launch {
+ HyperXActivity.context.let {
+ Toast.makeText(
+ it,
+ it.getString(R.string.save_failed),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ }
+ ) {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ text = stringResource(R.string.reset),
+ fontSize = MiuixTheme.textStyles.headline1.fontSize,
+ fontWeight = FontWeight.Medium,
+ color = colorResource(R.color.colorTextRed)
+ )
+ }
+ }
+ }
+ }
+ }
+ AlertDialog(
+ visibility = modifiedDialogVisibility,
+ title = stringResource(R.string.not_saved_title),
+ message = stringResource(R.string.not_saved_hint),
+ cancelable = false,
+ mode = AlertDialogMode.NegativeAndPositive,
+ negativeText = stringResource(R.string.button_abandonment),
+ positiveText = stringResource(R.string.button_reedit),
+ onNegativeButton = {
+ dismissDialog(modifiedDialogVisibility)
+ navController.popBackStack()
+ }
+ )
+ AlertDialog(
+ visibility = dropdownDialogVisibility,
+ title = stringResource(R.string.not_saved_title),
+ message = stringResource(R.string.not_saved_hint),
+ cancelable = false,
+ mode = AlertDialogMode.NegativeAndPositive,
+ negativeText = stringResource(R.string.button_abandonment),
+ positiveText = stringResource(R.string.button_reedit),
+ onNegativeButton = {
+ dismissDialog(dropdownDialogVisibility)
+ currentDarkMode.value = !currentDarkMode.value
+ (if (currentDarkMode.value) defaultColorDark else defaultColorLight).let { color ->
+ selectedColor.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ )
+}
+
+@Composable
+fun ColorModePreference(
+ title: String,
+ summary: String? = null,
+ entries: List,
+ darkMode: MutableState,
+ onSelectedIndexChange: ((Int) -> Unit)
+) {
+ val wrappedEntries = entries.map { entry ->
+ SpinnerEntry(
+ title = entry.title,
+ )
+ }
+ SuperSpinner(
+ title = title,
+ summary = summary,
+ items = wrappedEntries,
+ selectedIndex = if (darkMode.value) 1 else 0,
+ mode = SpinnerMode.AlwaysOnRight,
+ showValue = true
+ ) { newValue ->
+ onSelectedIndexChange(newValue)
+ }
+}
+
+@Composable
+fun ColorStringPreference(
+ title: String,
+ summary: String? = null,
+ colorValue: MutableState,
+ hueColor: MutableState>,
+ dialogMessage: String? = null
+) {
+ val dialogVisibility = remember { mutableStateOf(false) }
+ val stringValue = "#" + "%08X".format(colorValue.value.toArgb()).substring(2)
+ val doOnInputConfirm: (String) -> Unit = { newString: String ->
+ val trimmedString = newString.replace("#", "")
+ if (trimmedString.length <= 6) {
+ val oldValue = colorValue.value.toArgb()
+ val newValue = trimmedString.toIntOrNull(16)
+ if (newValue != null && oldValue != newValue) {
+ Color(android.graphics.Color.parseColor("#$trimmedString")).let { color ->
+ colorValue.value = color
+ hueColor.value = Triple(color.h, color.s, color.v)
+ }
+ }
+ }
+ }
+ SuperArrow(
+ title = title,
+ summary = summary,
+ rightText = stringValue,
+ insideMargin = PaddingValues(16.dp),
+ onClick = {
+ dialogVisibility.value = true
+ }
+ )
+ EditTextDialog(
+ visibility = dialogVisibility,
+ title = title,
+ message = dialogMessage,
+ value = "%08X".format(colorValue.value.toArgb()).substring(2),
+ onInputConfirm = { newString ->
+ doOnInputConfirm(newString)
+ }
+ )
+}
+
+@Composable
+fun IntColorSeekBar(
+ title: String,
+ value: Int,
+ min: Int,
+ max: Int,
+ colors: SliderColors,
+ onValueChange: ((Int) -> Unit)? = null
+) {
+ Column {
+ BasicComponent(
+ modifier = Modifier,
+ insideMargin = PaddingValues(16.dp, 16.dp, 16.dp, 12.dp),
+ title = title,
+ rightActions = {
+ Text(
+ text = "$value / $max",
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantActions,
+ textAlign = TextAlign.End,
+ )
+ }
+ )
+ Slider(
+ modifier = Modifier.padding(16.dp, 0.dp, 16.dp, 16.dp),
+ progress = value.toFloat(),
+ minValue = min.toFloat(),
+ maxValue = max.toFloat(),
+ height = 28.dp,
+ colors = colors,
+ onProgressChange = { newValue ->
+ val newInt = newValue.toInt()
+ onValueChange?.let { it1 -> it1(newInt) }
+ }
+ )
+ }
+}
+
+@Composable
+fun HueSeekBar(
+ title: String,
+ value: Float,
+ onValueChange: (Float) -> Unit
+) {
+ Column {
+ BasicComponent(
+ modifier = Modifier,
+ insideMargin = PaddingValues(16.dp, 16.dp, 16.dp, 12.dp),
+ title = title,
+ rightActions = {
+ Text(
+ text = "${value.let { it1 -> "%.2f".format(it1) }} / ${"%.2f".format(360.0f)}",
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantActions,
+ textAlign = TextAlign.End,
+ )
+ }
+ )
+ val hapticFeedback = LocalHapticFeedback.current
+ var dragOffset by remember { mutableFloatStateOf(0f) }
+ var isDragging by remember { mutableStateOf(false) }
+ var currentValue by remember { mutableFloatStateOf(value) }
+ var hapticTriggered by remember { mutableStateOf(false) }
+ val updatedOnProgressChange by rememberUpdatedState(onValueChange)
+ val calculateProgress = { offset: Float, width: Int, height: Int ->
+ val newValue = ((offset - height / 2) / (width - height)).coerceIn(0.0f, 1.0f) * 360.0f
+ (round(newValue * 10f.pow(2)) / 10f.pow(2)).coerceIn(0.0f, 360.0f)
+ }
+
+ Box(
+ modifier = Modifier
+ .padding(16.dp, 0.dp, 16.dp, 16.dp)
+ .pointerInput(Unit) {
+ detectHorizontalDragGestures(
+ onDragStart = { offset ->
+ isDragging = true
+ dragOffset = offset.x
+ currentValue = calculateProgress(dragOffset, size.width, size.height)
+ updatedOnProgressChange(currentValue)
+ hapticTriggered = false
+ },
+ onHorizontalDrag = { _, dragAmount ->
+ dragOffset = (dragOffset + dragAmount).coerceIn(0f, size.width.toFloat())
+ currentValue = calculateProgress(dragOffset, size.width, size.height)
+ updatedOnProgressChange(currentValue)
+ if ((currentValue == 0.0f || currentValue == 360.0f) && !hapticTriggered) {
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
+ hapticTriggered = true
+ } else if (currentValue != 0.0f && currentValue != 360.0f) {
+ hapticTriggered = false
+ }
+ },
+ onDragEnd = {
+ isDragging = false
+ }
+ )
+ },
+ contentAlignment = Alignment.CenterStart
+ ) {
+ Canvas(
+ modifier = Modifier.fillMaxWidth().height(28.dp)
+ .clip(SmoothRoundedCornerShape(28.dp))
+ .drawBehind {
+ val barHeight = size.height
+ val barWidth = size.width
+ val cornerRadius = CornerRadius.Zero
+ drawRoundRect(
+ brush = Brush.horizontalGradient(
+ colors = listOf(
+ Color.hsv(0.0f, 1.0f, 1.0f),
+ Color.hsv(60.0f, 1.0f, 1.0f),
+ Color.hsv(120.0f, 1.0f, 1.0f),
+ Color.hsv(180.0f, 1.0f, 1.0f),
+ Color.hsv(240.0f, 1.0f, 1.0f),
+ Color.hsv(300.0f, 1.0f, 1.0f),
+ Color.hsv(360.0f, 1.0f, 1.0f),
+ ),
+ startX = size.height,
+ endX = size.width - size.height,
+ tileMode = TileMode.Clamp
+ ),
+ size = Size(barWidth, barHeight),
+ topLeft = Offset(0f, center.y - barHeight / 2),
+ cornerRadius = cornerRadius
+ )
+ }
+ ) {
+ val barHeight = size.height
+ val barWidth = size.width
+ val circleX = barHeight / 2 + (value / 360.0f) * (barWidth - barHeight)
+ drawCircle(
+ color = Color.White.copy(0.9f),
+ radius = size.height / 2 - 6.dp.toPx(),
+ center = Offset(circleX, barHeight / 2),
+ style = Stroke(
+ width = 4.dp.toPx()
+ )
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun FloatColorSeekBar(
+ title: String,
+ value: Float,
+ min: Float,
+ max: Float,
+ onValueChange: ((Float) -> Unit)? = null
+) {
+ Column {
+ BasicComponent(
+ modifier = Modifier,
+ insideMargin = PaddingValues(16.dp, 16.dp, 16.dp, 12.dp),
+ title = title,
+ rightActions = {
+ Text(
+ text = "${value.let { it1 -> "%.2f".format(it1) }} / ${"%.2f".format(max)}",
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantActions,
+ textAlign = TextAlign.End,
+ )
+ }
+ )
+ Slider(
+ modifier = Modifier.padding(16.dp, 0.dp, 16.dp, 16.dp),
+ progress = value,
+ minValue = min,
+ maxValue = max,
+ height = 28.dp,
+ onProgressChange = { newValue ->
+ onValueChange?.let { it1 -> it1(newValue) }
+ }
+ )
+ }
+}
+
+private val Color.r: Int
+ get() {
+ return ((convert(ColorSpaces.Srgb).value shr 32).toInt() shr 16) and 0xFF
+ }
+
+private val Color.g: Int
+ get() {
+ return ((convert(ColorSpaces.Srgb).value shr 32).toInt() shr 8) and 0xFF
+ }
+
+private val Color.b: Int
+ get() {
+ return (convert(ColorSpaces.Srgb).value shr 32).toInt() and 0xFF
+ }
+
+private val Color.h: Float
+ get() {
+ val r = red.toDouble()
+ val g = green.toDouble()
+ val b = blue.toDouble()
+ val min = minOf(r, g, b)
+ val h = when (val max = maxOf(r, g, b)) {
+ min -> 0.0
+ r -> 60 * (g - b) / (max - min)
+ g -> 120 + 60 * (b - r) / (max - min)
+ b -> 240 + 60 * (r - g) / (max - min)
+ else -> 0.0
+ }
+ return ((h + 360) % 360).toFloat().coerceIn(0.0f, 360.0f)
+ }
+
+private val Color.s: Float
+ get() {
+ val r = red.toDouble()
+ val g = green.toDouble()
+ val b = blue.toDouble()
+ val min = minOf(r, g, b)
+ val max = maxOf(r, g, b)
+ return (
+ if (max == 0.0) 0.0
+ else ((max - min) / max)
+ ).toFloat()
+ }
+
+private val Color.v: Float
+ get() {
+ val r = red.toDouble()
+ val g = green.toDouble()
+ val b = blue.toDouble()
+ return maxOf(r, g, b).toFloat()
+ }
+
+object ColorPickerPageArgs {
+ const val PACKAGE_NAME = "PkgName"
+ const val KEY_LIGHT = "KeyLight"
+ const val KEY_DARK = "KeyDark"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt
new file mode 100644
index 00000000..9f75fe96
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt
@@ -0,0 +1,107 @@
+package com.gswxxn.restoresplashscreen.ui.component
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import top.yukonga.miuix.kmp.basic.Card
+import top.yukonga.miuix.kmp.basic.Text
+import kotlin.math.max
+
+@Composable
+fun HeaderCard(
+ imageResID: Int,
+ title: String,
+ maxLines: Int = 1
+) {
+ val offset: Offset
+ val blurRadius: Float
+ with(LocalDensity.current) {
+ offset = Offset(0f, 3.dp.toPx())
+ blurRadius = 6.dp.toPx()
+ }
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 12.dp)
+ .padding(bottom = 6.dp, top = 12.dp)
+ ) {
+ var textStyle by remember { mutableStateOf(
+ TextStyle(
+ fontSize = 30.sp,
+ fontWeight = FontWeight.SemiBold,
+ shadow = Shadow(
+ color = Color.Black.copy(alpha = 0.1f),
+ offset = offset,
+ blurRadius = blurRadius
+ )
+ )
+ ) }
+ var readyToDraw by remember { mutableStateOf(false) }
+ Layout(
+ content = {
+ Image(
+ modifier = Modifier,
+ painter = painterResource(imageResID),
+ contentDescription = null
+ )
+ Text(
+ modifier = Modifier
+ .drawWithContent {
+ if (readyToDraw) drawContent()
+ },
+ text = title,
+ textAlign = TextAlign.Center,
+ style = textStyle,
+ onTextLayout = { textLayoutResult ->
+ if (textLayoutResult.didOverflowWidth || textLayoutResult.didOverflowHeight) {
+ textStyle = textStyle.copy(fontSize = textStyle.fontSize * 0.9)
+ } else {
+ readyToDraw = true
+ }
+ },
+ maxLines = maxLines
+ )
+ }
+ ) { measurables, constraints ->
+ if (measurables.size != 2) {
+ layout(0, 0) { }
+ }
+ val px16dp = 16.dp.roundToPx()
+ val px32dp = 32.dp.roundToPx()
+ val px250dp = 250.dp.roundToPx()
+ val image = measurables[0].measure(constraints.copy(
+ minHeight = px250dp, maxHeight = px250dp
+ ))
+ val text = measurables[1].measure(constraints.copy(
+ maxWidth = constraints.maxWidth - image.width - px16dp * 3
+ ))
+ val totalHeight = max(image.height, text.height) + px32dp
+ layout(constraints.maxWidth, totalHeight) {
+ image.place(px16dp, (totalHeight - image.height) / 2)
+ val rightCenterX = px16dp + image.width + (constraints.maxWidth - px16dp - image.width) / 2
+ text.place(
+ rightCenterX - text.width / 2,
+ (totalHeight - text.height) / 2
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BGColorIndividualConfig.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BGColorIndividualConfig.kt
deleted file mode 100644
index a112f8f9..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BGColorIndividualConfig.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.content.Intent
-import android.graphics.Color
-import android.graphics.drawable.GradientDrawable
-import android.view.View
-import android.widget.CheckBox
-import android.widget.TextView
-import cn.fkj233.ui.activity.dp2px
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.ConstValue.SELECT_COLOR_CODE
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.AdapterConfigBinding
-import com.gswxxn.restoresplashscreen.ui.ColorSelectActivity
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity.Companion.isDarkMode
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.utils.AppInfoHelper
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toastL
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/** 单独配置背景颜色 */
-object BGColorIndividualConfig : IConfigApps {
- override val titleID: Int
- get() = R.string.configure_bg_colors_individually
- override val subSettingHint: Int
- get() = R.string.custom_bg_color_sub_setting_hint
- override val configMapPrefs: PrefsData>
- get() = if (isDarkMode) DataConst.INDIVIDUAL_BG_COLOR_APP_MAP_DARK else DataConst.INDIVIDUAL_BG_COLOR_APP_MAP
- override val submitSet: Boolean
- get() = false
- override val submitMap: Boolean
- get() = true
-
- override fun adpTextView(
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): TextView.() -> Unit = {
- if (item.config == null) {
- text = context.getString(R.string.default_value)
- background = null
- } else {
- text = ""
- width = dp2px(context, 30f)
- background = GradientDrawable().apply {
- setColor(Color.parseColor(item.config))
- setStroke(2, context.getColor(R.color.brandColor))
- cornerRadius = dp2px(context, 15f).toFloat()
- }
- }
- }
-
- override fun adpCheckBox(
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): CheckBox.() -> Unit = { visibility = View.GONE }
-
- override fun adpLinearLayout(
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): (View) -> Unit = {
- context.startActivityForResult(Intent(context, ColorSelectActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE_PACKAGE_NAME, item.packageName)
- putExtra(ConstValue.EXTRA_MESSAGE_APP_INDEX, context.appInfo.getIndex(item))
- putExtra(ConstValue.EXTRA_MESSAGE_CURRENT_COLOR, item.config)
- }, SELECT_COLOR_CODE)
- }
-
- override fun onActivityResult(context: ConfigAppsActivity, requestCode: Int, resultCode: Int, data: Intent?) {
- val color = data?.getStringExtra(ConstValue.EXTRA_MESSAGE_SELECTED_COLOR)
- val pkgName = data?.getStringExtra(ConstValue.EXTRA_MESSAGE_PACKAGE_NAME)
- val index = data?.getIntExtra(ConstValue.EXTRA_MESSAGE_APP_INDEX, -1) ?: -1
- if (requestCode != SELECT_COLOR_CODE || color == null || index == -1 || pkgName == null) return
- try {
- when (resultCode) {
- ConstValue.SELECTED_COLOR -> {
- context.appInfo.setConfig(index, color)
- context.onRefreshList?.invoke()
- context.configMap[pkgName] = color
- }
-
- ConstValue.DEFAULT_COLOR -> {
- context.appInfo.setConfig(index, null)
- context.onRefreshList?.invoke()
- context.configMap.remove(pkgName)
- }
-
- ConstValue.UNDO_MODIFY -> {}
- }
- } catch (_: RuntimeException) {
- context.toastL(context.getString(R.string.mode_conflict))
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BackgroundExcept.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BackgroundExcept.kt
deleted file mode 100644
index 95b60d22..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BackgroundExcept.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 背景 - 替换背景颜色 - 排除列表
- */
-object BackgroundExcept : IConfigApps {
- override val titleID: Int
- get() = R.string.background_except_title
- override val checkedListPrefs: PrefsData>
- get() = DataConst.BG_EXCEPT_LIST
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BrandingImage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BrandingImage.kt
deleted file mode 100644
index e710680d..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BrandingImage.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 底部 - 移除底部图片 - 配置移除列表
- */
-object BrandingImage : IConfigApps {
- override val titleID: Int
- get() = R.string.background_image_title
-
- override val checkedListPrefs: PrefsData>
- get() = DataConst.REMOVE_BRANDING_IMAGE_LIST
-
- override fun blockMIUIView(context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref: Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> (view as TextView).text = context.getString(R.string.exception_mode_message, context.getString(if (data as Boolean) R.string.not_chosen else R.string.chosen))
- }
- }
-
- // 排除模式
- val exceptionModePrefs = DataConst.IS_REMOVE_BRANDING_IMAGE_EXCEPTION_MODE
- val exceptionModeBinding = getDataBinding(context.prefs().get(exceptionModePrefs))
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.exception_mode), SwitchView(exceptionModePrefs, dataBindingSend = exceptionModeBinding.bindingSend))
-
- CustomView(
- TextV(
- textSize = 13F,
- colorId = R.color.colorTextRed,
- dataBindingRecv = exceptionModeBinding.getRecv(0)
- ).create(context, null).apply {
- setPadding(0, 0, 0, 0)
- },
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/CustomScope.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/CustomScope.kt
deleted file mode 100644
index 9ba69415..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/CustomScope.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 作用域 - 自定义模块作用域 - 配置应用列表
- */
-object CustomScope : IConfigApps {
- override val titleID: Int
- get() = R.string.custom_scope_title
-
- override val checkedListPrefs: PrefsData>
- get() = DataConst.CUSTOM_SCOPE_LIST
-
- override fun blockMIUIView(context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref: Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> (view as TextView).text = context.getString(R.string.custom_scope_exception_mode_message, context.getString(if (data as Boolean) R.string.will_not else R.string.will_only))
- }
- }
-
- // 排除模式
- val exceptionModePrefs = DataConst.IS_CUSTOM_SCOPE_EXCEPTION_MODE
- val exceptionModeBinding = getDataBinding(context.prefs().get(exceptionModePrefs))
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.exception_mode), SwitchView(exceptionModePrefs, dataBindingSend = exceptionModeBinding.bindingSend))
-
- CustomView(
- TextV(
- textSize = 13F,
- colorId = R.color.colorTextRed,
- dataBindingRecv = exceptionModeBinding.getRecv(0)
- ).create(context, null).apply {
- setPadding(0, 0, 0, 0)
- },
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/DefaultStyle.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/DefaultStyle.kt
deleted file mode 100644
index 9336b14b..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/DefaultStyle.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 图标 - 忽略应用主动谁知的图标 - 配置应用列表
- */
-object DefaultStyle : IConfigApps {
- override val titleID: Int
- get() = R.string.default_style_title
-
- override val checkedListPrefs: PrefsData>
- get() = DataConst.DEFAULT_STYLE_LIST
-
- override fun blockMIUIView(context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref: Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> (view as TextView).text = context.getString(R.string.exception_mode_message, context.getString(if (data as Boolean) R.string.not_chosen else R.string.chosen))
- }
- }
-
- // 排除模式
- val exceptionModePrefs = DataConst.IS_DEFAULT_STYLE_LIST_EXCEPTION_MODE
- val exceptionModeBinding = getDataBinding(context.prefs().get(exceptionModePrefs))
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.exception_mode), SwitchView(exceptionModePrefs, dataBindingSend = exceptionModeBinding.bindingSend))
-
- CustomView(
- TextV(
- textSize = 13F,
- colorId = R.color.colorTextRed,
- dataBindingRecv = exceptionModeBinding.getRecv(0)
- ).create(context, null).apply {
- setPadding(0, 0, 0, 0)
- },
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/ForceShowSplashScreen.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/ForceShowSplashScreen.kt
deleted file mode 100644
index c741a702..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/ForceShowSplashScreen.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 实验功能 - 强制显示遮罩 - 配置应用列表
- */
-object ForceShowSplashScreen : IConfigApps {
- override val titleID: Int
- get() = R.string.force_show_splash_screen_title
- override val checkedListPrefs: PrefsData>
- get() = DataConst.FORCE_SHOW_SPLASH_SCREEN_LIST
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/HideSplashScreenIcon.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/HideSplashScreenIcon.kt
deleted file mode 100644
index 39061526..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/HideSplashScreenIcon.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/** 图标 - 不显示图标 */
-object HideSplashScreenIcon : IConfigApps {
- override val titleID: Int
- get() = R.string.hide_splash_screen_icon_title
-
- override val checkedListPrefs = DataConst.HIDE_SPLASH_SCREEN_ICON_LIST
-
- override fun blockMIUIView(context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref: Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> (view as TextView).text = context.getString(R.string.exception_mode_message, context.getString(if (data as Boolean) R.string.not_chosen else R.string.chosen))
- }
- }
-
- // 排除模式
- val exceptionModePrefs = DataConst.IS_HIDE_SPLASH_SCREEN_ICON_EXCEPTION_MODE
- val exceptionModeBinding = getDataBinding(context.prefs().get(exceptionModePrefs))
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.exception_mode), SwitchView(exceptionModePrefs, dataBindingSend = exceptionModeBinding.bindingSend))
-
- CustomView(
- TextV(
- textSize = 13F,
- colorId = R.color.colorTextRed,
- dataBindingRecv = exceptionModeBinding.getRecv(0)
- ).create(context, null).apply {
- setPadding(0, 0, 0, 0)
- },
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/MinDuration.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/MinDuration.kt
deleted file mode 100644
index 995e2051..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/MinDuration.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.configapps
-
-import android.annotation.SuppressLint
-import android.os.Build
-import android.text.method.DigitsKeyListener
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.MIUIEditText
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.dialog.MIUIDialog
-import com.gswxxn.restoresplashscreen.BuildConfig
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.AdapterConfigBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.`interface`.IConfigApps
-import com.gswxxn.restoresplashscreen.utils.AppInfoHelper
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.highcapable.yukihookapi.hook.factory.current
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 基础设置 - 遮罩最小持续时长
- */
-object MinDuration : IConfigApps {
- override val titleID: Int = R.string.min_duration_title
- override val subSettingHint: Int
- get() = R.string.min_duration_sub_setting_hint
- override val checkedListPrefs: PrefsData>
- get() = DataConst.MIN_DURATION_LIST
- override val configMapPrefs: PrefsData>
- get() = DataConst.MIN_DURATION_CONFIG_MAP
- override val submitMap: Boolean
- get() = true
-
- override fun moreOptions(context: ConfigAppsActivity): ImageView.() -> Unit = {
- visibility = View.GONE
- }
-
- override fun blockMIUIView(context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- TextSummaryArrow(TextSummaryV(textId = R.string.set_default_min_duration) {
- MIUIDialog(context) {
- setTitle(R.string.set_default_min_duration)
- setMessage(R.string.set_min_duration_unit)
- setEditText(context.prefs().get(DataConst.MIN_DURATION).toString(), "", config = {
- it.keyListener = DigitsKeyListener.getInstance("1234567890")
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) it.isLocalePreferredLineHeightForMinimumUsed = false
- })
- setRButton(R.string.button_okay) {
- context.prefs().edit {
- if (getEditText().isNotBlank())
- put(DataConst.MIN_DURATION, getEditText().toInt())
- else
- put(DataConst.MIN_DURATION, 0)
- }
- dismiss()
- }
- setLButton(R.string.button_cancel) { dismiss() }
- }.show()
- })
- Line()
- TitleText(textId = R.string.min_duration_separate_configuration)
- }
-
- override fun adpTextView(
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): TextView.() -> Unit = {
- holder.adpAppTextView.text =
- if (item.config == null) context.getString(R.string.not_set_min_duration)
- else "${item.config} ms"
- }
-
- @SuppressLint("SetTextI18n")
- override fun adpLinearLayout(
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): (View) -> Unit = {
- holder.adpAppCheckBox.isChecked = true
- MIUIDialog(context) {
- setTitle(R.string.set_min_duration)
- setMessage(R.string.set_min_duration_unit)
- setEditText(item.config ?: "", "", config = {
- it.keyListener = DigitsKeyListener.getInstance("1234567890")
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) it.isLocalePreferredLineHeightForMinimumUsed = false
- })
- setRButton(R.string.button_okay) {
- if (getEditText().isEmpty() || getEditText() == "0") {
- context.appInfo.setConfig(item, null)
- holder.adpAppTextView.text = context.getString(R.string.not_set_min_duration)
- context.configMap.remove(item.packageName)
- } else {
- context.appInfo.setConfig(item, getEditText())
- holder.adpAppTextView.text = "${getEditText()} ms"
- context.configMap[item.packageName] = getEditText()
- }
- dismiss()
- }
- setLButton(R.string.button_cancel) { dismiss() }
- }.show()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/IConfigApps.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/IConfigApps.kt
deleted file mode 100644
index 6edd9a35..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/IConfigApps.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.`interface`
-
-import android.content.Intent
-import android.view.View
-import android.widget.CheckBox
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.PopupMenu
-import android.widget.TextView
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.AdapterConfigBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.utils.AppInfoHelper
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 配置应用界面接口
- *
- * @property titleID 标题文本 ID, 之后通过 getString(titleID) 获取标题文本
- * @property subSettingHint 子设置界面提示文本 ID, 之后通过 getString(subSettingHint) 获取子设置界面提示文本
- * @property submitSet 是否需要提交保存 [Set] 集合设置
- * @property submitMap 是否需要提交保存 [Map] 集合设置
- * @property checkedListPrefs 保存 [Set] 集合设置的 [PrefsData]
- * @property configMapPrefs 保存 [Map] 集合设置的 [PrefsData]
- */
-interface IConfigApps {
-
- val titleID: Int
- val subSettingHint: Int
- get() = R.string.save_hint
- val submitSet: Boolean
- get() = true
- val submitMap: Boolean
- get() = false
- val checkedListPrefs: PrefsData>
- get() = DataConst.UNDEFINED_LIST
- val configMapPrefs: PrefsData>
- get() = DataConst.UNDEFINED_LIST
-
- /**
- * 配置界面右上角的菜单栏事件
- *
- * @param context 当前配置界面的实例
- * @return 返回一个 lambda 表达式, 该表达式会在 ImageView 中被调用
- */
- fun moreOptions (context: ConfigAppsActivity): ImageView.() -> Unit = {
- setOnClickListener { it ->
- PopupMenu(context, it).apply {
- setOnMenuItemClickListener { item ->
- when (item.itemId) {
- R.id.select_system_apps -> {
- context.appInfo.getAppInfoList().forEach {
- if (it.isSystemApp) {
- context.appInfo.setChecked(it, true)
- context.checkedList.add(it.packageName)
- }
- }
- context.appInfoFilter = context.appInfo.getAppInfoList()
- context.onRefreshList?.invoke()
- true
- }
- R.id.clear_slection -> {
- context.appInfo.getAppInfoList().forEach {
- context.appInfo.setChecked(it, false)
- context.checkedList.remove(it.packageName)
- }
- context.appInfoFilter = context.appInfo.getAppInfoList()
- context.onRefreshList?.invoke()
- true
- }
- else -> false
- }
- }
- inflate(R.menu.more_options_menu)
- show()
- }
- }
- }
-
- /**
- * 在提示文本和列表之间添加一个自定义的 BlockMIUIView, 用于添加一些自定义的设置
- * @see BlockMIUIItemData
- *
- * @param context 当前配置界面的实例
- */
- fun blockMIUIView (context: ConfigAppsActivity): BlockMIUIItemData.() -> Unit = {
- context.findViewById(R.id.overall_settings).visibility = View.GONE
- }
-
- /**
- * 配置每个列表项目的布局
- *
- * @param context 当前配置界面的实例
- * @param holder 当前列表项的 [AdapterConfigBinding] 实例
- * @param item 当前列表项的 [AppInfoHelper.MyAppInfo] 实例
- * @return 返回一个 lambda 表达式, 该表达式会在 TextView 中被调用
- */
- fun adpTextView (
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): TextView.() -> Unit = { }
-
- /**
- * 配置每个列表项目的复选框
- *
- * @param context 当前配置界面的实例
- * @param holder 当前列表项的 [AdapterConfigBinding] 实例
- * @param item 当前列表项的 [AppInfoHelper.MyAppInfo] 实例
- * @return 返回一个 lambda 表达式, 该表达式会在 CheckBox 中被调用
- */
- fun adpCheckBox (
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): CheckBox.() -> Unit = {
- setOnCheckedChangeListener { _, isChecked ->
- context.appInfo.setChecked(item, isChecked)
- if (isChecked) {
- context.checkedList.add(item.packageName)
- } else {
- context.checkedList.remove(item.packageName)
- }
- }
- isChecked = item.packageName in context.checkedList
- }
-
- /**
- * 配置每个列表项目的线性布局
- *
- * @param context 当前配置界面的实例
- * @param holder 当前列表项的 [AdapterConfigBinding] 实例
- * @param item 当前列表项的 [AppInfoHelper.MyAppInfo] 实例
- * @return 返回一个 lambda 表达式, 该表达式会在 LinearLayout 中被调用
- */
- fun adpLinearLayout (
- context: ConfigAppsActivity,
- holder: AdapterConfigBinding,
- item: AppInfoHelper.MyAppInfo
- ): ((View) -> Unit) = {
- holder.adpAppCheckBox.isChecked = !holder.adpAppCheckBox.isChecked
- }
-
- /**
- * 重写以处理 onActivityResult
- *
- * @param context 当前子设置界面的实例
- * @param requestCode 请求码
- * @param resultCode 结果码
- * @param data 返回的 Intent
- *
- * @see SubSettings.onActivityResult
- */
- fun onActivityResult(context: ConfigAppsActivity, requestCode: Int, resultCode: Int, data: Intent?) { }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/ISubSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/ISubSettings.kt
deleted file mode 100644
index 6cb5b2a8..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/ISubSettings.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.`interface`
-
-import android.content.Intent
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-
-/**
- * 创建子设置界面的接口, 需要在 [SubSettings.onCreate] 中注册
- *
- * @property titleID 标题文本 ID, 之后通过 getString(titleID) 获取标题文本
- * @property demoImageID 演示图片 ID, 之后通过 getDrawable(demoImageID) 获取字节面上方演示图片
- */
-interface ISubSettings {
- val titleID: Int
- val demoImageID: Int?
-
- /**
- * 创建子设置界面
- *
- * @param context 当前子设置界面的实例
- * @param binding 当前子设置界面的 DataBinding
- * @return 返回一个 lambda 表达式, 该表达式会在 BlockMIUIItemData 中被调用
- */
- fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit
-
- /**
- * 重写以处理 onActivityResult
- *
- * @param context 当前子设置界面的实例
- * @param requestCode 请求码
- * @param resultCode 结果码
- * @param data 返回的 Intent
- *
- * @see SubSettings.onActivityResult
- */
- fun onActivityResult(context: SubSettings, requestCode: Int, resultCode: Int, data: Intent?) { }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt
new file mode 100644
index 00000000..0ce4784a
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt
@@ -0,0 +1,291 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.widget.Toast
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.core.graphics.toColorInt
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.BuildConfig
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.IconSize
+import dev.lackluster.hyperx.compose.base.ImageIcon
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.TextPreference
+import top.yukonga.miuix.kmp.basic.Card
+import top.yukonga.miuix.kmp.basic.Text
+import top.yukonga.miuix.kmp.extra.SuperArrow
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import kotlin.math.min
+
+/**
+ * 关于页面
+ */
+@Composable
+fun AboutPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ val referencesList = listOf(
+ Reference("MIUINativeNotifyIcon", "fankes","AGPL-3.0","https://github.com/fankes/MIUINativeNotifyIcon"),
+ Reference("Hide-My-Applist", "Dr-TSNG", "AGPL-3.0", "https://github.com/Dr-TSNG/Hide-My-Applist"),
+ Reference("YukiHookAPI", "fankes", "Apache-2.0", "https://github.com/fankes/YukiHookAPI"),
+ Reference("MiuiHomeR", "YuKongA", "GPL-3.0", "https://github.com/qqlittleice/MiuiHome_R"),
+ Reference("BlockMIUI", "577fkj", "LGPL-2.1", "https://github.com/Block-Network/blockmiui"),
+ )
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.about),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ var count = 0
+ var lastClickTime: Long = 0
+ AdaptiveHeaderCard(
+ colorCardContent = {
+ Box(
+ modifier = Modifier.clickable {
+ val now = System.currentTimeMillis()
+ if (now - lastClickTime < 500)
+ count++
+ else
+ count = 1
+ lastClickTime = now
+ if (count != 5) return@clickable
+ count = 0
+ if (!SafeSP.getBoolean(DataConst.ENABLE_DEV_SETTINGS.key)) {
+ MainActivity.devMode.value = true
+ SafeSP.putAny(DataConst.ENABLE_DEV_SETTINGS.key, true)
+ HyperXActivity.context.let {
+ Toast.makeText(
+ it,
+ it.getString(R.string.enable_dev_settings),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ } else {
+ HyperXActivity.context.let {
+ Toast.makeText(
+ it,
+ it.getString(R.string.enable_dev_settings),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ ) {
+ val offset: Offset
+ val blurRadius: Float
+ with(LocalDensity.current) {
+ offset = Offset(0f, 3.dp.toPx())
+ blurRadius = 6.dp.toPx()
+ }
+ Image(
+ modifier = Modifier.fillMaxSize(),
+ painter = painterResource(R.drawable.ic_launcher_foreground),
+ contentDescription = null,
+ colorFilter = ColorFilter.tint(Color.Black.copy(alpha = 0.08f)),
+ alignment = Alignment.CenterStart,
+ contentScale = ContentScale.Fit,
+ )
+ Column(
+ modifier = Modifier.fillMaxWidth().align(Alignment.Center),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ Text(
+ text = stringResource(R.string.app_name),
+ color = Color.White.copy(alpha = 0.7f),
+ style = TextStyle(
+ color = Color.White.copy(alpha = 0.7f),
+ fontSize = 30.sp,
+ fontWeight = FontWeight.SemiBold,
+ shadow = Shadow(
+ color = Color.Black.copy(alpha = 0.1f),
+ offset = offset,
+ blurRadius = blurRadius
+ )
+ )
+ )
+ Spacer(modifier = Modifier.heightIn(min = 12.dp))
+ Text(
+ text = stringResource(R.string.version, BuildConfig.VERSION_NAME),
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = Color.White.copy(alpha = 0.7f),
+ )
+ }
+ }
+ },
+ infoCardContent = {
+ TextPreference(
+ icon = ImageIcon(
+ iconRes = R.mipmap.img_developer,
+ iconSize = IconSize.App,
+ cornerRadius = 40.dp
+ ),
+ title = stringResource(R.string.developer_milu),
+ summary = stringResource(R.string.developer)
+ ) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.follow_me), Toast.LENGTH_SHORT).show()
+ try {
+ it.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("coolmarket://u/1189245")))
+ } catch (e: Exception) {
+ it.openUrl("https://www.coolapk.com/u/1189245")
+ }
+ }
+ }
+ TextPreference(
+ icon = ImageIcon(
+ iconRes = R.drawable.img_github,
+ iconSize = IconSize.App
+ ),
+ title = "GitHub",
+ summary = stringResource(R.string.open_source_repo)
+ ) {
+ HyperXActivity.context.openUrl("https://github.com/GSWXXN/RestoreSplashScreen")
+ }
+ SuperArrow(
+ title = "",
+ leftAction = {
+ Image(
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .height(40.dp),
+ painter = painterResource(R.drawable.img_iconfont),
+ contentDescription = null
+ )
+ },
+ insideMargin = PaddingValues(16.dp),
+ onClick = {
+ HyperXActivity.context.openUrl("https://www.iconfont.cn")
+ }
+ )
+ }
+ )
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.open_source_license),
+ last = true
+ ) {
+ for (project in referencesList) {
+ TextPreference(
+ title = "${project.author}/${project.name}",
+ summary = project.license
+ ) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.thanks_to, project.author), Toast.LENGTH_SHORT).show()
+ it.openUrl(project.link)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+fun Context.openUrl(url: String) {
+ try {
+ val uri = Uri.parse(url)
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ this.startActivity(intent)
+ } catch (_: Exception) { }
+}
+
+@Composable
+private fun AdaptiveHeaderCard(
+ colorCardContent: @Composable () -> Unit,
+ infoCardContent: @Composable () -> Unit
+) {
+ Layout(
+ content = {
+ Card(
+ color = Color("#21A2EE".toColorInt())
+ ) {
+ colorCardContent()
+ }
+ Card {
+ infoCardContent()
+ }
+ }
+ ) { measurables, constraints ->
+ if (measurables.size != 2) {
+ layout(0, 0) { }
+ }
+ if (constraints.maxWidth >= 768.dp.roundToPx()) {
+ val cardWidthPx = (constraints.maxWidth - 48.dp.roundToPx()) / 2
+ val infoCard = measurables[1].measure(constraints.copy(
+ minWidth = cardWidthPx, maxWidth = cardWidthPx
+ ))
+ val colorCard = measurables[0].measure(constraints.copy(
+ minWidth = cardWidthPx, maxWidth = cardWidthPx,
+ minHeight = infoCard.height, maxHeight = infoCard.height
+ ))
+ val layoutHeight = infoCard.height + 18.dp.roundToPx()
+ layout(constraints.maxWidth, layoutHeight) {
+ colorCard.place(12.dp.roundToPx(), 12.dp.roundToPx())
+ infoCard.place(constraints.maxWidth - cardWidthPx - 12.dp.roundToPx(), 12.dp.roundToPx())
+ }
+ } else {
+ val cardWidthPx = constraints.maxWidth - 24.dp.roundToPx()
+ val infoCard = measurables[1].measure(constraints.copy(
+ minWidth = cardWidthPx, maxWidth = cardWidthPx
+ ))
+ val colorCardHeight = min(infoCard.height, cardWidthPx / 2)
+ val colorCard = measurables[0].measure(constraints.copy(
+ minWidth = cardWidthPx, maxWidth = cardWidthPx,
+ minHeight = colorCardHeight, maxHeight = colorCardHeight
+ ))
+ val layoutHeight = colorCard.height + infoCard.height + 30.dp.roundToPx()
+ layout(constraints.maxWidth, layoutHeight) {
+ colorCard.place(12.dp.roundToPx(), 12.dp.roundToPx())
+ infoCard.place(12.dp.roundToPx(), colorCard.height + 24.dp.roundToPx())
+ }
+ }
+ }
+}
+
+data class Reference(
+ val name: String,
+ val author:String,
+ val license: String,
+ val link: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt
new file mode 100644
index 00000000..3c757ec1
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt
@@ -0,0 +1,171 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.ColorPickerPageArgs
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import com.gswxxn.restoresplashscreen.utils.YukiHelper.isMIUI
+import com.highcapable.yukihookapi.hook.factory.hasClass
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.DropDownEntry
+import dev.lackluster.hyperx.compose.preference.DropDownPreference
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+
+/**
+ * 背景 界面
+ */
+@Composable
+fun BackgroundPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var changeColorType by remember { mutableIntStateOf(SafeSP.getInt(DataConst.CHANG_BG_COLOR_TYPE.key)) }
+ var colorMode by remember { mutableIntStateOf(SafeSP.getInt(DataConst.BG_COLOR_MODE.key)) }
+ val ignoreDarkMode = remember { mutableStateOf(SafeSP.getBoolean(DataConst.IGNORE_DARK_MODE.key)) }
+ var ignoreDarkModeEnabled by remember { mutableStateOf(true) }
+
+ val changeColorTypeItems = listOf(
+ DropDownEntry(stringResource(R.string.not_change_bg_color)),
+ DropDownEntry(stringResource(R.string.from_icon)),
+ DropDownEntry(stringResource(R.string.from_monet)),
+ DropDownEntry(stringResource(R.string.from_custom))
+ )
+ val colorModeItems = listOf(
+ DropDownEntry(stringResource(R.string.light_color)),
+ DropDownEntry(stringResource(R.string.dark_color)),
+ DropDownEntry(stringResource(R.string.follow_system))
+ )
+
+ if (isMIUI && colorMode == 2 && (changeColorType == 1 || changeColorType == 2)) {
+ SafeSP.putAny(DataConst.IGNORE_DARK_MODE.key, true)
+ ignoreDarkMode.value = true
+ ignoreDarkModeEnabled = false
+ } else {
+ ignoreDarkModeEnabled = true
+ }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.background_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_background,
+ title = "BACKGROUND"
+ )
+ }
+ item {
+ PreferenceGroup(
+ last = !isMIUI
+ ) {
+ // 替换背景颜色
+ DropDownPreference(
+ title = stringResource(R.string.change_bg_color),
+ entries = changeColorTypeItems,
+ key = DataConst.CHANG_BG_COLOR_TYPE.key
+ ) {
+ changeColorType = it
+ }
+ AnimatedVisibility(
+ changeColorType == 1 || changeColorType == 2
+ ) {
+ // 颜色模式
+ DropDownPreference(
+ title = stringResource(R.string.color_mode),
+ summary = if (isMIUI) stringResource(R.string.color_mode_tips) else null,
+ entries = colorModeItems,
+ key = DataConst.BG_COLOR_MODE.key
+ ) {
+ colorMode = it
+ }
+ }
+ AnimatedVisibility(
+ changeColorType == 3
+ ) {
+ // 自定义背景颜色
+ TextPreference(
+ title = stringResource(R.string.set_custom_bg_color),
+ summary = stringResource(R.string.set_custom_bg_color_tips)
+ ) {
+ navController.navigateTo(
+ "${Pages.CONFIG_COLOR_PICKER}?" +
+ "${ColorPickerPageArgs.PACKAGE_NAME}=${""}," +
+ "${ColorPickerPageArgs.KEY_LIGHT}=${DataConst.OVERALL_BG_COLOR.key}," +
+ "${ColorPickerPageArgs.KEY_DARK}=${DataConst.OVERALL_BG_COLOR_NIGHT.key}"
+ )
+ }
+ }
+ AnimatedVisibility(
+ changeColorType != 0
+ ) {
+ Column {
+ // 如果应用主动设置了背景颜色则不替换
+ SwitchPreference(
+ title = stringResource(R.string.skip_app_with_bg_color),
+ key = DataConst.SKIP_APP_WITH_BG_COLOR.key,
+ defValue = DataConst.SKIP_APP_WITH_BG_COLOR.value
+ )
+ // 配置应用列表
+ TextPreference(
+ title = stringResource(R.string.change_bg_color_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_BACKGROUND_EXCEPT)
+ }
+ }
+ }
+ // 单独配置应用背景颜色
+ TextPreference(
+ title = stringResource(R.string.configure_bg_colors_individually)
+ ) {
+ navController.navigateTo(Pages.CONFIG_BACKGROUND_INDIVIDUALLY)
+ }
+ }
+ }
+ item {
+ if(isMIUI) {
+ Column {
+ PreferenceGroup(
+ last = true
+ ) {
+ // 忽略深色模式
+ SwitchPreference(
+ title = stringResource(R.string.ignore_dark_mode),
+ summary = stringResource(R.string.ignore_dark_mode_tips),
+ key = DataConst.IGNORE_DARK_MODE.key,
+ checked = ignoreDarkMode,
+ enabled = ignoreDarkModeEnabled
+ )
+ if("android.app.TaskSnapshotHelperImpl".hasClass()) {
+ // 移除截图背景
+ SwitchPreference(
+ title = stringResource(R.string.remove_bg_drawable),
+ summary = stringResource(R.string.remove_bg_drawable_tips),
+ key = DataConst.REMOVE_BG_DRAWABLE.key
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt
new file mode 100644
index 00000000..a58839ff
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt
@@ -0,0 +1,148 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.net.Uri
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.BuildConfig
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import com.gswxxn.restoresplashscreen.utils.BackupUtils
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+import java.time.LocalDateTime
+
+/**
+ * 基础设置 界面
+ */
+@Composable
+fun BasicPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var enableLog by remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_LOG.key, DataConst.ENABLE_LOG.value)) }
+ LaunchedEffect(Unit) {
+ if (enableLog && (System.currentTimeMillis() - SafeSP.getLong(DataConst.ENABLE_LOG_TIMESTAMP.key, DataConst.ENABLE_LOG_TIMESTAMP.value)) > 86400000) {
+ SafeSP.putAny(DataConst.ENABLE_LOG.key, false)
+ enableLog = false
+ }
+ }
+
+ val backupUri = remember { mutableStateOf(null) }
+ val backupLauncher = rememberLauncherForActivityResult(
+ ActivityResultContracts.CreateDocument("application/json")
+ ) {
+ backupUri.value = it
+ }
+ backupUri.value?.let {
+ BackupUtils.handleCreateDocument(HyperXActivity.context, it)
+ }
+ val restoreUri = remember { mutableStateOf(null) }
+ val restoreLauncher = rememberLauncherForActivityResult(
+ ActivityResultContracts.OpenDocument()
+ ) {
+ restoreUri.value = it
+ }
+ restoreUri.value?.let { uri ->
+ BackupUtils.handleReadDocument(HyperXActivity.context, uri)
+ }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.basic_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_basic,
+ title = "BASIC"
+ )
+ }
+ item {
+ PreferenceGroup {
+ // 启用日志
+ SwitchPreference(
+ title = stringResource(R.string.enable_log),
+ summary = stringResource(R.string.enable_log_tips),
+ key = DataConst.ENABLE_LOG.key,
+ defValue = enableLog
+ ) {
+ enableLog = it
+ if (it) {
+ SafeSP.putAny(DataConst.ENABLE_LOG_TIMESTAMP.key, System.currentTimeMillis())
+ }
+ }
+ // 隐藏桌面图标
+ SwitchPreference(
+ title = stringResource(R.string.hide_icon),
+ key = DataConst.ENABLE_HIDE_ICON.key
+ ) {
+ HyperXActivity.context.let { context ->
+ context.packageManager.setComponentEnabledSetting(
+ ComponentName(context, "${BuildConfig.APPLICATION_ID}.Home"),
+ if (it)
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ else
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+ }
+ // 模糊效果
+ SwitchPreference(
+ title = stringResource(R.string.blur),
+ key = DataConst.BLUR.key,
+ defValue = MainActivity.blurEnabled.value
+ ) {
+ MainActivity.blurEnabled.value = it
+ }
+ // 自适应布局
+ SwitchPreference(
+ title = stringResource(R.string.split_view),
+ summary = stringResource(R.string.split_view_tips),
+ key = DataConst.SPLIT_VIEW.key,
+ defValue = MainActivity.splitEnabled.value
+ ) {
+ MainActivity.splitEnabled.value = it
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.backup_restore_title),
+ last = true
+ ) {
+ // 备份设置项
+ TextPreference(
+ title = stringResource(R.string.backup)
+ ) {
+ backupLauncher.launch("RestoreSplashScreen_${LocalDateTime.now()}.json")
+ }
+ // 恢复设置项
+ TextPreference(
+ title = stringResource(R.string.restore)
+ ) {
+ restoreLauncher.launch(arrayOf("application/json"))
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt
new file mode 100644
index 00000000..6576b0ee
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt
@@ -0,0 +1,80 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.widget.Toast
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+
+/**
+ * 底部 界面
+ */
+@Composable
+fun BottomPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var removeBrandingImage by remember { mutableStateOf(SafeSP.getBoolean(DataConst.REMOVE_BRANDING_IMAGE.key)) }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.bottom_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_branding,
+ title = "BRANDING\nIMAGE",
+ maxLines = 2
+ )
+ }
+ item {
+ PreferenceGroup(
+ last = true
+ ) {
+ // 移除底部图片
+ SwitchPreference(
+ title = stringResource(R.string.remove_branding_image),
+ summary = stringResource(R.string.remove_branding_image_tips),
+ key = DataConst.REMOVE_BRANDING_IMAGE.key
+ ) { newValue ->
+ removeBrandingImage = newValue
+ if (newValue) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.custom_scope_message), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ AnimatedVisibility(
+ removeBrandingImage
+ ) {
+ // 配置移除列表
+ TextPreference(
+ title = stringResource(R.string.remove_branding_image_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_REMOVE_BRANDING)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt
new file mode 100644
index 00000000..7ae3002b
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt
@@ -0,0 +1,171 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.utils.YukiHelper.getHookInfo
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.preference.EditTextDataType
+import dev.lackluster.hyperx.compose.preference.EditTextPreference
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SeekBarPreference
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import top.yukonga.miuix.kmp.basic.Text
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import kotlin.math.roundToInt
+
+/**
+ * 开发者选项
+ */
+@Composable
+fun DevPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ val hookInfos = remember { mutableStateListOf() }
+
+ LaunchedEffect(Unit) {
+ hookInfos.clear()
+ HyperXActivity.context.getHookInfo("com.android.systemui") { hookInfo ->
+ hookInfo.entries.sortedWith(
+ compareBy({ !it.value.isAbnormal }, {it.key})
+ ).forEach { (key, hookManager) ->
+ hookInfos.add(
+ HookInfo(
+ title = key,
+ msg = "createCondition: ${hookManager.createCondition}\n" +
+ "isMemberFound: ${hookManager.isMemberFound}\n" +
+ "hasBeforeHooks: ${hookManager.hasBeforeHooks}\n" +
+ "isBeforeHookExecuted: ${hookManager.isBeforeHookExecuted}\n" +
+ "hasAfterHooks: ${hookManager.hasAfterHooks}\n" +
+ "isAfterHookExecuted: ${hookManager.isAfterHookExecuted}\n" +
+ "hasReplaceHook: ${hookManager.hasReplaceHook}\n" +
+ "isReplaceHookExecuted: ${hookManager.isReplaceHookExecuted}",
+ error = hookManager.isAbnormal
+ )
+ )
+ }
+ }
+ }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.dev_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ PreferenceGroup(
+ first = true
+ ) {
+ SwitchPreference(
+ title = stringResource(R.string.dev_settings),
+ key = DataConst.ENABLE_DEV_SETTINGS.key,
+ defValue = MainActivity.devMode.value
+ ) {
+ MainActivity.devMode.value = it
+ }
+ EditTextPreference(
+ title = stringResource(R.string.dev_blur_tint_alpha_light),
+ key = DataConst.HAZE_TINT_ALPHA_LIGHT.key,
+ defValue = (MainActivity.blurTintAlphaLight.floatValue * 100).roundToInt().coerceIn(0..100),
+ dataType = EditTextDataType.INT,
+ dialogMessage = stringResource(R.string.dev_blur_tint_alpha_tips),
+ isValueValid = {
+ (it as? Int) in (0..100)
+ }
+ ) { _, newValue ->
+ (newValue as? Int)?.let {
+ MainActivity.blurTintAlphaLight.floatValue = it / 100f
+ }
+ }
+ EditTextPreference(
+ title = stringResource(R.string.dev_blur_tint_alpha_dark),
+ key = DataConst.HAZE_TINT_ALPHA_DARK.key,
+ defValue = (MainActivity.blurTintAlphaDark.floatValue * 100).roundToInt().coerceIn(0..100),
+ dataType = EditTextDataType.INT,
+ dialogMessage = stringResource(R.string.dev_blur_tint_alpha_tips),
+ isValueValid = {
+ (it as? Int) in (0..100)
+ }
+ ) { _, newValue ->
+ (newValue as? Int)?.let {
+ MainActivity.blurTintAlphaDark.floatValue = it / 100f
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.icon_settings)
+ ) {
+ SeekBarPreference(
+ title = stringResource(R.string.dev_icon_round_corner_rate),
+ key = DataConst.DEV_ICON_ROUND_CORNER_RATE.key,
+ defValue = DataConst.DEV_ICON_ROUND_CORNER_RATE.value,
+ min = 0,
+ max = 50,
+ format = "%d%% / 50%%"
+ )
+ }
+ }
+ item {
+ PreferenceGroup(
+ title = stringResource(R.string.hook_info),
+ last = true
+ ) {
+ if (hookInfos.size == 0) {
+ Column(
+ modifier = Modifier.padding(16.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.dev_hook_info_empty),
+ fontSize = MiuixTheme.textStyles.headline1.fontSize,
+ fontWeight = FontWeight.Medium,
+ color = MiuixTheme.colorScheme.onSurface
+ )
+ }
+ } else {
+ hookInfos.forEach { hookInfo ->
+ Column(
+ modifier = Modifier.padding(16.dp)
+ ) {
+ Text(
+ text = hookInfo.title,
+ fontSize = MiuixTheme.textStyles.headline1.fontSize,
+ fontWeight = FontWeight.Medium,
+ color = if (hookInfo.error) Color.Red else MiuixTheme.colorScheme.onSurface
+ )
+ Text(
+ text = hookInfo.msg,
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = MiuixTheme.colorScheme.onSurfaceVariantSummary
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+data class HookInfo(
+ val title: String,
+ val msg: String,
+ val error: Boolean
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt
new file mode 100644
index 00000000..93def098
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt
@@ -0,0 +1,131 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.widget.Toast
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+
+/**
+ * 显示设置 界面
+ */
+@Composable
+fun DisplayPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var forceShowSplash by remember { mutableStateOf(SafeSP.getBoolean(DataConst.FORCE_SHOW_SPLASH_SCREEN.key)) }
+ var forceEnableSplash by remember { mutableStateOf(SafeSP.getBoolean(DataConst.FORCE_ENABLE_SPLASH_SCREEN.key)) }
+ val hotStartCompatible = remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_HOT_START_COMPATIBLE.key)) }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.display_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_display,
+ title = "DISPLAY"
+ )
+ }
+ item {
+ // 遮罩最小持续时间
+ PreferenceGroup {
+ TextPreference(
+ title = stringResource(R.string.min_duration),
+ summary = stringResource(R.string.min_duration_tips)
+ ) {
+ navController.navigateTo(Pages.CONFIG_MIN_DURATION)
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ // 强制显示遮罩
+ SwitchPreference(
+ title = stringResource(R.string.force_show_splash_screen),
+ summary = stringResource(R.string.force_show_splash_screen_tips),
+ key = DataConst.FORCE_SHOW_SPLASH_SCREEN.key
+ ) { newValue ->
+ forceShowSplash = newValue
+ if (newValue) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.custom_scope_message), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ AnimatedVisibility(
+ forceShowSplash
+ ) {
+ Column {
+ // 配置应用列表
+ TextPreference(
+ title = stringResource(R.string.force_show_splash_screen_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_FORCE_SHOW_SPLASH)
+ }
+ // 减少不必要的启动遮罩
+ SwitchPreference(
+ title = stringResource(R.string.reduce_splash_screen),
+ summary = stringResource(R.string.reduce_splash_screen_tips),
+ key = DataConst.REDUCE_SPLASH_SCREEN.key
+ )
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ last = true
+ ) {
+ // 强制开启启动遮罩
+ SwitchPreference(
+ title = stringResource(R.string.force_enable_splash_screen),
+ summary = stringResource(R.string.force_enable_splash_screen_tips),
+ key = DataConst.FORCE_ENABLE_SPLASH_SCREEN.key
+ ) {
+ forceEnableSplash = it
+ if (!it) {
+ hotStartCompatible.value = false
+ SafeSP.putAny(DataConst.ENABLE_HOT_START_COMPATIBLE.key, false)
+ }
+ }
+ // 将启动遮罩适用于热启动
+ SwitchPreference(
+ title = stringResource(R.string.hot_start_compatible),
+ summary = stringResource(R.string.hot_start_compatible_tips),
+ key = DataConst.ENABLE_HOT_START_COMPATIBLE.key,
+ checked = hotStartCompatible,
+ enabled = forceEnableSplash
+ )
+ // 彻底关闭 Splash Screen
+ SwitchPreference(
+ title = stringResource(R.string.disable_splash_screen),
+ summary = stringResource(R.string.disable_splash_screen_tips),
+ key = DataConst.DISABLE_SPLASH_SCREEN.key
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt
new file mode 100644
index 00000000..31a98f32
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt
@@ -0,0 +1,205 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.widget.Toast
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import com.gswxxn.restoresplashscreen.utils.IconPackManager
+import com.gswxxn.restoresplashscreen.utils.YukiHelper
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.DropDownEntry
+import dev.lackluster.hyperx.compose.preference.DropDownPreference
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+
+/**
+ * 图标 界面
+ */
+@Composable
+fun IconPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var shrinkIcon by remember { mutableIntStateOf(SafeSP.getInt(DataConst.SHRINK_ICON.key)) }
+ var selectedIconPack by remember { mutableIntStateOf(0) }
+ var ignoreAppIcon by remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_DEFAULT_STYLE.key)) }
+ var hideSplashIcon by remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_HIDE_SPLASH_SCREEN_ICON.key)) }
+
+ val shrinkIconItems = listOf(
+ DropDownEntry(stringResource(R.string.not_shrink_icon)),
+ DropDownEntry(stringResource(R.string.shrink_low_resolution_icon)),
+ DropDownEntry(stringResource(R.string.shrink_all_icon))
+ )
+ val availableIconPackItems = remember { mutableStateListOf(
+ DropDownEntry(title = "None", summary = "None")
+ ) }
+
+ LaunchedEffect(Unit) {
+ val availableIconPacks = IconPackManager(HyperXActivity.context).getAvailableIconPacks()
+ val tempIconPackItems = mutableListOf()
+ for (iconPack in availableIconPacks) {
+ if (iconPack.key == "None") continue
+ tempIconPackItems.add(
+ DropDownEntry(
+ title = iconPack.value,
+ summary = iconPack.key
+ )
+ )
+ }
+ availableIconPackItems.addAll(tempIconPackItems)
+ val selectedPkgName = SafeSP.getString(DataConst.ICON_PACK_PACKAGE_NAME.key, DataConst.ICON_PACK_PACKAGE_NAME.value)
+ availableIconPackItems.indexOfFirst {
+ it.summary == selectedPkgName
+ }.let {
+ if (it != -1) {
+ selectedIconPack = it
+ } else {
+ selectedIconPack = 0
+ SafeSP.putAny(DataConst.ICON_PACK_PACKAGE_NAME.key, "None")
+ HyperXActivity.context.let { context ->
+ Toast.makeText(
+ context,
+ context.getString(R.string.icon_pack_is_removed),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.icon_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_icon,
+ title = "ICON"
+ )
+ }
+ item {
+ PreferenceGroup {
+ // 绘制图标圆角
+ SwitchPreference(
+ title = stringResource(R.string.draw_round_corner),
+ key = DataConst.ENABLE_DRAW_ROUND_CORNER.key
+ )
+ // 缩小图标
+ DropDownPreference(
+ title = stringResource(R.string.shrink_icon),
+ entries = shrinkIconItems,
+ key = DataConst.SHRINK_ICON.key
+ ) {
+ shrinkIcon = it
+ }
+ AnimatedVisibility(
+ shrinkIcon != 0
+ ) {
+ // 为缩小的图标添加模糊背景
+ SwitchPreference(
+ title = stringResource(R.string.add_icon_blur_bg),
+ key = DataConst.ENABLE_ADD_ICON_BLUR_BG.key
+ )
+ }
+ // 替换图标获取方式
+ SwitchPreference(
+ title = stringResource(R.string.replace_icon),
+ summary = stringResource(R.string.replace_icon_tips),
+ key = DataConst.ENABLE_REPLACE_ICON.key
+ )
+ if (YukiHelper.atLeastMIUI14) {
+ // 使用 MIUI 大图标
+ SwitchPreference(
+ title = stringResource(R.string.use_miui_large_icon),
+ key = DataConst.ENABLE_USE_MIUI_LARGE_ICON.key
+ )
+ }
+ // 使用图标包
+ DropDownPreference(
+ title = stringResource(R.string.use_icon_pack),
+ entries = availableIconPackItems,
+ defValue = selectedIconPack
+ ) {
+ SafeSP.putAny(DataConst.ICON_PACK_PACKAGE_NAME.key, availableIconPackItems[it].summary ?: "None")
+ selectedIconPack = it
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ // 忽略应用主动设置的图标
+ SwitchPreference(
+ title = stringResource(R.string.default_style),
+ summary = stringResource(R.string.default_style_tips),
+ key = DataConst.ENABLE_DEFAULT_STYLE.key
+ ) { newValue ->
+ ignoreAppIcon = newValue
+ if (newValue) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.custom_scope_message), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ AnimatedVisibility(
+ ignoreAppIcon
+ ) {
+ // 配置应用列表
+ TextPreference(
+ title = stringResource(R.string.default_style_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_IGNORE_APP_ICON)
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup(
+ last = true
+ ) {
+ // 不显示图标
+ SwitchPreference(
+ title = stringResource(R.string.hide_splash_screen_icon),
+ key = DataConst.ENABLE_HIDE_SPLASH_SCREEN_ICON.key
+ ) { newValue ->
+ hideSplashIcon = newValue
+ if (newValue) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.custom_scope_message), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ AnimatedVisibility(
+ hideSplashIcon
+ ) {
+ // 配置应用列表
+ TextPreference(
+ title = stringResource(R.string.default_style_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_HIDE_SPLASH_ICON)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt
new file mode 100644
index 00000000..4a94c5fb
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt
@@ -0,0 +1,344 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.content.Intent
+import android.net.Uri
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.platform.LocalHapticFeedback
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.BuildConfig
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.MainActivity.Companion.androidRestartNeeded
+import com.gswxxn.restoresplashscreen.ui.MainActivity.Companion.moduleActive
+import com.gswxxn.restoresplashscreen.ui.MainActivity.Companion.systemUIRestartNeeded
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.execShell
+import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
+import com.highcapable.yukihookapi.YukiHookAPI.Status.Executor
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.base.ImageIcon
+import dev.lackluster.hyperx.compose.navigation.navigateWithPopup
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.TextPreference
+import top.yukonga.miuix.kmp.basic.ButtonDefaults
+import top.yukonga.miuix.kmp.basic.Card
+import top.yukonga.miuix.kmp.basic.Icon
+import top.yukonga.miuix.kmp.basic.IconButton
+import top.yukonga.miuix.kmp.basic.ListPopup
+import top.yukonga.miuix.kmp.basic.ListPopupColumn
+import top.yukonga.miuix.kmp.basic.ListPopupDefaults
+import top.yukonga.miuix.kmp.basic.PopupPositionProvider
+import top.yukonga.miuix.kmp.basic.Text
+import top.yukonga.miuix.kmp.basic.TextButton
+import top.yukonga.miuix.kmp.extra.DropdownImpl
+import top.yukonga.miuix.kmp.extra.SuperDialog
+import top.yukonga.miuix.kmp.icon.MiuixIcons
+import top.yukonga.miuix.kmp.icon.icons.ImmersionMore
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog
+import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissPopup
+
+@Composable
+fun MainPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ val isTopPopupExpanded = remember { mutableStateOf(false) }
+ val showTopPopup = remember { mutableStateOf(false) }
+ val dialogRestartVisibility = remember { mutableStateOf(false) }
+
+ val cardBackground = Color(HyperXActivity.context.getColor(
+ when {
+ moduleActive.value && (androidRestartNeeded.value == true || systemUIRestartNeeded.value) ->
+ R.color.yellow
+ moduleActive.value ->
+ R.color.green
+ else ->
+ R.color.gray
+ }
+ ))
+ val stateIconRes = if (moduleActive.value && androidRestartNeeded.value != true && !systemUIRestartNeeded.value)
+ R.drawable.ic_success
+ else
+ R.drawable.ic_warn
+ val stateText = when {
+ moduleActive.value && androidRestartNeeded.value == true ->
+ stringResource(R.string.module_is_updated, stringResource(R.string.phone))
+ moduleActive.value && systemUIRestartNeeded.value->
+ stringResource(R.string.module_is_updated, stringResource(R.string.system_ui))
+ moduleActive.value ->
+ stringResource(R.string.module_is_active)
+ else ->
+ stringResource(R.string.module_is_not_active)
+ }
+
+ val contextMenuItems = listOf(
+ stringResource(R.string.restart),
+ stringResource(R.string.about)
+ )
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.app_name),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode,
+ navigationIcon = {},
+ actions = { padding ->
+ val hapticFeedback = LocalHapticFeedback.current
+ if (isTopPopupExpanded.value) {
+ ListPopup(
+ show = showTopPopup,
+ popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
+ alignment = PopupPositionProvider.Align.TopRight,
+ onDismissRequest = {
+ isTopPopupExpanded.value = false
+ }
+ ) {
+ ListPopupColumn {
+ contextMenuItems.forEachIndexed { index, string ->
+ DropdownImpl(
+ text = string,
+ optionSize = contextMenuItems.size,
+ isSelected = false,
+ onSelectedIndexChange = {
+ when(it) {
+ 0 -> {
+ dialogRestartVisibility.value = true
+ }
+ 1 -> {
+ navController.navigateWithPopup(Pages.ABOUT)
+ }
+ }
+ dismissPopup(showTopPopup)
+ isTopPopupExpanded.value = false
+ },
+ index = index
+ )
+ }
+ }
+ }
+ showTopPopup.value = true
+ }
+ IconButton(
+ modifier = Modifier.padding(padding).padding(end = 21.dp).size(40.dp),
+ onClick = {
+ isTopPopupExpanded.value = true
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
+ }
+ ) {
+ Icon(
+ imageVector = MiuixIcons.ImmersionMore,
+ contentDescription = "Menu"
+ )
+ }
+ }
+ ) {
+ item {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 12.dp)
+ .padding(bottom = 6.dp, top = 12.dp),
+ color = cardBackground
+ ) {
+ Row(
+ modifier = Modifier.clickable {
+ try {
+ execShell("am broadcast -a android.telephony.action.SECRET_CODE -d android_secret_code://5776733 android")
+ } catch (_: Exception) {
+ HyperXActivity.context.let {
+ it.toast(it.getString(R.string.no_root))
+ }
+ }
+ },
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Image(
+ modifier = Modifier.padding(16.dp).size(28.dp),
+ painter = painterResource(stateIconRes),
+ colorFilter = ColorFilter.tint(Color.White),
+ contentDescription = null
+ )
+ Column(
+ modifier = Modifier.fillMaxWidth().padding(end = 16.dp)
+ ) {
+ Text(
+ modifier = Modifier.padding(top = 16.dp),
+ text = stateText,
+ fontSize = MiuixTheme.textStyles.title3.fontSize,
+ color = Color.White
+ )
+ Text(
+ modifier = Modifier.padding(vertical = 8.dp),
+ text = stringResource(R.string.module_version, BuildConfig.VERSION_NAME),
+ fontSize = MiuixTheme.textStyles.body1.fontSize,
+ color = Color.White.copy(alpha = 0.8f),
+ )
+ AnimatedVisibility(
+ !moduleActive.value
+ ) {
+ Spacer(Modifier.height(8.dp))
+ }
+ AnimatedVisibility(
+ moduleActive.value
+ ) {
+ Text(
+ modifier = Modifier.padding(bottom = 16.dp),
+ text = stringResource(
+ R.string.xposed_framework_version,
+ Executor.name,
+ Executor.apiLevel
+ ),
+ fontSize = MiuixTheme.textStyles.body2.fontSize,
+ color = Color.White.copy(alpha = 0.6f),
+ )
+ }
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_setting),
+ title = stringResource(R.string.basic_settings)
+ ) {
+ navController.navigateWithPopup(Pages.BASIC_SETTINGS)
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_app),
+ title = stringResource(R.string.custom_scope_settings)
+ ) {
+ navController.navigateWithPopup(Pages.SCOPE_SETTINGS)
+ }
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_picture),
+ title = stringResource(R.string.icon_settings)
+ ) {
+ navController.navigateWithPopup(Pages.ICON_SETTINGS)
+ }
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_bottom),
+ title = stringResource(R.string.bottom_settings)
+ ) {
+ navController.navigateWithPopup(Pages.BOTTOM_SETTINGS)
+ }
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_color),
+ title = stringResource(R.string.background_settings)
+ ) {
+ navController.navigateWithPopup(Pages.BACKGROUND_SETTINGS)
+ }
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_monitor),
+ title = stringResource(R.string.display_settings)
+ ) {
+ navController.navigateWithPopup(Pages.DISPLAY_SETTINGS)
+ }
+ AnimatedVisibility(
+ visible = MainActivity.devMode.value
+ ) {
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_lab),
+ title = stringResource(R.string.dev_settings)
+ ) {
+ navController.navigateWithPopup(Pages.DEVELOPER_SETTINGS)
+ }
+ }
+ }
+ }
+ item {
+ PreferenceGroup {
+ TextPreference(
+ icon = ImageIcon(iconRes = R.drawable.ic_help),
+ title = stringResource(R.string.faq)
+ ) {
+ HyperXActivity.context.let {
+ it.startActivity(
+ Intent(Intent.ACTION_VIEW, Uri.parse(it.getString(R.string.faq_url)))
+ )
+ }
+ }
+ }
+ }
+ item {
+ Text(
+ modifier = Modifier.padding(horizontal = 28.dp, vertical = 8.dp),
+ text = stringResource(R.string.main_activity_hint),
+ fontSize = MiuixTheme.textStyles.subtitle.fontSize,
+ color = MiuixTheme.colorScheme.onBackground.copy(alpha = 0.6f)
+ )
+ }
+ }
+
+ SuperDialog(
+ title = stringResource(R.string.restart_title),
+ summary = stringResource(R.string.restart_message),
+ show = dialogRestartVisibility,
+ onDismissRequest = {
+ dismissDialog(dialogRestartVisibility)
+ }
+ ) {
+ Column {
+ TextButton(
+ modifier = Modifier.fillMaxWidth(),
+ text = stringResource(R.string.reboot),
+ onClick = {
+ execShell("reboot")
+ Thread.sleep(300)
+ HyperXActivity.context.let {
+ it.toast(it.getString(R.string.no_root))
+ }
+ }
+ )
+ Spacer(Modifier.height(12.dp))
+ TextButton(
+ modifier = Modifier.fillMaxWidth(),
+ text = stringResource(R.string.restart_system_ui),
+ onClick = {
+ execShell("pkill -f com.android.systemui && pkill -f com.gswxxn.restoresplashscreen")
+ Thread.sleep(300)
+ HyperXActivity.context.let {
+ it.toast(it.getString(R.string.no_root))
+ }
+ }
+ )
+ Spacer(Modifier.height(12.dp))
+ TextButton(
+ modifier = Modifier.fillMaxWidth(),
+ colors = ButtonDefaults.textButtonColorsPrimary(),
+ text = stringResource(R.string.button_cancel),
+ onClick = {
+ dismissDialog(dialogRestartVisibility)
+ }
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt
new file mode 100644
index 00000000..0420b361
--- /dev/null
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt
@@ -0,0 +1,87 @@
+package com.gswxxn.restoresplashscreen.ui.page
+
+import android.widget.Toast
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavController
+import com.gswxxn.restoresplashscreen.R
+import com.gswxxn.restoresplashscreen.data.DataConst
+import com.gswxxn.restoresplashscreen.data.Pages
+import com.gswxxn.restoresplashscreen.ui.MainActivity
+import com.gswxxn.restoresplashscreen.ui.component.HeaderCard
+import dev.lackluster.hyperx.compose.activity.HyperXActivity
+import dev.lackluster.hyperx.compose.activity.SafeSP
+import dev.lackluster.hyperx.compose.base.BasePage
+import dev.lackluster.hyperx.compose.base.BasePageDefaults
+import dev.lackluster.hyperx.compose.navigation.navigateTo
+import dev.lackluster.hyperx.compose.preference.PreferenceGroup
+import dev.lackluster.hyperx.compose.preference.SwitchPreference
+import dev.lackluster.hyperx.compose.preference.TextPreference
+
+/**
+ * 作用域 界面
+ */
+@Composable
+fun ScopePage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) {
+ var customScope by remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_CUSTOM_SCOPE.key)) }
+
+ BasePage(
+ navController,
+ adjustPadding,
+ stringResource(R.string.custom_scope_settings),
+ MainActivity.blurEnabled,
+ MainActivity.blurTintAlphaLight,
+ MainActivity.blurTintAlphaDark,
+ mode
+ ) {
+ item {
+ HeaderCard(
+ imageResID = R.drawable.demo_scope,
+ title = "SCOPE"
+ )
+ }
+ item {
+ PreferenceGroup(
+ last = true
+ ) {
+ // 自定义模块作用域
+ SwitchPreference(
+ title = stringResource(R.string.custom_scope),
+ key = DataConst.ENABLE_CUSTOM_SCOPE.key
+ ) { newValue ->
+ customScope = newValue
+ if (newValue) {
+ HyperXActivity.context.let {
+ Toast.makeText(it, it.getString(R.string.custom_scope_message), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ AnimatedVisibility(
+ customScope
+ ) {
+ Column {
+ // 将作用域外的应用替换位空白启动遮罩
+ SwitchPreference(
+ title = stringResource(R.string.replace_to_empty_splash_screen),
+ summary = stringResource(R.string.replace_to_empty_splash_screen_tips),
+ key = DataConst.REPLACE_TO_EMPTY_SPLASH_SCREEN.key
+ )
+ // 配置应用列表
+ TextPreference(
+ title = stringResource(R.string.exception_mode_list)
+ ) {
+ navController.navigateTo(Pages.CONFIG_CUSTOM_SCOPE)
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BackgroundSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BackgroundSettings.kt
deleted file mode 100644
index 3a08d36c..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BackgroundSettings.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import android.view.View
-import android.widget.LinearLayout
-import android.widget.Switch
-import android.widget.TextView
-import cn.fkj233.ui.activity.view.SpinnerV
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.ColorSelectActivity
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.YukiHelper.isMIUI
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.hasClass
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 背景 界面
- */
-object BackgroundSettings : ISubSettings {
- override val titleID = R.string.background_settings
- override val demoImageID = R.drawable.demo_background
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref : Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> if ((data as String) == context.getString(R.string.follow_system)) (view as Switch).isChecked = true
- 1 -> {
- when ((data as String)) {
- context.getString(R.string.not_change_bg_color) -> {
- view.visibility = View.GONE
- }
- context.getString(R.string.from_custom) -> {
- val subView = ((view as LinearLayout).getChildAt(0) as LinearLayout).getChildAt(0)
- if (subView is TextView && subView.text.toString() == context.getString(R.string.color_mode))
- view.visibility = View.GONE
- else
- view.visibility = View.VISIBLE
- }
- else -> {
- view.visibility = View.VISIBLE
- }
- }
-
- }
- 2 -> view.visibility = if ((data as String) == context.getString(R.string.from_custom)) View.VISIBLE else View.GONE
- }
- }
- // 替换背景颜色
- val changeColorTypeItems = mapOf(
- 0 to context.getString(R.string.not_change_bg_color),
- 1 to context.getString(R.string.from_icon),
- 2 to context.getString(R.string.from_monet),
- 3 to context.getString(R.string.from_custom))
- val changeBGColorTypeBinding = getDataBinding(changeColorTypeItems[context.prefs().get(DataConst.CHANG_BG_COLOR_TYPE)]!!)
- TextWithSpinner(
- TextV(textId = R.string.change_bg_color), SpinnerV(changeColorTypeItems[context.prefs().get(
- DataConst.CHANG_BG_COLOR_TYPE)]!!, 180F, dataBindingSend = changeBGColorTypeBinding.bindingSend){
- for (item in changeColorTypeItems) {
- add(item.value) {
- context.prefs().edit { put(DataConst.CHANG_BG_COLOR_TYPE, item.key) }
- }
- }
- })
- // 自定义背景颜色
- TextSummaryArrow(TextSummaryV(textId = R.string.set_custom_bg_color, tipsId = R.string.set_custom_bg_color_tips, onClickListener = {
- context.startActivity(Intent(context, ColorSelectActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE_OVERALL_BG_COLOR, true)
- })
- }), dataBindingRecv = changeBGColorTypeBinding.getRecv(2))
-
- // 如果应用主动设置了背景颜色则不替换
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.skip_app_with_bg_color), SwitchView(
- DataConst.SKIP_APP_WITH_BG_COLOR), dataBindingRecv = changeBGColorTypeBinding.getRecv(1)
- )
-
- // 颜色模式
- val colorModeItems = mapOf(
- 0 to context.getString(R.string.light_color),
- 1 to context.getString(R.string.dark_color),
- 2 to context.getString(R.string.follow_system))
- val colorModeBinding = getDataBinding(colorModeItems[context.prefs().get(DataConst.BG_COLOR_MODE)]!!)
- TextSummaryWithSpinner(
- TextSummaryV(textId = R.string.color_mode, tipsId = if (isMIUI) R.string.color_mode_tips else null), SpinnerV(colorModeItems[context.prefs().get(
- DataConst.BG_COLOR_MODE)]!!, dataBindingSend = colorModeBinding.bindingSend) {
- for (item in colorModeItems) {
- add(item.value) {
- context.prefs().edit { put(DataConst.BG_COLOR_MODE, item.key) }
- }
- }
- }, dataBindingRecv = changeBGColorTypeBinding.getRecv(1))
-
- // 配置应用列表
- TextSummaryArrow(TextSummaryV(textId = R.string.change_bg_color_list, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BACKGROUND_EXCEPT)
- })
- }), dataBindingRecv = changeBGColorTypeBinding.getRecv(1))
-
- // 单独配置应用背景颜色
- TextSummaryArrow(TextSummaryV(textId = R.string.configure_bg_colors_individually, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BACKGROUND_INDIVIDUALLY_CONFIG)
- })
- }))
-
- Line()
-
- // 忽略深色模式
- if (isMIUI)
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.ignore_dark_mode, tipsId = R.string.ignore_dark_mode_tips), SwitchView(
- DataConst.IGNORE_DARK_MODE, dataBindingRecv = colorModeBinding.getRecv(0))
- )
-
- // 移除截图背景
- if (isMIUI && "android.app.TaskSnapshotHelperImpl".hasClass())
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.remove_bg_drawable, tipsId = R.string.remove_bg_drawable_tips),
- SwitchView(DataConst.REMOVE_BG_DRAWABLE)
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BasicSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BasicSettings.kt
deleted file mode 100644
index ebb0b60e..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BasicSettings.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.ComponentName
-import android.content.Intent
-import android.content.pm.PackageManager
-import cn.fkj233.ui.activity.view.TextSummaryV
-import com.gswxxn.restoresplashscreen.BuildConfig
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue.CREATE_DOCUMENT_CODE
-import com.gswxxn.restoresplashscreen.data.ConstValue.OPEN_DOCUMENT_CODE
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.BackupUtils
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 基础设置 界面
- */
-object BasicSettings : ISubSettings {
- override val titleID = R.string.basic_settings
- override val demoImageID = R.drawable.demo_basic
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- // 启用日志
- if (System.currentTimeMillis() - context.prefs().get(DataConst.ENABLE_LOG_TIMESTAMP) > 86400000) {
- context.prefs().edit().put(DataConst.ENABLE_LOG, false).commit()
- }
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.enable_log, tipsId = R.string.enable_log_tips),
- SwitchView(DataConst.ENABLE_LOG) {
- if (it) {
- context.prefs().edit { put(DataConst.ENABLE_LOG_TIMESTAMP, System.currentTimeMillis()) }
- }
- }
- )
-
- // 隐藏桌面图标
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.hide_icon), SwitchView(DataConst.ENABLE_HIDE_ICON) {
- context.packageManager.setComponentEnabledSetting(
- ComponentName(context, "${BuildConfig.APPLICATION_ID}.Home"),
- if (it) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP
- )
- })
-
- Line()
- TitleText(textId = R.string.backup_restore_title)
-
- // 备份设置项
- TextSummaryArrow(TextSummaryV(textId = R.string.backup) {
- BackupUtils.saveFile(context)
- })
-
- // 恢复设置项
- TextSummaryArrow(TextSummaryV(textId = R.string.restore) {
- BackupUtils.openFile(context)
- })
- }
-
- override fun onActivityResult(context: SubSettings, requestCode: Int, resultCode: Int, data: Intent?) {
- when (requestCode) {
- CREATE_DOCUMENT_CODE -> BackupUtils.handleCreateDocument(context, data?.data)
- OPEN_DOCUMENT_CODE -> BackupUtils.handleReadDocument(context, data?.data)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BottomSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BottomSettings.kt
deleted file mode 100644
index c1bc479d..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BottomSettings.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import android.view.View
-import cn.fkj233.ui.activity.view.TextSummaryV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 底部 界面
- */
-object BottomSettings : ISubSettings {
- override val titleID = R.string.bottom_settings
- override val demoImageID = R.drawable.demo_branding
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref : Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> view.visibility = if (data as Boolean) View.VISIBLE else View.GONE
- }
- }
-
- // 移除底部图片
- val removeBrandingImageBinding = getDataBinding(context.prefs().get(DataConst.REMOVE_BRANDING_IMAGE))
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.remove_branding_image,
- tipsId = R.string.remove_branding_image_tips
- ),
- SwitchView(DataConst.REMOVE_BRANDING_IMAGE, dataBindingSend = removeBrandingImageBinding.bindingSend) {
- if (it) context.toast(context.getString(R.string.custom_scope_message))
- }
- )
-
- // 配置移除列表
- TextSummaryArrow(TextSummaryV(textId = R.string.remove_branding_image_list, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.BRANDING_IMAGE)
- })
- }), dataBindingRecv = removeBrandingImageBinding.getRecv(0))
-
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/CustomScopeSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/CustomScopeSettings.kt
deleted file mode 100644
index a6af7c30..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/CustomScopeSettings.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import android.view.View
-import cn.fkj233.ui.activity.view.TextSummaryV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 作用域 界面
- */
-object CustomScopeSettings : ISubSettings {
- override val titleID = R.string.custom_scope_settings
- override val demoImageID = R.drawable.demo_scope
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref : Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> view.visibility = if (data as Boolean) View.VISIBLE else View.GONE
- }
- }
-
- // 自定义模块作用域
- val customScopeBinding = getDataBinding(context.prefs().get(DataConst.ENABLE_CUSTOM_SCOPE))
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.custom_scope), SwitchView(DataConst.ENABLE_CUSTOM_SCOPE, dataBindingSend = customScopeBinding.bindingSend) {
- if (it) context.toast(context.getString(R.string.custom_scope_message))
- })
-
- // 将作用域外的应用替换位空白启动遮罩
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.replace_to_empty_splash_screen, tipsId = R.string.replace_to_empty_splash_screen_tips), SwitchView(
- DataConst.REPLACE_TO_EMPTY_SPLASH_SCREEN), dataBindingRecv = customScopeBinding.binding.getRecv(0))
-
- // 配置应用列表
- TextSummaryArrow(TextSummaryV(textId = R.string.exception_mode_list) {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.CUSTOM_SCOPE)
- })
- }, dataBindingRecv = customScopeBinding.binding.getRecv(0))
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DevSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DevSettings.kt
deleted file mode 100644
index 283e19ac..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DevSettings.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import cn.fkj233.ui.activity.view.TextSummaryV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-
-/** 开发者选项 */
-object DevSettings: ISubSettings {
- override val titleID = R.string.dev_settings
- override val demoImageID = null
-
- /** onCreate 事件 */
- override fun create(
- context: SubSettings,
- binding: ActivitySubSettingsBinding
- ): BlockMIUIItemData.() -> Unit = {
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.dev_settings
- ),
- SwitchView(DataConst.ENABLE_DEV_SETTINGS) {
- if (it) return@SwitchView
-
- context.toast(context.getString(R.string.disabled_dev_settings))
- context.finishAfterTransition()
- }
- )
-
- TextSummaryArrow(
- TextSummaryV(textId = R.string.hook_info) {
- context.startActivity(Intent(context, SubSettings::class.java).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.HOOK_INFO)
- })
- }
- )
-
- Line()
- TitleText(textId = R.string.icon_settings)
-
- SeekBarWithStatus(
- titleID = R.string.dev_icon_round_corner_rate,
- pref = DataConst.DEV_ICON_ROUND_CORNER_RATE,
- min = 0,
- max = 50,
- isPercentage = true
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DisplaySettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DisplaySettings.kt
deleted file mode 100644
index 484caf84..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DisplaySettings.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import android.view.View
-import android.widget.Switch
-import cn.fkj233.ui.activity.view.TextSummaryV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-
-/**
- * 显示设置 界面
- */
-object DisplaySettings : ISubSettings {
- override val titleID = R.string.display_settings
- override val demoImageID = R.drawable.demo_display
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref : Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> view.visibility = if (data as Boolean) View.VISIBLE else View.GONE
- 1 -> if (data as Boolean) (view as Switch).isChecked = true
- 2 -> if (!(data as Boolean)) (view as Switch).isChecked = false
- }
- }
-
- // 遮罩最小持续时间
- TextSummaryArrow(TextSummaryV(textId = R.string.min_duration, tipsId = R.string.min_duration_tips) {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.MIN_DURATION)
- })
- })
-
- Line()
-
- // 强制显示遮罩
- val forceShowSplashScreenBinding = getDataBinding(context.prefs().get(DataConst.FORCE_SHOW_SPLASH_SCREEN))
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.force_show_splash_screen,
- tipsId = R.string.force_show_splash_screen_tips
- ),
- SwitchView(DataConst.FORCE_SHOW_SPLASH_SCREEN, dataBindingSend = forceShowSplashScreenBinding.bindingSend) {
- if (it) context.toast(context.getString(R.string.custom_scope_message))
- }
- )
-
- // 配置应用列表
- TextSummaryArrow(TextSummaryV(textId = R.string.force_show_splash_screen_list, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.FORCE_SHOW_SPLASH_SCREEN)
- })
- }), dataBindingRecv = forceShowSplashScreenBinding.getRecv(0))
-
- // 减少不必要的启动遮罩
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.reduce_splash_screen,
- tipsId = R.string.reduce_splash_screen_tips
- ),
- SwitchView(DataConst.REDUCE_SPLASH_SCREEN),
- dataBindingRecv = forceShowSplashScreenBinding.getRecv(0)
- )
-
- Line()
-
- // 强制开启启动遮罩
- val hotStartBinding = getDataBinding(context.prefs().get(DataConst.ENABLE_HOT_START_COMPATIBLE))
- val forceEnableSplashScreenBinding = getDataBinding(context.prefs().get(DataConst.FORCE_ENABLE_SPLASH_SCREEN))
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.force_enable_splash_screen,
- tipsId = R.string.force_enable_splash_screen_tips
- ),
- SwitchView(
- DataConst.FORCE_ENABLE_SPLASH_SCREEN,
- dataBindingRecv = hotStartBinding.getRecv(1),
- dataBindingSend = forceEnableSplashScreenBinding.bindingSend
- )
- )
-
- // 将启动遮罩适用于热启动
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.hot_start_compatible,
- tipsId = R.string.hot_start_compatible_tips
- ),
- SwitchView(
- DataConst.ENABLE_HOT_START_COMPATIBLE,
- dataBindingRecv = forceEnableSplashScreenBinding.getRecv(2),
- dataBindingSend = hotStartBinding.bindingSend
- )
- )
-
- // 彻底关闭 Splash Screen
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.disable_splash_screen, tipsId = R.string.disable_splash_screen_tips), SwitchView(
- DataConst.DISABLE_SPLASH_SCREEN)
- )
-
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/HookInfo.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/HookInfo.kt
deleted file mode 100644
index 9ebda510..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/HookInfo.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.widget.LinearLayout
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toArgb
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.hook.base.HookManager
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.BlockMIUIHelper.addBlockMIUIView
-import com.gswxxn.restoresplashscreen.utils.YukiHelper.getHookInfo
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-
-/**
- * Hook 信息 界面
- */
-object HookInfo: ISubSettings {
- override val titleID = R.string.hook_info
- override val demoImageID = null
-
- /**
- * 创建一个新的 BlockMIUIItemData 实例
- */
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- context.getHookInfo("com.android.systemui") { hookInfo ->
- redrawView(context, binding.settingItems, hookInfo)
- }
- }
-
- /**
- * 重新绘制视图,使用给定的上下文和钩子管理器的映射。
- * 从线性布局中移除所有现有视图,并为映射中的每个条目添加新的 TextSummary 视图,
- * 按照 Hook 是否可能异常以及键进行排序
- *
- * @param context 用于创建视图的上下文。
- * @param linearLayout 要重新绘制的线性布局。
- * @param map 钩子管理器的映射。
- */
- private fun redrawView(context: SubSettings, linearLayout: LinearLayout, map: Map) {
- linearLayout.removeAllViews()
- linearLayout.addBlockMIUIView(context) {
- map.entries.sortedWith(compareBy({ !it.value.isAbnormal }, {it.key})).forEach { (key, hookInfo) ->
- TextSummary(
- text = key,
- colorInt = if (hookInfo.isAbnormal) Color.Red.toArgb() else null,
- tips = "createCondition: ${hookInfo.createCondition}\n" +
- "isMemberFound: ${hookInfo.isMemberFound}\n" +
- "hasBeforeHooks: ${hookInfo.hasBeforeHooks}\n" +
- "isBeforeHookExecuted: ${hookInfo.isBeforeHookExecuted}\n" +
- "hasAfterHooks: ${hookInfo.hasAfterHooks}\n" +
- "isAfterHookExecuted: ${hookInfo.isAfterHookExecuted}\n" +
- "hasReplaceHook: ${hookInfo.hasReplaceHook}\n" +
- "isReplaceHookExecuted: ${hookInfo.isReplaceHookExecuted}"
- )
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/IconSettings.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/IconSettings.kt
deleted file mode 100644
index 5af1f070..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/IconSettings.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.gswxxn.restoresplashscreen.ui.subsettings
-
-import android.content.Intent
-import android.view.View
-import androidx.core.widget.NestedScrollView
-import cn.fkj233.ui.activity.view.SpinnerV
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.gswxxn.restoresplashscreen.data.ConstValue
-import com.gswxxn.restoresplashscreen.data.DataConst
-import com.gswxxn.restoresplashscreen.databinding.ActivitySubSettingsBinding
-import com.gswxxn.restoresplashscreen.ui.ConfigAppsActivity
-import com.gswxxn.restoresplashscreen.ui.SubSettings
-import com.gswxxn.restoresplashscreen.ui.`interface`.ISubSettings
-import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
-import com.gswxxn.restoresplashscreen.utils.IconPackManager
-import com.gswxxn.restoresplashscreen.utils.YukiHelper
-import com.gswxxn.restoresplashscreen.view.BlockMIUIItemData
-import com.gswxxn.restoresplashscreen.view.SwitchView
-import com.highcapable.yukihookapi.hook.factory.prefs
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-
-/**
- * 图标 界面
- */
-object IconSettings : ISubSettings {
- override val titleID = R.string.icon_settings
- override val demoImageID = R.drawable.demo_icon
-
- override fun create(context: SubSettings, binding: ActivitySubSettingsBinding): BlockMIUIItemData.() -> Unit = {
- fun getDataBinding(pref : Any) = GetDataBinding({ pref }) { view, flags, data ->
- when (flags) {
- 0 -> view.visibility = if (data as Boolean) View.VISIBLE else View.GONE
- 1 -> view.visibility = if (data as String != context.getString(R.string.not_shrink_icon)) View.VISIBLE else View.GONE
- }
- }
-
- // 绘制图标圆角
- TextSummaryWithSwitch(TextSummaryV(textId = R.string.draw_round_corner), SwitchView(DataConst.ENABLE_DRAW_ROUND_CORNER))
-
- // 缩小图标
- val shrinkIconItems = mapOf(
- 0 to context.getString(R.string.not_shrink_icon),
- 1 to context.getString(R.string.shrink_low_resolution_icon),
- 2 to context.getString(R.string.shrink_all_icon)
- )
- val shrinkIconBinding = getDataBinding(shrinkIconItems[context.prefs().get(DataConst.SHRINK_ICON)]!!)
- TextWithSpinner(TextV(textId = R.string.shrink_icon), SpinnerV(shrinkIconItems[context.prefs().get(DataConst.SHRINK_ICON)]!!, 180F, dataBindingSend = shrinkIconBinding.bindingSend) {
- for (item in shrinkIconItems) {
- add(item.value) {
- context.prefs().edit { put(DataConst.SHRINK_ICON, item.key) }
- }
- }
- })
-
- // 为缩小的图标添加模糊背景
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.add_icon_blur_bg),
- SwitchView(DataConst.ENABLE_ADD_ICON_BLUR_BG),
- dataBindingRecv = shrinkIconBinding.getRecv(1)
- )
-
- // 替换图标获取方式
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.replace_icon, tipsId = R.string.replace_icon_tips),
- SwitchView(DataConst.ENABLE_REPLACE_ICON)
- )
-
- // 使用 MIUI 大图标
- if (YukiHelper.atLeastMIUI14)
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.use_miui_large_icon),
- SwitchView(DataConst.ENABLE_USE_MIUI_LARGE_ICON)
- )
-
- // 使用图标包
- val availableIconPacks = IconPackManager(context).getAvailableIconPacks()
- TextWithSpinner(
- TextV(textId = R.string.use_icon_pack), SpinnerV(availableIconPacks[context.prefs().get(DataConst.ICON_PACK_PACKAGE_NAME)]?:context.getString(
- R.string.icon_pack_is_removed)) {
- for (item in availableIconPacks) {
- add(item.value) {
- context.prefs().edit { put(DataConst.ICON_PACK_PACKAGE_NAME, item.key) }
- }
- }
- })
-
- Line()
-
- // 忽略应用主动设置的图标
- val defaultStyleBinding = getDataBinding(context.prefs().get(DataConst.ENABLE_DEFAULT_STYLE))
- TextSummaryWithSwitch(
- TextSummaryV(
- textId = R.string.default_style,
- tipsId = R.string.default_style_tips
- ),
- SwitchView(DataConst.ENABLE_DEFAULT_STYLE, dataBindingSend = defaultStyleBinding.bindingSend) {
- if (it) {
- context.toast(context.getString(R.string.custom_scope_message))
- }
- }
- )
-
- // 配置应用列表
- TextSummaryArrow(TextSummaryV(textId = R.string.default_style_list, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.DEFAULT_STYLE)
- })
- }), dataBindingRecv = defaultStyleBinding.getRecv(0))
-
- Line()
-
- // 不显示图标
- val hideSplashScreenIconBinding = getDataBinding(context.prefs().get(DataConst.ENABLE_HIDE_SPLASH_SCREEN_ICON))
- TextSummaryWithSwitch(
- TextSummaryV(textId = R.string.hide_splash_screen_icon),
- SwitchView(DataConst.ENABLE_HIDE_SPLASH_SCREEN_ICON, dataBindingSend = hideSplashScreenIconBinding.bindingSend) {
- if (it) {
- context.toast(context.getString(R.string.custom_scope_message))
- MainScope().launch {
- delay(100)
- binding.nestedScrollView.fullScroll(NestedScrollView.FOCUS_DOWN)
- }
- }
- }
- )
-
- // 配置应用列表
- TextSummaryArrow(TextSummaryV(textId = R.string.default_style_list, onClickListener = {
- context.startActivity(Intent(context, ConfigAppsActivity::class.java).apply {
- putExtra(ConstValue.EXTRA_MESSAGE, ConstValue.HIDE_SPLASH_SCREEN_ICON)
- })
- }), dataBindingRecv = hideSplashScreenIconBinding.getRecv(0))
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/AppInfoHelper.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/AppInfoHelper.kt
deleted file mode 100644
index 5e0610f8..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/AppInfoHelper.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.gswxxn.restoresplashscreen.utils
-
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import android.graphics.drawable.Drawable
-
-/**
- * 原始位置 [Hide-My-Applist](https://github.com/Dr-TSNG/Hide-My-Applist/blob/d377ab13ddf74a3f1b561fda1631a62e4fbc0ab0/app/src/main/java/com/tsng/hidemyapplist/app/helpers/AppInfoHelper.kt)
- */
-class AppInfoHelper(private val context: Context, private val checkedList: Set, private val configList: MutableMap) {
- private lateinit var appInfoList: MutableList
-
- /**
- * 数据类, 存储应用信息
- */
- data class MyAppInfo(
- val appName: String,
- val packageName: String,
- val icon: Drawable,
- // 该 config 用于存储具体应用配置, 例如最小持续时间, 单独设置的背景颜色等
- var config: String?,
- // 该 isChecked 用于存储应用是否被勾选, 0 为未勾选, 1 为勾选
- var isChecked: Int,
- val isSystemApp: Boolean
- )
-
- /**
- * 获取应用信息列表
- *
- * @return [MutableList] 应用信息列表
- */
- fun getAppInfoList(): MutableList {
- if (::appInfoList.isInitialized)
- return appInfoList.apply {
- sortBy { it.appName }
- sortByDescending { it.config }
- sortByDescending {it.isChecked }
- }.toMutableList()
- appInfoList = mutableListOf()
- val pm = context.packageManager
- for (appInfo in pm.getInstalledApplications(0)) {
- MyAppInfo(
- appInfo.loadLabel(pm).toString(),
- appInfo.packageName,
- appInfo.loadIcon(pm),
- configList[appInfo.packageName],
- if (appInfo.packageName in checkedList) 1 else 0,
- appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
- ).also { appInfoList.add(it) }
- }
- return appInfoList.apply {
- sortBy { it.appName }
- sortByDescending { it.config }
- sortByDescending { it.isChecked }
- }.toMutableList()
- }
-
- /**
- * 设置选项的勾选状态 ([MyAppInfo.isChecked])
- *
- * @param info 应用信息
- * @param status 勾选状态
- */
- fun setChecked(info : MyAppInfo, status : Boolean) {
- appInfoList[appInfoList.indexOf(info)].isChecked = if (status) 1 else 0
- }
-
- /**
- * 根据应用信息设置其参配置 ([MyAppInfo.config]),
- *
- * @param info 应用信息
- * @param config 参数
- */
- fun setConfig(info : MyAppInfo, config : String?) {
- appInfoList[appInfoList.indexOf(info)].config = config
- }
-
- /**
- * 根据索引设置其参配置 ([MyAppInfo.config]),
- *
- * @param index 应用信息的索引
- * @param config 参数
- */
- fun setConfig(index : Int, config : String?) {
- appInfoList[index].config = config
- }
-
- /**
- * 获取应用信息的索引
- *
- * @param info 应用信息
- * @return 应用信息的索引
- */
- fun getIndex(info : MyAppInfo) = appInfoList.indexOf(info)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BackupUtils.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BackupUtils.kt
index 40ac42d3..41ca0400 100644
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BackupUtils.kt
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BackupUtils.kt
@@ -1,11 +1,13 @@
package com.gswxxn.restoresplashscreen.utils
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.net.Uri
import com.gswxxn.restoresplashscreen.R
import com.gswxxn.restoresplashscreen.data.ConstValue.CREATE_DOCUMENT_CODE
import com.gswxxn.restoresplashscreen.data.ConstValue.OPEN_DOCUMENT_CODE
+import com.gswxxn.restoresplashscreen.ui.MainActivity
import com.gswxxn.restoresplashscreen.utils.CommonUtils.toast
import com.highcapable.yukihookapi.hook.factory.prefs
import org.json.JSONObject
@@ -14,50 +16,25 @@ import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.time.LocalDateTime
+import kotlin.system.exitProcess
/**
* 改自 [MiuiHomeR](https://github.com/qqlittleice/MiuiHome_R/blob/9f3a298df6427b3a8ea6a47aaabfa0a56c4dd11e/app/src/main/java/com/yuk/miuiHomeR/utils/BackupUtils.kt#L47)
* 用于备份和恢复数据
*/
object BackupUtils {
-
- /**
- * 打开文件, 用于选择备份文件
- *
- * @param activity [Activity]
- * @return [Unit]
- */
- fun openFile(activity: Activity) =
- activity.startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
- addCategory(Intent.CATEGORY_OPENABLE)
- type = "application/json"
- }, OPEN_DOCUMENT_CODE)
-
- /**
- * 读取文件, 用于恢复数据
- *
- * @param activity [Activity]
- * @return [Unit]
- */
- fun saveFile(activity: Activity) =
- activity.startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
- addCategory(Intent.CATEGORY_OPENABLE)
- type = "application/json"
- putExtra(Intent.EXTRA_TITLE, "RestoreSplashScreen_${LocalDateTime.now()}.json")
- }, CREATE_DOCUMENT_CODE)
-
/**
* 处理打开文件, 处理并写出数据
*
- * @param activity [Activity]
+ * @param context [Context]
* @param data [Uri]
*/
- fun handleReadDocument(activity: Activity, data: Uri?) {
+ fun handleReadDocument(context: Context, data: Uri?) {
val uri = data ?: return
try {
- activity.prefs().edit {
+ context.prefs().edit {
clear()
- activity.contentResolver.openInputStream(uri)?.let { loadFile ->
+ context.contentResolver.openInputStream(uri)?.let { loadFile ->
BufferedReader(InputStreamReader(loadFile)).apply {
val sb = StringBuffer()
var line = readLine()
@@ -87,32 +64,40 @@ object BackupUtils {
}
}
}
- activity.finish()
- activity.toast(activity.getString(R.string.restore_successful))
- } catch (e: Throwable) { activity.toast(activity.getString(R.string.restore_failed)) }
+ context.toast(context.getString(R.string.restore_successful))
+ Thread {
+ Thread.sleep(500)
+ val intent =
+ Intent(context, MainActivity::class.java)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ context.startActivity(intent)
+ exitProcess(0)
+ }.start()
+ } catch (e: Throwable) { context.toast(context.getString(R.string.restore_failed)) }
}
/**
* 处理保存文件, 写出数据
*
- * @param activity [Activity]
+ * @param context [Context]
* @param data [Uri]
*/
- fun handleCreateDocument(activity: Activity, data: Uri?) {
+ fun handleCreateDocument(context: Context, data: Uri?) {
val uri = data ?: return
try {
- activity.contentResolver.openOutputStream(uri)?.let { saveFile ->
+ context.contentResolver.openOutputStream(uri)?.let { saveFile ->
BufferedWriter(OutputStreamWriter(saveFile)).apply {
write(JSONObject().also {
- for (entry: Map.Entry in activity.prefs().all()) {
+ for (entry: Map.Entry in context.prefs().all()) {
it.put(entry.key, entry.value)
}
}.toString())
close()
}
}
- activity.toast(activity.getString(R.string.save_successful))
- } catch (_: Throwable) { activity.toast(activity.getString(R.string.save_failed)) }
+ context.toast(context.getString(R.string.save_successful))
+ } catch (_: Throwable) { context.toast(context.getString(R.string.save_failed)) }
}
/**
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BlockMIUIHelper.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BlockMIUIHelper.kt
deleted file mode 100644
index 2e6e3bba..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/BlockMIUIHelper.kt
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.gswxxn.restoresplashscreen.utils
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.view.Gravity
-import android.view.MotionEvent
-import android.view.ViewGroup
-import android.widget.LinearLayout
-import android.widget.Toast
-import cn.fkj233.ui.R
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.view.*
-import com.gswxxn.restoresplashscreen.view.*
-import com.highcapable.yukihookapi.YukiHookAPI
-import com.highcapable.yukihookapi.hook.factory.current
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.launch
-
-/**
- * 复制自 [BlockMIUI](https://github.com/Block-Network/blockmiui/blob/6a2cf743d5c6904f6807634750e03ce3ecc6bbad/src/main/java/cn/fkj233/ui/activity/fragment/MIUIFragment.kt)
- *
- */
-object BlockMIUIHelper {
-
- fun LinearLayout.addBlockMIUIView(context: Context, itemData: BlockMIUIItemData.() -> Unit) =
- BlockMIUIItemData().apply(itemData).itemList.forEach {
- MainScope().launch { addItem(this@addBlockMIUIView, it, context) }
- }
-
- @SuppressLint("ClickableViewAccessibility")
- fun addItem(itemView: LinearLayout, item: BaseView, context: Context) {
- val callBacks: (() -> Unit)? = null
-
- itemView.addView(LinearLayout(context).apply { // 控件布局
- layoutParams = ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- background = context.getDrawable(R.drawable.ic_click_check)
- setPadding(dp2px(context, 30f), 0, dp2px(context, 30f), 0)
- when (item) {
- is SeekBarV -> { // 滑动条
- addView(LinearLayout(context).apply {
- setPadding(dp2px(context, 12f), 0, dp2px(context, 12f), 0)
- addView(
- item.create(context, callBacks), LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- )
- )
- })
- }
- is SeekBarWithTextV -> { // 滑动条 带文本
- addView(
- item.create(context, callBacks), LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- )
- )
- }
- is TextV -> { // 文本
- addView(item.create(context, callBacks))
- item.onClickListener?.let { unit ->
- setOnClickListener {
- unit()
- callBacks?.let { it1 -> it1() }
- }
- }
- }
- is SwitchView -> addView(item.create(context, callBacks)) // 开关
- is TextSummaryWithSwitchView -> {
- val switch: SwitchView = item.switchV
- addView(item.create(context, callBacks)) // 带文本的开关
- setOnTouchListener { _, motionEvent ->
- when (motionEvent.action) {
- MotionEvent.ACTION_DOWN -> if (switch.switch.isEnabled) background =
- context.getDrawable(
- R.drawable.ic_main_down_bg
- )
- MotionEvent.ACTION_UP -> {
- val touchX: Float = motionEvent.x
- val touchY: Float = motionEvent.y
- val maxX = width.toFloat()
- val maxY = height.toFloat()
- if (touchX < 0 || touchX > maxX || touchY < 0 || touchY > maxY) {
- setPressed(false)
- return@setOnTouchListener false
- }
- if (switch.switch.isEnabled) {
- switch.click()
- callBacks?.let { it1 -> it1() }
- background = context.getDrawable(R.drawable.ic_main_bg)
- }
- }
- else -> background = context.getDrawable(R.drawable.ic_main_bg)
- }
- true
- }
- }
- is TitleTextV -> addView(item.create(context, callBacks)) // 标题文字
- is LineV -> addView(item.create(context, callBacks)) // 分割线
- is LinearContainerV -> addView(item.create(context, callBacks)) // 布局创建
- is ImageTextV -> { // 作者框
- addView(item.create(context, callBacks).apply {
- (layoutParams as LinearLayout.LayoutParams).setMargins(0, 0,0,0)
- })
- item.current().field { type = Function0::class.java }.cast<(() -> Unit)?>()?.let { unit ->
- setOnClickListener {
- unit()
- callBacks?.let { it1 -> it1() }
- }
- }
- }
- is TextSummaryV -> { // 带箭头和提示的文本框
- addView(item.create(context, callBacks))
- item.onClickListener?.let { unit ->
- setOnClickListener {
- unit()
- callBacks?.let { it1 -> it1() }
- }
- }
- }
- is SpinnerV -> { // 下拉选择框
- addView(item.create(context, callBacks))
- }
- is TextSummaryWithSpinnerV, is TextWithSpinnerV -> {
- addView(item.create(context, callBacks))
- setOnClickListener {}
- val spinner = when (item) {
- is TextSummaryWithSpinnerV -> item.current().field { type = SpinnerV::class.java }.cast()
- is TextWithSpinnerV -> item.current().field { type = SpinnerV::class.java }.cast()
- else -> throw IllegalAccessException("Not is TextSummaryWithSpinnerV or TextWithSpinnerV")
- }!!
- setOnTouchListener { view, motionEvent ->
- if (motionEvent.action == MotionEvent.ACTION_UP) {
- if (!YukiHookAPI.Status.isXposedModuleActive) {
- Toast.makeText(context, com.gswxxn.restoresplashscreen.R.string.make_sure_active, Toast.LENGTH_SHORT).show()
- return@setOnTouchListener false
- }
- val popup = MIUIPopup(context, view, spinner.currentValue, spinner.dropDownWidth, {
- spinner.select.text = it
- spinner.currentValue = it
- callBacks?.let { it1 -> it1() }
- spinner.dataBindingSend?.send(it)
- }, SpinnerV.SpinnerData().apply(spinner.data).arrayList)
- if (view.width / 2 >= motionEvent.x) {
- popup.apply {
- horizontalOffset = dp2px(context, 24F)
- setDropDownGravity(Gravity.LEFT)
- }
- } else {
- popup.apply {
- horizontalOffset = -dp2px(context, 24F)
- setDropDownGravity(Gravity.RIGHT)
- }
- }
- popup.show()
- }
- false
- }
- }
- is TextSummaryWithArrowV -> {
- addView(item.create(context, callBacks))
- item.current().field { type = TextSummaryV::class.java }.cast()!!.onClickListener?.let { unit ->
- setOnClickListener {
- if (!YukiHookAPI.Status.isXposedModuleActive) {
- Toast.makeText(context, com.gswxxn.restoresplashscreen.R.string.make_sure_active, Toast.LENGTH_SHORT).show()
- return@setOnClickListener
- }
- unit()
- callBacks?.let { it1 -> it1() }
- }
- }
- }
- is CustomViewV -> {
- addView(item.create(context, callBacks))
- }
- is RadioViewV -> {
- setPadding(0, 0, 0, 0)
- addView(item.create(context, callBacks))
- }
- is SeekBarWithTitleView -> addView(item.create(context, callBacks))
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/GraphicUtils.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/GraphicUtils.kt
index 7861b9da..5d767565 100644
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/GraphicUtils.kt
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/GraphicUtils.kt
@@ -14,9 +14,9 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.palette.graphics.Palette
-import cn.fkj233.ui.activity.dp2px
import com.gswxxn.restoresplashscreen.data.RoundDegree
import android.graphics.Path
+import com.gswxxn.restoresplashscreen.hook.systemui.dp2px
/**
* 图形工具类
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/YukiHelper.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/YukiHelper.kt
index 72637104..932f268d 100644
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/utils/YukiHelper.kt
+++ b/app/src/main/java/com/gswxxn/restoresplashscreen/utils/YukiHelper.kt
@@ -10,6 +10,7 @@ import com.highcapable.yukihookapi.hook.core.finder.members.FieldFinder.Result.I
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.dataChannel
+import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.YLog
@@ -122,6 +123,21 @@ object YukiHelper {
*/
val isMIUI by lazy { "android.miui.R".hasClass() }
+ /**
+ * 当前设备是否是小米平板
+ *
+ * @return [Boolean] 是否符合条件
+ */
+ val isXiaomiPad by lazy {
+ isMIUI && try {
+ "miui.os.Build".toClass().field {
+ name = "IS_TABLET"
+ modifiers { isStatic }
+ }.get().boolean()
+ } catch (_: Exception) {
+ false
+ }
+ }
/**
* 检测 MIUI 版本是否至少为 14
*
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/view/BlockMIUIItemData.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/view/BlockMIUIItemData.kt
deleted file mode 100644
index a3cadc34..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/view/BlockMIUIItemData.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-@file:Suppress("FunctionName")
-
-package com.gswxxn.restoresplashscreen.view
-
-import android.graphics.Typeface
-import android.graphics.drawable.Drawable
-import android.view.View
-import android.widget.TextView
-import cn.fkj233.ui.activity.data.DataBinding
-import cn.fkj233.ui.activity.data.Padding
-import cn.fkj233.ui.activity.view.*
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 复制自 [cn.fkj233.ui.activity.data.InitView], 后续可能会使用更优办法实现, 而不是复制整个类
- */
-class BlockMIUIItemData {
- companion object {
- val datalist = mutableMapOf>()
- }
- val itemList: ArrayList = arrayListOf()
- private var bindingData = arrayListOf()
-
- fun GetDataBinding(defValue: () -> Any, recvCallbacks: (View, Int, Any) -> Unit): DataBinding.BindingData {
- return DataBinding.get(bindingData, defValue, recvCallbacks)
- }
-
- fun Author(authorHead: Drawable, authorName: String, authorTips: String? = null, round: Float = 30f, onClickListener: (() -> Unit)? = null, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(ImageTextV(authorHead, authorName, authorTips, round, onClickListener, dataBindingRecv))
- }
-
- fun Page(pageHead: Drawable, pageName: String?, pageNameId: Int?, round: Float = 0f, onClickListener: (() -> Unit)? = null, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(PageV(pageHead, pageName, pageNameId, round, onClickListener, dataBindingRecv))
- }
-
- fun Line() {
- itemList.add(LineV())
- }
-
- fun SeekBar(key: String, min: Int, max: Int, defaultProgress: Int, dataSend: DataBinding.Binding.Send? = null, dataBindingRecv: DataBinding.Binding.Recv? = null, callBacks: ((Int, TextView) -> Unit)? = null) {
- itemList.add(SeekBarV(key, min, max, defaultProgress, dataSend, dataBindingRecv, callBacks))
- }
-
- fun TextSummaryWithSpinner(textV: TextSummaryV, spinnerV: SpinnerV, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextSummaryWithSpinnerV(textV, spinnerV, dataBindingRecv))
- }
-
- fun Text(text: String? = null, textId: Int? = null, textSize: Float? = null, colorInt: Int? = null, colorId: Int? = null, padding: Padding? = null, dataBindingRecv: DataBinding.Binding.Recv? = null, typeface: Typeface? = null, onClickListener: (() -> Unit)? = null) {
- itemList.add(TextV(text, textId, textSize, colorInt, colorId, padding, dataBindingRecv, typeface, onClickListener))
- }
-
- fun SeekBarWithText(key: String = "", min: Int, max: Int, defaultProgress: Int = 0, dataBindingRecv: DataBinding.Binding.Recv? = null, dataBindingSend: DataBinding.Binding.Send? = null, callBacks: ((Int, TextView) -> Unit)? = null) {
- itemList.add(SeekBarWithTextV(key, min, max, defaultProgress, dataBindingRecv, dataBindingSend, callBacks))
- }
-
- fun TextSummaryArrow(textSummaryV: TextSummaryV, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextSummaryWithArrowV(textSummaryV, dataBindingRecv))
- }
-
- fun TextA(text: String? = null, textId: Int? = null, onClickListener: (() -> Unit)? = null, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextSummaryWithArrowV(TextSummaryV(text, textId, onClickListener = onClickListener), dataBindingRecv))
- }
-
- fun TextSummaryWithSwitch(textSummaryV: TextSummaryV, switchView: SwitchView, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextSummaryWithSwitchView(textSummaryV, switchView, dataBindingRecv))
- }
-
- fun TitleText(text: String? = null, textId: Int? = null,colorInt: Int? = null, colorId: Int? = null, dataBindingRecv: DataBinding.Binding.Recv? = null, onClickListener: (() -> Unit)? = null) {
- itemList.add(TitleTextV(text, textId,colorInt, colorId,dataBindingRecv, onClickListener))
- }
-
- fun TextWithSwitch(textV: TextV, switchV: SwitchV, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextWithSwitchV(textV, switchV, dataBindingRecv))
- }
-
- fun TextS(text: String? = null, textId: Int? = null, key: String, defValue: Boolean=false, onClickListener: ((Boolean) -> Unit)? = null, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextWithSwitchV(TextV(text, textId), SwitchV(key, defValue, onClickListener = onClickListener), dataBindingRecv))
- }
-
- fun TextWithSpinner(textV: TextV, spinnerV: SpinnerV, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(TextWithSpinnerV(textV, spinnerV, dataBindingRecv))
- }
-
- fun CustomView(view: View, dataBindingRecv: DataBinding.Binding.Recv? = null) {
- itemList.add(CustomViewV(view, dataBindingRecv))
- }
-
- fun RadioView(key: String, dataBindingRecv: DataBinding.Binding.Recv? = null, data: RadioViewV.RadioData.() -> Unit) {
- itemList.add(RadioViewV(key, dataBindingRecv, data))
- }
-
- fun TextSummary(text: String? = null, textId: Int? = null, tips: String? = null, colorInt: Int? = null, colorId: Int? = null, tipsId: Int? = null, dataBindingRecv: DataBinding.Binding.Recv? = null, onClickListener: (() -> Unit)? = null) {
- itemList.add(TextSummaryV(text, textId, tips, colorInt, colorId, tipsId, dataBindingRecv, onClickListener))
- }
-
- fun SeekBarWithStatus(
- titleID: Int,
- pref: PrefsData? = null,
- min: Int,
- max: Int,
- defaultProgress: Int = 0,
- isPercentage: Boolean = false,
- progressColor: Int = 0xFF0d7AEC.toInt(),
- drawHuePanel: Boolean = false,
- dataBindingRecv: DataBinding.Binding.Recv? = null,
- dataBindingSend: DataBinding.Binding.Send? = null,
- onProgressChanged: ((value: Int) -> Unit)? = null
- ) {
- itemList.add(SeekBarWithTitleView(titleID, pref, min, max, defaultProgress, isPercentage, progressColor, drawHuePanel, dataBindingRecv, dataBindingSend, onProgressChanged))
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/view/NewMIUIDialog.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/view/NewMIUIDialog.kt
deleted file mode 100644
index 829b6710..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/view/NewMIUIDialog.kt
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * BlockMIUI
- * Copyright (C) 2022 fkj@fkj233.cn
- * https://github.com/577fkj/BlockMIUI
- *
- * This software is free opensource software: you can redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public License v2.1
- * as published by the Free Software Foundation; either
- * version 3 of the License, or any later version and our eula as published
- * by 577fkj.
- *
- * 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
- * GNU Lesser General Public License v2.1 for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License v2.1
- * and eula along with this software. If not, see
- *
- * .
- */
-
-package com.gswxxn.restoresplashscreen.view
-
-import android.app.Dialog
-import android.content.Context
-import android.graphics.drawable.GradientDrawable
-import android.text.Editable
-import android.text.TextWatcher
-import android.util.TypedValue
-import android.view.Gravity
-import android.view.View
-import android.view.ViewTreeObserver
-import android.view.WindowManager
-import android.widget.Button
-import android.widget.EditText
-import android.widget.LinearLayout
-import android.widget.RelativeLayout
-import android.widget.TextView
-import cn.fkj233.ui.R
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.getDisplay
-
-/**
- * 自定义一些弹窗参数, 后续可能会通过反射实现, 而不是把类复制过来
- */
-class NewMIUIDialog(context: Context, val build: NewMIUIDialog.() -> Unit) : Dialog(context, R.style.CustomDialog) {
- private val title by lazy {
- TextView(context).also { textView ->
- textView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
- it.setMargins(0, dp2px(context, 20f), 0, dp2px(context, 20f))
- }
- textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 19f)
- textView.setTextColor(context.getColor(R.color.whiteText))
- textView.gravity = Gravity.CENTER
- textView.setPadding(0, dp2px(context, 10f), 0, 0)
- }
- }
-
- private val message by lazy {
- TextView(context).also { textView ->
- textView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
- it.setMargins(dp2px(context, 20f), 0, dp2px(context, 20f), 0)
- }
- textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17f)
- textView.setTextColor(context.getColor(R.color.author_tips))
- textView.gravity = Gravity.START
- textView.visibility = View.GONE
- textView.setPadding(dp2px(context, 10f), 0, dp2px(context, 10f), 0)
- }
- }
-
- private val editText by lazy {
- EditText(context).also { editText ->
- editText.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dp2px(context, 55f)).also {
- it.setMargins(dp2px(context, 20f), 0, dp2px(context, 20f), 0)
- }
- editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25f)
- editText.setTextColor(context.getColor(R.color.whiteText))
- editText.gravity = Gravity.CENTER
- editText.setPadding(dp2px(context, 8f), dp2px(context, 8f), dp2px(context, 8f), dp2px(context, 8f))
- editText.visibility = View.GONE
- editText.background = context.getDrawable(R.drawable.editview_background)
- val mHeight = dp2px(context, 55f)
- val maxHeight = getDisplay(context).height / 2
- editText.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
- override fun onGlobalLayout() {
- editText.viewTreeObserver.removeOnGlobalLayoutListener(this)
- val params = editText.layoutParams as LinearLayout.LayoutParams
- if (editText.lineCount <= 1) {
- params.height = mHeight
- } else {
- var tempHeight = mHeight
- for (i in 0..editText.lineCount) {
- tempHeight += mHeight / 2 - 20
- }
- params.height = if (tempHeight >= maxHeight) maxHeight else tempHeight
- }
- editText.layoutParams = params
- }
- })
- editText.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
- override fun afterTextChanged(p0: Editable?) {}
-
- override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
- val params = editText.layoutParams as LinearLayout.LayoutParams
- if (editText.lineCount <= 1) {
- params.height = mHeight
- } else {
- var tempHeight = mHeight
- for (i in 0..editText.lineCount) {
- tempHeight += mHeight / 2 - 20
- }
- params.height = if (tempHeight >= maxHeight) maxHeight else tempHeight
- }
- editText.layoutParams = params
- }
- })
- }
- }
-
- private val view by lazy {
- LinearLayout(context).also { linearLayout ->
- linearLayout.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
- linearLayout.orientation = LinearLayout.VERTICAL
- linearLayout.addView(message)
- linearLayout.addView(editText)
- }
- }
-
- var bView: LinearLayout
-
- private val root = RelativeLayout(context).also { viewRoot ->
- viewRoot.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)
- viewRoot.addView(LinearLayout(context).also { viewLinearLayout ->
- viewLinearLayout.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
- viewLinearLayout.orientation = LinearLayout.VERTICAL
- viewLinearLayout.addView(title)
- viewLinearLayout.addView(view)
- viewLinearLayout.addView(LinearLayout(context).also { linearLayout ->
- linearLayout.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
- it.gravity = Gravity.CENTER_HORIZONTAL
- }
- linearLayout.orientation = LinearLayout.VERTICAL
- linearLayout.setPadding(0, dp2px(context, 10f), 0, dp2px(context, 20f))
- bView = linearLayout
- })
- })
- }
-
- fun Button(text: CharSequence?, enable: Boolean = true, cancelStyle: Boolean = false, callBacks: (View) -> Unit) {
- bView.addView(Button(context).also { buttonView ->
- buttonView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dp2px(context, 50f), 1f).also {
- it.setMargins(dp2px(context, 20f), dp2px(context, 10f), dp2px(context, 20f), 0)
- it.gravity = Gravity.CENTER
- }
- buttonView.setTextColor(context.getColor(if (cancelStyle) R.color.whiteText else R.color.white))
- buttonView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17f)
- buttonView.text = text
- buttonView.isEnabled = enable
- buttonView.stateListAnimator = null
- buttonView.background = context.getDrawable(if (cancelStyle) R.drawable.l_button_background else R.drawable.r_button_background)
- buttonView.setOnClickListener {
- callBacks(it)
- }
- })
- }
-
- init {
- window?.setGravity(Gravity.BOTTOM)
- setContentView(root)
- window?.setBackgroundDrawable(GradientDrawable().apply {
- cornerRadius = dp2px(context, 30f).toFloat()
- setColor(context.getColor(R.color.dialog_background))
- })
- }
-
- fun addView(mView: View) {
- view.addView(mView)
- }
-
- override fun setTitle(title: CharSequence?) {
- this.title.text = title
- }
-
- override fun setTitle(titleId: Int) {
- this.title.setText(titleId)
- }
-
- override fun show() {
- build()
- window!!.setWindowAnimations(R.style.DialogAnim)
- super.show()
- val layoutParams = window!!.attributes
- layoutParams.dimAmount = 0.3F
- layoutParams.width = getDisplay(context).width - dp2px(context, 25f)
- layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
- layoutParams.verticalMargin = 0.02F
- window!!.attributes = layoutParams
- }
-
- fun setMessage(textId: Int) {
- message.apply {
- setText(textId)
- visibility = View.VISIBLE
- }
- }
-
- fun setMessage(text: CharSequence?) {
- message.apply {
- this.text = text
- visibility = View.VISIBLE
- }
- }
-
- fun setEditText(text: String, hint: String, editCallBacks: ((String) -> Unit)? = null) {
- editText.apply {
- setText(text.toCharArray(), 0, text.length)
- this.hint = hint
- visibility = View.VISIBLE
- editCallBacks?.let {
- addTextChangedListener(object : TextWatcher {
- override fun afterTextChanged(var1: Editable?) {
- it(var1.toString())
- }
-
- override fun beforeTextChanged(var1: CharSequence?, var2: Int, var3: Int, var4: Int) {}
- override fun onTextChanged(var1: CharSequence?, var2: Int, var3: Int, var4: Int) {}
- })
- }
- }
- }
-
- fun getEditText(): String = editText.text.toString()
-}
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/view/SeekBarWithTitleView.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/view/SeekBarWithTitleView.kt
deleted file mode 100644
index a2585a3a..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/view/SeekBarWithTitleView.kt
+++ /dev/null
@@ -1,180 +0,0 @@
-package com.gswxxn.restoresplashscreen.view
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.BitmapShader
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Shader
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.LayerDrawable
-import android.view.Gravity
-import android.view.View
-import android.view.ViewGroup
-import android.widget.LinearLayout
-import android.widget.SeekBar
-import android.widget.TextView
-import cn.fkj233.ui.activity.data.DataBinding
-import cn.fkj233.ui.activity.data.LayoutPair
-import cn.fkj233.ui.activity.data.Padding
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.view.BaseView
-import cn.fkj233.ui.activity.view.LinearContainerV
-import cn.fkj233.ui.activity.view.TextSummaryV
-import cn.fkj233.ui.activity.view.TextV
-import com.gswxxn.restoresplashscreen.R
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-class SeekBarWithTitleView(
- private val titleID: Int,
- private val pref: PrefsData? = null,
- private val min: Int,
- private val max: Int,
- private val defaultProgress: Int,
- private val isPercentage: Boolean,
- private val progressColor: Int,
- private val drawHuePanel: Boolean,
- private val dataBindingRecv: DataBinding.Binding.Recv? = null,
- private val dataBindingSend: DataBinding.Binding.Send? = null,
- private val onProgressChanged: ((value: Int) -> Unit)? = null
-): BaseView {
-
- companion object {
- lateinit var huePanel: Drawable
- /** 判断 [huePanel] 是否被初始化 */
- fun isHuePanelInitialized() = ::huePanel.isInitialized
- }
-
- lateinit var context: Context
-
- private fun drawHuePanel() {
- if (isHuePanelInitialized()) return
- val bitmap = Bitmap.createBitmap(context.resources.displayMetrics.widthPixels - dp2px(context, 60f) + 1, dp2px(context, 31f), Bitmap.Config.ARGB_8888)
- val canvas = Canvas(bitmap)
- val hueColors = IntArray(bitmap.width)
- val paint = Paint().apply { strokeWidth = 0.0f }
-
- var h = 0f
- for (i in hueColors.indices) {
- hueColors[i] = Color.HSVToColor(floatArrayOf(h, 1.0f, 1.0f))
- h += 360.0f / hueColors.size.toFloat()
- }
-
- for (i in hueColors.indices) {
- paint.color = hueColors[i]
- canvas.drawLine(
- i.toFloat(),
- 0f,
- i.toFloat(),
- bitmap.height.toFloat(),
- paint)
- }
-
- val roundCornerBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
- canvas.apply { setBitmap(roundCornerBitmap) }.drawRoundRect(
- 0f,
- 0f,
- bitmap.width.toFloat(),
- bitmap.height.toFloat(),
- bitmap.height.toFloat() / 2,
- bitmap.height.toFloat() / 2,
- paint.apply {
- isAntiAlias = true
- shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
- }
- )
- huePanel = BitmapDrawable(context.resources, roundCornerBitmap)
- }
-
- override fun getType(): BaseView = this
-
- @SuppressLint("SetTextI18n")
- override fun create(context: Context, callBacks: (() -> Unit)?): View {
- this.context = context
- if (drawHuePanel) drawHuePanel()
-
- val statusTextView = TextV(
- if (isPercentage) "$defaultProgress% / $max%" else "$defaultProgress / $max",
- textSize = 13.75f,
- colorId = cn.fkj233.ui.R.color.author_tips,
- padding = Padding(0, 0, 0, 0)
- ).create(context, null) as TextView
-
- val titleTextView = LinearContainerV(LinearContainerV.HORIZONTAL, arrayOf(
- LayoutPair(
- TextSummaryV(context.getString(titleID)).apply { notShowMargins(true) }.create(context, null),
- LinearLayout.LayoutParams(
- 0,
- LinearLayout.LayoutParams.WRAP_CONTENT,
- 1f
- )
- ),
- LayoutPair(
- statusTextView,
- LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { it.gravity = Gravity.CENTER_VERTICAL }
- )
- ), layoutParams = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- ).apply {
- setMargins(0, dp2px(context, 17.75f),0, dp2px(context, 10f))
- }).create(context, null)
-
- val seekBar = SeekBar(context).also { view ->
- view.thumb = if (drawHuePanel) context.getDrawable(R.drawable.thumb_seek) else null
- view.splitTrack = false
- view.maxHeight = dp2px(context, 30f)
- view.minHeight = dp2px(context, 30f)
- view.background = null
- view.isIndeterminate = false
-
- view.progressDrawable = (context.getDrawable(cn.fkj233.ui.R.drawable.seekbar_progress_drawable) as LayerDrawable).apply {
- if (drawHuePanel) setDrawable(0, huePanel)
- ((getDrawable(1) as ClipDrawable).drawable as GradientDrawable).setColor(if (drawHuePanel) 0 else progressColor)
- }
- view.min = min
- view.max = max
- view.layoutParams = ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- view.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
- onProgressChanged?.let { it(p1) }
- dataBindingSend?.send(p1)
- statusTextView.text = if (isPercentage) "$p1% / $max%" else "$p1 / $max"
- pref?.let { context.prefs().edit { put(it, p1) } }
- }
- override fun onStartTrackingTouch(p0: SeekBar?) {}
- override fun onStopTrackingTouch(seekBar: SeekBar?) {}
- })
- view.setPadding(0, 0, 0, 0)
- view.invalidate()
- }
-
- val progress = pref?.let { context.prefs().get(it) } ?: defaultProgress
- statusTextView.text = if (isPercentage) "$progress% / $max%" else "$progress / $max"
- seekBar.progress = progress
-
- return LinearContainerV(
- LinearContainerV.VERTICAL,
- arrayOf(
- LayoutPair(titleTextView, LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
- it.setMargins(0, dp2px(context, 15.75f), 0, dp2px(context, 15.75f))
- }),
- LayoutPair(seekBar, LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
- it.setMargins(0, 0, 0, dp2px(context, 15.75f))
- })
- ),
- layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
- ).create(context, callBacks).also {
- dataBindingRecv?.setView(it)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/view/SwitchView.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/view/SwitchView.kt
deleted file mode 100644
index 392073a2..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/view/SwitchView.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * BlockMIUI
- * Copyright (C) 2022 fkj@fkj233.cn
- * https://github.com/577fkj/BlockMIUI
- *
- * This software is free opensource software: you can redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public License v2.1
- * as published by the Free Software Foundation; either
- * version 3 of the License, or any later version and our eula as published
- * by 577fkj.
- *
- * 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
- * GNU Lesser General Public License v2.1 for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License v2.1
- * and eula along with this software. If not, see
- *
- * .
- */
-
-package com.gswxxn.restoresplashscreen.view
-
-
-import android.content.Context
-import android.view.View
-import android.widget.Toast
-import cn.fkj233.ui.activity.data.DataBinding
-import cn.fkj233.ui.activity.view.BaseView
-import cn.fkj233.ui.switch.MIUISwitch
-import com.gswxxn.restoresplashscreen.R
-import com.highcapable.yukihookapi.YukiHookAPI
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
-
-/**
- * 改自 BlockMIUI, 为了适配 YukiHookAPI 的配置存储方式, 后续可能通过反射实现而不是把这个类复制过来
- */
-class SwitchView(
- private val pref: PrefsData,
- private val dataBindingRecv: DataBinding.Binding.Recv? = null,
- private val dataBindingSend: DataBinding.Binding.Send? = null,
- private val onClickListener: ((Boolean) -> Unit)? = null
-): BaseView {
- private lateinit var context : Context
-
- lateinit var switch: MIUISwitch
-
- override fun getType(): BaseView = this
-
- override fun create(context: Context, callBacks: (() -> Unit)?): View {
- return MIUISwitch(context).also {
- switch = it
- dataBindingRecv?.setView(it)
- this.context = context
- it.isChecked = context.prefs().get(pref)
- it.setOnCheckedChangeListener { v, b ->
- if (!YukiHookAPI.Status.isXposedModuleActive) {
- v.isChecked = !b
- Toast.makeText(context, R.string.make_sure_active, Toast.LENGTH_SHORT).show()
- } else {
- dataBindingSend?.let { send ->
- send.send(b)
- }
- callBacks?.let { it1 -> it1() }
- onClickListener?.let { it(b) }
- context.prefs().edit { put(pref, b) }
- }
- }
- }
- }
-
- /** 切换开关状态 */
- fun click() { switch.isChecked = !switch.isChecked }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gswxxn/restoresplashscreen/view/TextSummaryWithSwitchView.kt b/app/src/main/java/com/gswxxn/restoresplashscreen/view/TextSummaryWithSwitchView.kt
deleted file mode 100644
index 4c0b7e09..00000000
--- a/app/src/main/java/com/gswxxn/restoresplashscreen/view/TextSummaryWithSwitchView.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * BlockMIUI
- * Copyright (C) 2022 fkj@fkj233.cn
- * https://github.com/577fkj/BlockMIUI
- *
- * This software is free opensource software: you can redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public License v2.1
- * as published by the Free Software Foundation; either
- * version 3 of the License, or any later version and our eula as published
- * by 577fkj.
- *
- * 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
- * GNU Lesser General Public License v2.1 for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License v2.1
- * and eula along with this software. If not, see
- *
- * .
- */
-
-package com.gswxxn.restoresplashscreen.view
-
-import android.content.Context
-import android.view.Gravity
-import android.view.View
-import android.widget.LinearLayout
-import cn.fkj233.ui.activity.data.DataBinding
-import cn.fkj233.ui.activity.data.LayoutPair
-import cn.fkj233.ui.activity.dp2px
-import cn.fkj233.ui.activity.view.BaseView
-import cn.fkj233.ui.activity.view.LinearContainerV
-import cn.fkj233.ui.activity.view.TextSummaryV
-
-/**
- * 改自 BlockMIUI, 为了将适应 [SwitchView]
- */
-class TextSummaryWithSwitchView(private val textV: TextSummaryV, val switchV: SwitchView, private val dataBindingRecv: DataBinding.Binding.Recv? = null): BaseView {
-
- override fun getType(): BaseView = this
-
- override fun create(context: Context, callBacks: (() -> Unit)?): View {
- textV.notShowMargins(true)
- return LinearContainerV(
- LinearContainerV.HORIZONTAL,
- arrayOf(
- LayoutPair(textV.create(context, callBacks), LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)),
- LayoutPair(switchV.create(context, callBacks), LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { it.gravity = Gravity.CENTER_VERTICAL })
- ),
- layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT).also {
- it.setMargins(0, dp2px(context, 17.75f),0, dp2px(context, 17.75f))
- }
- ).create(context, callBacks).also {
- dataBindingRecv?.setView(it)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/demo_transparency.xml b/app/src/main/res/drawable/demo_transparency.xml
index 6b70cf58..3e8e86ab 100644
--- a/app/src/main/res/drawable/demo_transparency.xml
+++ b/app/src/main/res/drawable/demo_transparency.xml
@@ -1,20 +1,24 @@
-
-
-
-
+ android:width="326dp"
+ android:height="662dp"
+ android:viewportWidth="326"
+ android:viewportHeight="662">
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/img_github.xml b/app/src/main/res/drawable/img_github.xml
index 7b9b6a75..3939af5d 100644
--- a/app/src/main/res/drawable/img_github.xml
+++ b/app/src/main/res/drawable/img_github.xml
@@ -5,5 +5,5 @@
android:viewportHeight="1024">
+ android:fillColor="@color/colorTextGray"/>
diff --git a/app/src/main/res/values-night/app_splash.xml b/app/src/main/res/values-night/app_splash.xml
new file mode 100644
index 00000000..a40049d5
--- /dev/null
+++ b/app/src/main/res/values-night/app_splash.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/color.xml b/app/src/main/res/values-night/color.xml
index 18f59013..2f2d3bd2 100644
--- a/app/src/main/res/values-night/color.xml
+++ b/app/src/main/res/values-night/color.xml
@@ -1,7 +1,7 @@
#FF000000
- #FF2D2D2D
+ #FF242424
#FFCFCFCF
#FFD3D3D3
diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml
index f697806c..26bbed47 100644
--- a/app/src/main/res/values/color.xml
+++ b/app/src/main/res/values/color.xml
@@ -1,7 +1,7 @@
#FFFFFFFF
- #FFF5F5F5
+ #FFFFFFFF
#FF777777
#FF323B42
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 95bd51f4..4bb77ec3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
Activated by %s API %d
做出任何设置前,请确保模块已激活。\n修改设置后立即生效,无需重启。
+ 重启
重启提示
模块更新后需要重启系统界面才能生效。\n\n如果您 LSPosed 框架中的作用域包含系统框架,则需要重启手机
重启手机
@@ -34,6 +35,7 @@
显示
开发者选项
Hook 信息
+
常见问题
https://gswxxn.coding.net/public/restoresplashscreen/faq/git
@@ -42,6 +44,9 @@
启用日志
启用日志 24 小时后自动关闭
隐藏桌面图标
+ 模糊效果
+ 自适应布局
+ 在大屏幕设备上或横屏时,应用程序将自动切换到双面板布局
遮罩最小持续时长
注意:设置此参数会拖慢应用启动时间。如无特殊需求,则不应配置此项。
备份与恢复
@@ -159,7 +164,10 @@
明度
撤销本次修改
恢复默认
-
+ 颜色生效模式
+ 当前颜色的生效模式,浅色模式和深色模式需要分别配置
+ 浅色模式
+ 深色模式
v%s
点个关注,不迷路
@@ -174,5 +182,9 @@
+ 浅色模式着色不透明度
+ 深色模式着色不透明度
+ 不透明度应该是 0 到 100 之间的整数,值为 0 时最透明。
+ 空
图标圆角率
diff --git a/blockmiui b/blockmiui
deleted file mode 160000
index 614d90d5..00000000
--- a/blockmiui
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 614d90d5a759ff7f8849f9e889cb3ca707b36069
diff --git a/build.gradle.kts b/build.gradle.kts
index e18577bb..3a79deb4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,5 @@
plugins {
autowire(libs.plugins.com.android.application) apply false
autowire(libs.plugins.org.jetbrains.kotlin.android) apply false
+ autowire(libs.plugins.org.jetbrains.kotlin.plugin.compose) apply false
}
diff --git a/gradle/sweet-dependency/sweet-dependency-config.yaml b/gradle/sweet-dependency/sweet-dependency-config.yaml
index ffb214a7..e660b68a 100644
--- a/gradle/sweet-dependency/sweet-dependency-config.yaml
+++ b/gradle/sweet-dependency/sweet-dependency-config.yaml
@@ -25,10 +25,12 @@ plugins:
version: 8.7.3
org.jetbrains.kotlin.android:
version: 2.1.0
- org.jetbrains.kotlin.plugin.serialization:
- version: 2.1.0
com.google.devtools.ksp:
version: 2.1.0-1.0.29
+ org.jetbrains.kotlin.plugin.compose:
+ version: 2.1.0
+ org.jetbrains.kotlin.plugin.serialization:
+ version: 2.1.0
libraries:
de.robv.android.xposed:
diff --git a/hyperx-compose b/hyperx-compose
new file mode 160000
index 00000000..e4c30cb7
--- /dev/null
+++ b/hyperx-compose
@@ -0,0 +1 @@
+Subproject commit e4c30cb7b3499375e3d9817ff2ef2aa38b37adca
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f9197935..88aeed90 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -33,4 +33,4 @@ sweetProperty {
}
}
rootProject.name = "RestoreSplashScreen"
-include(":app", ":blockmiui")
+include(":app", ":hyperx-compose")