From 6a78eb8ad717e6765440dc210b83eb7f8c76be12 Mon Sep 17 00:00:00 2001 From: howie Date: Fri, 6 Dec 2024 17:05:41 +0800 Subject: [PATCH 1/7] refactor: now we use Compose! --- .gitmodules | 3 + app/build.gradle.kts | 14 +- app/gradle.properties | 4 +- app/src/main/AndroidManifest.xml | 22 +- .../restoresplashscreen/data/DataConst.kt | 6 + .../gswxxn/restoresplashscreen/data/Pages.kt | 24 + .../hook/systemui/IconHookHandler.kt | 7 +- .../ui/AboutPageActivity.kt | 187 --- .../restoresplashscreen/ui/BaseActivity.kt | 62 - .../ui/ColorSelectActivity.kt | 427 ------- .../ui/ConfigAppsActivity.kt | 228 ---- .../restoresplashscreen/ui/MainActivity.kt | 152 +++ .../ui/MainSettingsActivity.kt | 190 --- .../restoresplashscreen/ui/SubSettings.kt | 61 - .../ui/apppage/BackgroundExceptPage.kt | 22 + .../ui/apppage/BgIndividualPage.kt | 301 +++++ .../ui/apppage/CustomScopePage.kt | 49 + .../ui/apppage/ForceSplashPage.kt | 22 + .../ui/apppage/HideIconPage.kt | 49 + .../ui/apppage/IgnoreAppIconPage.kt | 49 + .../ui/apppage/MinDurationPage.kt | 527 ++++++++ .../ui/apppage/RemoveBrandingPage.kt | 49 + .../ui/component/AppListPage.kt | 547 ++++++++ .../ui/component/ColorPickerPage.kt | 1129 +++++++++++++++++ .../ui/component/HeaderCard.kt | 83 ++ .../ui/configapps/BGColorIndividualConfig.kt | 98 -- .../ui/configapps/BackgroundExcept.kt | 16 - .../ui/configapps/BrandingImage.kt | 47 - .../ui/configapps/CustomScope.kt | 47 - .../ui/configapps/DefaultStyle.kt | 47 - .../ui/configapps/ForceShowSplashScreen.kt | 16 - .../ui/configapps/HideSplashScreenIcon.kt | 43 - .../ui/configapps/MinDuration.kt | 106 -- .../ui/interface/IConfigApps.kt | 158 --- .../ui/interface/ISubSettings.kt | 38 - .../restoresplashscreen/ui/page/AboutPage.kt | 289 +++++ .../ui/page/BackgroundPage.kt | 169 +++ .../restoresplashscreen/ui/page/BasicPage.kt | 146 +++ .../restoresplashscreen/ui/page/BottomPage.kt | 77 ++ .../restoresplashscreen/ui/page/DevPage.kt | 169 +++ .../ui/page/DisplayPage.kt | 129 ++ .../restoresplashscreen/ui/page/IconPage.kt | 203 +++ .../restoresplashscreen/ui/page/MainPage.kt | 338 +++++ .../restoresplashscreen/ui/page/ScopePage.kt | 85 ++ .../ui/subsettings/BackgroundSettings.kt | 132 -- .../ui/subsettings/BasicSettings.kt | 70 - .../ui/subsettings/BottomSettings.kt | 52 - .../ui/subsettings/CustomScopeSettings.kt | 50 - .../ui/subsettings/DevSettings.kt | 57 - .../ui/subsettings/DisplaySettings.kt | 110 -- .../ui/subsettings/HookInfo.kt | 59 - .../ui/subsettings/IconSettings.kt | 138 -- .../restoresplashscreen/utils/BackupUtils.kt | 63 +- .../utils/BlockMIUIHelper.kt | 186 --- .../restoresplashscreen/utils/GraphicUtils.kt | 2 +- .../restoresplashscreen/utils/YukiHelper.kt | 16 + .../view/BlockMIUIItemData.kt | 111 -- .../restoresplashscreen/view/NewMIUIDialog.kt | 236 ---- .../view/SeekBarWithTitleView.kt | 180 --- .../restoresplashscreen/view/SwitchView.kt | 76 -- .../view/TextSummaryWithSwitchView.kt | 58 - .../main/res/drawable/demo_transparency.xml | 40 +- app/src/main/res/drawable/img_github.xml | 2 +- app/src/main/res/values-night/app_splash.xml | 8 + app/src/main/res/values-night/color.xml | 2 +- app/src/main/res/values/color.xml | 2 +- app/src/main/res/values/strings.xml | 14 +- build.gradle.kts | 1 + .../sweet-dependency-config.yaml | 17 +- hyperx-compose | 1 + settings.gradle.kts | 1 + 71 files changed, 4741 insertions(+), 3378 deletions(-) create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/data/Pages.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/AboutPageActivity.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/BaseActivity.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/ColorSelectActivity.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/ConfigAppsActivity.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainSettingsActivity.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/SubSettings.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BGColorIndividualConfig.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BackgroundExcept.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/BrandingImage.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/CustomScope.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/DefaultStyle.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/ForceShowSplashScreen.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/HideSplashScreenIcon.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/configapps/MinDuration.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/IConfigApps.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/interface/ISubSettings.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt create mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BackgroundSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BasicSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/BottomSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/CustomScopeSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DevSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/DisplaySettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/HookInfo.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/ui/subsettings/IconSettings.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/utils/BlockMIUIHelper.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/view/BlockMIUIItemData.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/view/NewMIUIDialog.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/view/SeekBarWithTitleView.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/view/SwitchView.kt delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/view/TextSummaryWithSwitchView.kt create mode 100644 app/src/main/res/values-night/app_splash.xml create mode 160000 hyperx-compose diff --git a/.gitmodules b/.gitmodules index b12ee233..19d8b01b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [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..53786e46 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,22 @@ 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(androidx.activity.activity.compose) + implementation(androidx.navigation.navigation.compose) + implementation(androidx.compose.foundation.foundation) + + 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..873facb4 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 = 3001 +project.versionName = "3.0-compose" \ 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..99f8bb9d --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt @@ -0,0 +1,152 @@ +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 -> + MainPage(navController, adjustPadding) + }, + 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 -> +// composable(Pages.MODULE_SETTINGS) { ModuleSettingsPage(navController, adjustPadding) } + composable(Pages.ABOUT) { AboutPage(navController, adjustPadding) } + composable(Pages.BASIC_SETTINGS) { BasicPage(navController, adjustPadding) } + composable(Pages.SCOPE_SETTINGS) { ScopePage(navController, adjustPadding) } + composable(Pages.ICON_SETTINGS) { IconPage(navController, adjustPadding) } + composable(Pages.BOTTOM_SETTINGS) { BottomPage(navController, adjustPadding) } + composable(Pages.BACKGROUND_SETTINGS) { BackgroundPage(navController, adjustPadding) } + composable(Pages.DISPLAY_SETTINGS) { DisplayPage(navController, adjustPadding) } + composable(Pages.DEVELOPER_SETTINGS) { DevPage(navController, adjustPadding) } + + composable(Pages.CONFIG_CUSTOM_SCOPE) { CustomScopePage(navController, adjustPadding) } + composable(Pages.CONFIG_IGNORE_APP_ICON) { IgnoreAppIconPage(navController, adjustPadding) } + composable(Pages.CONFIG_HIDE_SPLASH_ICON) { HideIconPage(navController, adjustPadding) } + composable(Pages.CONFIG_REMOVE_BRANDING) { RemoveBrandingPage(navController, adjustPadding) } + composable(Pages.CONFIG_BACKGROUND_EXCEPT) { BackgroundExceptPage(navController, adjustPadding) } + composable(Pages.CONFIG_BACKGROUND_INDIVIDUALLY) { BgIndividualPage(navController, adjustPadding) } + composable(Pages.CONFIG_MIN_DURATION) { MinDurationPage(navController, adjustPadding) } + composable(Pages.CONFIG_FORCE_SHOW_SPLASH) { ForceSplashPage(navController, adjustPadding) } + + 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) + } +// composable(Pages.DEV_UI_TEST) { UITestPage(navController, adjustPadding) } + } + ) + } +} \ 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..59c676be --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt @@ -0,0 +1,22 @@ +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 + +/** + * 背景 - 替换背景颜色 - 排除列表 + */ +@Composable +fun BackgroundExceptPage(navController: NavController, adjustPadding: PaddingValues) { + AppListPage( + navController, + adjustPadding, + stringResource(R.string.background_except_title), + DataConst.BG_EXCEPT_LIST.key + ) +} \ 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..2c0de945 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt @@ -0,0 +1,301 @@ +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.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +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.windowInsetsPadding +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.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, + 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 } + } + } + } + } + + 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(start = 21.dp) + .size(40.dp), + onClick = { + navController.popBackStack() + } + ) { + Icon( + modifier = Modifier.size(26.dp), + imageVector = MiuixIcons.Back, + contentDescription = "Back", + tint = MiuixTheme.colorScheme.onSurfaceSecondary + ) + } + }, + 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) + .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) + .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + 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..f628d4cd --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt @@ -0,0 +1,49 @@ +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.preference.PreferenceGroup +import dev.lackluster.hyperx.compose.preference.SwitchPreference + +/** + * 作用域 - 自定义模块作用域 - 配置应用列表 + */ +@Composable +fun CustomScopePage(navController: NavController, adjustPadding: PaddingValues) { + 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 + ) { + 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..b31006ba --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt @@ -0,0 +1,22 @@ +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 + +/** + * 实验功能 - 强制显示遮罩 - 配置应用列表 + */ +@Composable +fun ForceSplashPage(navController: NavController, adjustPadding: PaddingValues) { + AppListPage( + navController, + adjustPadding, + stringResource(R.string.force_show_splash_screen_title), + DataConst.FORCE_SHOW_SPLASH_SCREEN_LIST.key + ) +} \ 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..37ea6a3e --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt @@ -0,0 +1,49 @@ +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.preference.PreferenceGroup +import dev.lackluster.hyperx.compose.preference.SwitchPreference + +/** + * 图标 - 不显示图标 + */ +@Composable +fun HideIconPage(navController: NavController, adjustPadding: PaddingValues) { + 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 + ) { + 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..bdef582e --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt @@ -0,0 +1,49 @@ +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.preference.PreferenceGroup +import dev.lackluster.hyperx.compose.preference.SwitchPreference + +/** + * 图标 - 忽略应用主动谁知的图标 - 配置应用列表 + */ +@Composable +fun IgnoreAppIconPage(navController: NavController, adjustPadding: PaddingValues) { + 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 + ) { + 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..10104214 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt @@ -0,0 +1,527 @@ +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.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.windowInsetsPadding +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.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.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.TextButton +import top.yukonga.miuix.kmp.basic.TopAppBar +import top.yukonga.miuix.kmp.basic.rememberTopAppBarState +import top.yukonga.miuix.kmp.extra.SuperArrow +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, + 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 } + sortBy { 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 } + sortBy { it.config.value != null } + sortByDescending { it.isChecked.value } + } + } + } + } + + 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(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 + ) + } + }, + 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) + .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) + .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + 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, + defValue = item.config.value?.toIntOrNull() ?: 0, + dialogMessage = dialogMessage + ) { text, value -> + if (value == 0) { + item.isChecked.value = false + item.config.value = null + } else { + item.isChecked.value = true + 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, + 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) } + } + } + SuperArrow( + title = title, + summary = summary, + leftAction = { + icon?.let { + DrawableResIcon(it) + } + }, + rightText = stringValue, + 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..ab6a5c60 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt @@ -0,0 +1,49 @@ +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.preference.PreferenceGroup +import dev.lackluster.hyperx.compose.preference.SwitchPreference + +/** + * 底部 - 移除底部图片 - 配置移除列表 + */ +@Composable +fun RemoveBrandingPage(navController: NavController, adjustPadding: PaddingValues) { + 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 + ) { + 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..46c0516b --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt @@ -0,0 +1,547 @@ +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.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.windowInsetsPadding +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.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?, + 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 } + } + } + } + } + + HazeScaffold( + modifier = Modifier.fillMaxSize(), + topBar = { contentPadding -> + TopAppBar( + color = topAppBarBackground.copy( + if (topBarBlurState) 0f else 1f + ), + title = title, + scrollBehavior = scrollBehavior, + navigationIcon = { + IconButton( + modifier = Modifier + .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(end = 21.dp) + .size(40.dp), + onClick = { + isTopPopupExpanded.value = true + } + ) { + Icon( + imageVector = MiuixIcons.ImmersionMore, + contentDescription = "Menu" + ) + } + } + }, + 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) + .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) + .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + 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..6b438b3e --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt @@ -0,0 +1,1129 @@ +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.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.width +import androidx.compose.foundation.layout.windowInsetsPadding +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.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, + 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) + } + } + + HazeScaffold( + modifier = Modifier.fillMaxSize(), + topBar = { contentPadding -> + TopAppBar( + color = topAppBarBackground.copy( + if (topBarBlurState) 0f else 1f + ), + title = appName, + scrollBehavior = scrollBehavior, + navigationIcon = { + IconButton( + modifier = Modifier + .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 + ) + } + }, + 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) + .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) + .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + 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) + 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 = px32dp + image.width + (constraints.maxWidth - px32dp - 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..f4897146 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt @@ -0,0 +1,83 @@ +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.ui.Modifier +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 +) { + 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) + ) { + Layout( + content = { + Image( + modifier = Modifier, + painter = painterResource(imageResID), + contentDescription = null + ) + Text( + text = title, + textAlign = TextAlign.Center, + style = TextStyle( + fontSize = 30.sp, + fontWeight = FontWeight.SemiBold, + shadow = Shadow( + color = Color.Black.copy(alpha = 0.1f), + offset = offset, + blurRadius = blurRadius + ) + ) + ) + } + ) { 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) + val totalHeight = max(image.height, text.height) + px32dp + layout(constraints.maxWidth, totalHeight) { + image.place(px16dp, (totalHeight - image.height) / 2) + val rightCenterX = px32dp + image.width + (constraints.maxWidth - px32dp - 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..4be6ba80 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt @@ -0,0 +1,289 @@ +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.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) { + 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, + ) { + 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..2ba81530 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt @@ -0,0 +1,169 @@ +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.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) { + 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, + ) { + item { + HeaderCard( + imageResID = R.drawable.demo_basic, + 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..d52cdf9d --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt @@ -0,0 +1,146 @@ +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.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) { + 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, + ) { + 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..7bd3959f --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt @@ -0,0 +1,77 @@ +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.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) { + 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, + ) { + item { + HeaderCard( + imageResID = R.drawable.demo_branding, + title = "BRANDING IMAGE" + ) + } + 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..c781c623 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt @@ -0,0 +1,169 @@ +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.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) { + 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, + ) { + 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..a5ab6c43 --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt @@ -0,0 +1,129 @@ +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.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) { + 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, + ) { + 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..308bce3a --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt @@ -0,0 +1,203 @@ +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.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) { + 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, + ) { + 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..14ad04be --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt @@ -0,0 +1,338 @@ +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.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.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) { + 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, + navigationIcon = {}, + actions = { + 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(end = 21.dp).size(40.dp), + onClick = { + isTopPopupExpanded.value = true + } + ) { + 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..0d13ec1b --- /dev/null +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt @@ -0,0 +1,85 @@ +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.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) { + 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, + ) { + 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/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/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..231bd33c 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: @@ -52,4 +54,13 @@ libraries: version: 1.7.3 androidx.annotation: annotation: - version: 1.9.1 \ No newline at end of file + version: 1.9.1 + androidx.activity: + activity-compose: + version: 1.9.3 + androidx.navigation: + navigation-compose: + version: 2.8.4 + androidx.compose.foundation: + foundation: + version: 1.7.5 \ No newline at end of file diff --git a/hyperx-compose b/hyperx-compose new file mode 160000 index 00000000..c44c5908 --- /dev/null +++ b/hyperx-compose @@ -0,0 +1 @@ +Subproject commit c44c590857f2e32006b50e9bd0e5ac9fcd2d4416 diff --git a/settings.gradle.kts b/settings.gradle.kts index f9197935..b4d9c8c5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,3 +34,4 @@ sweetProperty { } rootProject.name = "RestoreSplashScreen" include(":app", ":blockmiui") +include(":app", ":hyperx-compose") From 1040992c28bb81533e7aac487fc7620e89a5c714 Mon Sep 17 00:00:00 2001 From: howie Date: Fri, 6 Dec 2024 17:45:59 +0800 Subject: [PATCH 2/7] fix: fix the text of the HeaderCard is not center aligned; --- app/gradle.properties | 2 +- .../ui/component/ColorPickerPage.kt | 6 +- .../ui/component/HeaderCard.kt | 44 ++++++--- .../ui/page/BackgroundPage.kt | 2 +- .../utils/AppInfoHelper.kt | 95 ------------------- settings.gradle.kts | 1 - 6 files changed, 39 insertions(+), 111 deletions(-) delete mode 100644 app/src/main/java/com/gswxxn/restoresplashscreen/utils/AppInfoHelper.kt diff --git a/app/gradle.properties b/app/gradle.properties index 873facb4..b980d977 100644 --- a/app/gradle.properties +++ b/app/gradle.properties @@ -6,4 +6,4 @@ project.targetSdk=35 project.minSdk=31 project.versionCode = 3001 -project.versionName = "3.0-compose" \ No newline at end of file +project.versionName = "3.1-compose" \ 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 index 6b438b3e..9d3d6a41 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt @@ -542,7 +542,9 @@ fun ColorPickerPage( minWidth = px48dp, maxWidth = px48dp )) val rightWidth = constraints.maxWidth - image.width - px48dp - val text = measurables[2].measure(constraints) + val text = measurables[2].measure(constraints.copy( + maxWidth = rightWidth + )) val colorCount = measurables.size - 3 var colorPerRow = 1 val colorLines: Int @@ -571,7 +573,7 @@ fun ColorPickerPage( px16dp + image.width / 2 - icon.width / 2, totalHeight / 2 - icon.height / 2 ) - val rightCenterX = px32dp + image.width + (constraints.maxWidth - px32dp - image.width) / 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) { 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 index f4897146..dda6698e 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt @@ -4,7 +4,12 @@ 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 @@ -37,6 +42,18 @@ fun HeaderCard( .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( @@ -45,17 +62,20 @@ fun HeaderCard( contentDescription = null ) Text( + modifier = Modifier + .drawWithContent { + if (readyToDraw) drawContent() + }, text = title, textAlign = TextAlign.Center, - style = TextStyle( - fontSize = 30.sp, - fontWeight = FontWeight.SemiBold, - shadow = Shadow( - color = Color.Black.copy(alpha = 0.1f), - offset = offset, - blurRadius = blurRadius - ) - ) + style = textStyle, + onTextLayout = { textLayoutResult -> + if (textLayoutResult.didOverflowWidth && textLayoutResult.lineCount == 1) { + textStyle = textStyle.copy(fontSize = textStyle.fontSize * 0.9) + } else { + readyToDraw = true + } + } ) } ) { measurables, constraints -> @@ -68,11 +88,13 @@ fun HeaderCard( val image = measurables[0].measure(constraints.copy( minHeight = px250dp, maxHeight = px250dp )) - val text = measurables[1].measure(constraints) + 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 = px32dp + image.width + (constraints.maxWidth - px32dp - image.width) / 2 + val rightCenterX = px16dp + image.width + (constraints.maxWidth - px16dp - image.width) / 2 text.place( rightCenterX - text.width / 2, (totalHeight - text.height) / 2 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 index 2ba81530..e0e9db7d 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt @@ -68,7 +68,7 @@ fun BackgroundPage(navController: NavController, adjustPadding: PaddingValues) { ) { item { HeaderCard( - imageResID = R.drawable.demo_basic, + imageResID = R.drawable.demo_background, title = "BACKGROUND" ) } 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/settings.gradle.kts b/settings.gradle.kts index b4d9c8c5..88aeed90 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,5 +33,4 @@ sweetProperty { } } rootProject.name = "RestoreSplashScreen" -include(":app", ":blockmiui") include(":app", ":hyperx-compose") From 0542003907e1a2612cd7039bdfbcbe5950548b9d Mon Sep 17 00:00:00 2001 From: howie Date: Fri, 6 Dec 2024 17:47:42 +0800 Subject: [PATCH 3/7] misc: remove blockmiui --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 19d8b01b..8135687b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +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 From 497c259a04bf887e63162d335e79e9b0d7591631 Mon Sep 17 00:00:00 2001 From: howie Date: Fri, 6 Dec 2024 17:48:30 +0800 Subject: [PATCH 4/7] misc: remove blockmiui --- blockmiui | 1 - 1 file changed, 1 deletion(-) delete mode 160000 blockmiui diff --git a/blockmiui b/blockmiui deleted file mode 160000 index 614d90d5..00000000 --- a/blockmiui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 614d90d5a759ff7f8849f9e889cb3ca707b36069 From 3f9e42f714d6dafb6f91481da0d848baf014c085 Mon Sep 17 00:00:00 2001 From: howie Date: Fri, 6 Dec 2024 18:04:31 +0800 Subject: [PATCH 5/7] fix: restrict the maximum lines of text in the HeadCard; --- .../gswxxn/restoresplashscreen/ui/component/HeaderCard.kt | 8 +++++--- .../com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) 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 index dda6698e..9f75fe96 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/HeaderCard.kt @@ -28,7 +28,8 @@ import kotlin.math.max @Composable fun HeaderCard( imageResID: Int, - title: String + title: String, + maxLines: Int = 1 ) { val offset: Offset val blurRadius: Float @@ -70,12 +71,13 @@ fun HeaderCard( textAlign = TextAlign.Center, style = textStyle, onTextLayout = { textLayoutResult -> - if (textLayoutResult.didOverflowWidth && textLayoutResult.lineCount == 1) { + if (textLayoutResult.didOverflowWidth || textLayoutResult.didOverflowHeight) { textStyle = textStyle.copy(fontSize = textStyle.fontSize * 0.9) } else { readyToDraw = true } - } + }, + maxLines = maxLines ) } ) { measurables, constraints -> 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 index 7bd3959f..0e79b0f9 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt @@ -41,7 +41,8 @@ fun BottomPage(navController: NavController, adjustPadding: PaddingValues) { item { HeaderCard( imageResID = R.drawable.demo_branding, - title = "BRANDING IMAGE" + title = "BRANDING\nIMAGE", + maxLines = 2 ) } item { From 0c66b290145be9e5e397f2509e89babbea69c14b Mon Sep 17 00:00:00 2001 From: howie Date: Wed, 11 Dec 2024 19:42:24 +0800 Subject: [PATCH 6/7] fix: Fix incorrect padding in landscape; --- app/gradle.properties | 2 +- .../restoresplashscreen/ui/MainActivity.kt | 42 ++++++++-------- .../ui/apppage/BackgroundExceptPage.kt | 6 ++- .../ui/apppage/BgIndividualPage.kt | 18 +++++-- .../ui/apppage/CustomScopePage.kt | 6 ++- .../ui/apppage/ForceSplashPage.kt | 6 ++- .../ui/apppage/HideIconPage.kt | 6 ++- .../ui/apppage/IgnoreAppIconPage.kt | 6 ++- .../ui/apppage/MinDurationPage.kt | 50 +++++++++++++++---- .../ui/apppage/RemoveBrandingPage.kt | 6 ++- .../ui/component/AppListPage.kt | 20 ++++++-- .../ui/component/ColorPickerPage.kt | 18 +++++-- .../restoresplashscreen/ui/page/AboutPage.kt | 4 +- .../ui/page/BackgroundPage.kt | 4 +- .../restoresplashscreen/ui/page/BasicPage.kt | 4 +- .../restoresplashscreen/ui/page/BottomPage.kt | 4 +- .../restoresplashscreen/ui/page/DevPage.kt | 4 +- .../ui/page/DisplayPage.kt | 4 +- .../restoresplashscreen/ui/page/IconPage.kt | 4 +- .../restoresplashscreen/ui/page/MainPage.kt | 12 +++-- .../restoresplashscreen/ui/page/ScopePage.kt | 4 +- hyperx-compose | 2 +- 22 files changed, 160 insertions(+), 72 deletions(-) diff --git a/app/gradle.properties b/app/gradle.properties index b980d977..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 = 3001 +project.versionCode = 3100 project.versionName = "3.1-compose" \ 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 index 99f8bb9d..7ddc9c73 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/MainActivity.kt @@ -98,8 +98,8 @@ class MainActivity : HyperXActivity() { override fun AppContent() { HyperXApp( autoSplitView = splitEnabled, - mainPageContent = { navController, adjustPadding -> - MainPage(navController, adjustPadding) + mainPageContent = { navController, adjustPadding, mode -> + MainPage(navController, adjustPadding, mode) }, emptyPageContent = { Box( @@ -114,25 +114,24 @@ class MainActivity : HyperXActivity() { ) } }, - otherPageBuilder = { navController, adjustPadding -> -// composable(Pages.MODULE_SETTINGS) { ModuleSettingsPage(navController, adjustPadding) } - composable(Pages.ABOUT) { AboutPage(navController, adjustPadding) } - composable(Pages.BASIC_SETTINGS) { BasicPage(navController, adjustPadding) } - composable(Pages.SCOPE_SETTINGS) { ScopePage(navController, adjustPadding) } - composable(Pages.ICON_SETTINGS) { IconPage(navController, adjustPadding) } - composable(Pages.BOTTOM_SETTINGS) { BottomPage(navController, adjustPadding) } - composable(Pages.BACKGROUND_SETTINGS) { BackgroundPage(navController, adjustPadding) } - composable(Pages.DISPLAY_SETTINGS) { DisplayPage(navController, adjustPadding) } - composable(Pages.DEVELOPER_SETTINGS) { DevPage(navController, adjustPadding) } + 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) } - composable(Pages.CONFIG_IGNORE_APP_ICON) { IgnoreAppIconPage(navController, adjustPadding) } - composable(Pages.CONFIG_HIDE_SPLASH_ICON) { HideIconPage(navController, adjustPadding) } - composable(Pages.CONFIG_REMOVE_BRANDING) { RemoveBrandingPage(navController, adjustPadding) } - composable(Pages.CONFIG_BACKGROUND_EXCEPT) { BackgroundExceptPage(navController, adjustPadding) } - composable(Pages.CONFIG_BACKGROUND_INDIVIDUALLY) { BgIndividualPage(navController, adjustPadding) } - composable(Pages.CONFIG_MIN_DURATION) { MinDurationPage(navController, adjustPadding) } - composable(Pages.CONFIG_FORCE_SHOW_SPLASH) { ForceSplashPage(navController, adjustPadding) } + 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}?" + @@ -143,9 +142,8 @@ class MainActivity : HyperXActivity() { 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) + ColorPickerPage(navController, adjustPadding, pkgName, keyLight, keyDark, mode) } -// composable(Pages.DEV_UI_TEST) { UITestPage(navController, adjustPadding) } } ) } 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 index 59c676be..d8efed45 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BackgroundExceptPage.kt @@ -7,16 +7,18 @@ 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) { +fun BackgroundExceptPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) { AppListPage( navController, adjustPadding, stringResource(R.string.background_except_title), - DataConst.BG_EXCEPT_LIST.key + 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 index 2c0de945..d4dcfb52 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/BgIndividualPage.kt @@ -8,14 +8,15 @@ 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.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable @@ -49,6 +50,7 @@ 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 @@ -83,6 +85,7 @@ import top.yukonga.miuix.kmp.utils.getWindowSize fun BgIndividualPage( navController: NavController, adjustPadding: PaddingValues, + mode: BasePageDefaults.Mode, blurEnabled: MutableState = MainActivity.blurEnabled, blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight, blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark @@ -159,6 +162,11 @@ fun BgIndividualPage( } } } + 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(), @@ -172,6 +180,7 @@ fun BgIndividualPage( navigationIcon = { IconButton( modifier = Modifier + .padding(navigationIconPadding) .padding(start = 21.dp) .size(40.dp), onClick = { @@ -186,6 +195,7 @@ fun BgIndividualPage( ) } }, + defaultWindowInsetsPadding = false, horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current) ) }, @@ -203,9 +213,7 @@ fun BgIndividualPage( LazyColumn( modifier = Modifier .height(getWindowSize().height.dp) - .background(MiuixTheme.colorScheme.background) - .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) - .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + .background(MiuixTheme.colorScheme.background), state = listState, contentPadding = paddingValues, topAppBarScrollBehavior = scrollBehavior 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 index f628d4cd..da5b760a 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/CustomScopePage.kt @@ -12,6 +12,7 @@ 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 @@ -19,7 +20,7 @@ import dev.lackluster.hyperx.compose.preference.SwitchPreference * 作用域 - 自定义模块作用域 - 配置应用列表 */ @Composable -fun CustomScopePage(navController: NavController, adjustPadding: PaddingValues) { +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, @@ -32,7 +33,8 @@ fun CustomScopePage(navController: NavController, adjustPadding: PaddingValues) navController, adjustPadding, stringResource(R.string.custom_scope_title), - DataConst.CUSTOM_SCOPE_LIST.key + DataConst.CUSTOM_SCOPE_LIST.key, + mode ) { item { PreferenceGroup { 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 index b31006ba..cc75c668 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/ForceSplashPage.kt @@ -7,16 +7,18 @@ 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) { +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 + 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 index 37ea6a3e..13be267d 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/HideIconPage.kt @@ -12,6 +12,7 @@ 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 @@ -19,7 +20,7 @@ import dev.lackluster.hyperx.compose.preference.SwitchPreference * 图标 - 不显示图标 */ @Composable -fun HideIconPage(navController: NavController, adjustPadding: PaddingValues) { +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, @@ -32,7 +33,8 @@ fun HideIconPage(navController: NavController, adjustPadding: PaddingValues) { navController, adjustPadding, stringResource(R.string.hide_splash_screen_icon_title), - DataConst.HIDE_SPLASH_SCREEN_ICON_LIST.key + DataConst.HIDE_SPLASH_SCREEN_ICON_LIST.key, + mode ) { item { PreferenceGroup { 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 index bdef582e..61a03919 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/IgnoreAppIconPage.kt @@ -12,6 +12,7 @@ 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 @@ -19,7 +20,7 @@ import dev.lackluster.hyperx.compose.preference.SwitchPreference * 图标 - 忽略应用主动谁知的图标 - 配置应用列表 */ @Composable -fun IgnoreAppIconPage(navController: NavController, adjustPadding: PaddingValues) { +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, @@ -32,7 +33,8 @@ fun IgnoreAppIconPage(navController: NavController, adjustPadding: PaddingValues navController, adjustPadding, stringResource(R.string.default_style_title), - DataConst.DEFAULT_STYLE_LIST.key + DataConst.DEFAULT_STYLE_LIST.key, + mode ) { item { PreferenceGroup { 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 index 10104214..039d7d43 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/MinDurationPage.kt @@ -9,6 +9,7 @@ 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 @@ -21,7 +22,8 @@ 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.windowInsetsPadding +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 @@ -44,6 +46,8 @@ 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 @@ -61,6 +65,7 @@ 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 @@ -86,10 +91,11 @@ 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.extra.SuperArrow import top.yukonga.miuix.kmp.icon.MiuixIcons import top.yukonga.miuix.kmp.icon.icons.Info import top.yukonga.miuix.kmp.icon.icons.Search @@ -106,6 +112,7 @@ import top.yukonga.miuix.kmp.utils.getWindowSize fun MinDurationPage( navController: NavController, adjustPadding: PaddingValues, + mode: BasePageDefaults.Mode, blurEnabled: MutableState = MainActivity.blurEnabled, blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight, blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark, @@ -196,7 +203,7 @@ fun MinDurationPage( delay(100) appInfoFilter = appInfoList.toMutableList().apply { sortBy { it.appName } - sortBy { it.config.value != null } + sortByDescending { it.config.value != null} sortByDescending { it.isChecked.value } } } else { @@ -205,12 +212,17 @@ fun MinDurationPage( it.appName.contains(queryString, true) or it.packageName.contains(queryString, true) }.toMutableList().apply { sortBy { it.appName } - sortBy { it.config.value != null } + 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(), @@ -224,6 +236,7 @@ fun MinDurationPage( navigationIcon = { IconButton( modifier = Modifier + .padding(navigationIconPadding) .padding(start = 21.dp) .size(40.dp), onClick = { @@ -250,6 +263,7 @@ fun MinDurationPage( ) } }, + defaultWindowInsetsPadding = false, horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current) ) }, @@ -340,9 +354,7 @@ fun MinDurationPage( LazyColumn( modifier = Modifier .height(getWindowSize().height.dp) - .background(MiuixTheme.colorScheme.background) - .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) - .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + .background(MiuixTheme.colorScheme.background), state = listState, contentPadding = paddingValues, topAppBarScrollBehavior = scrollBehavior @@ -435,14 +447,13 @@ fun MinDurationPage( ), title = item.appName, summary = item.packageName, + checked = item.isChecked, defValue = item.config.value?.toIntOrNull() ?: 0, dialogMessage = dialogMessage ) { text, value -> if (value == 0) { - item.isChecked.value = false item.config.value = null } else { - item.isChecked.value = true item.config.value = text } } @@ -476,6 +487,7 @@ fun MinDurationPreference( icon: ImageIcon? = null, title: String, summary: String? = null, + checked: MutableState, defValue: Int = 0, dialogMessage: String? = null, onValueChange: ((String, Int) -> Unit)? = null, @@ -492,7 +504,7 @@ fun MinDurationPreference( onValueChange?.let { it(newString, newValue) } } } - SuperArrow( + BasicComponent( title = title, summary = summary, leftAction = { @@ -500,7 +512,23 @@ fun MinDurationPreference( DrawableResIcon(it) } }, - rightText = stringValue, + 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 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 index ab6a5c60..f0653104 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/apppage/RemoveBrandingPage.kt @@ -12,6 +12,7 @@ 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 @@ -19,7 +20,7 @@ import dev.lackluster.hyperx.compose.preference.SwitchPreference * 底部 - 移除底部图片 - 配置移除列表 */ @Composable -fun RemoveBrandingPage(navController: NavController, adjustPadding: PaddingValues) { +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, @@ -32,7 +33,8 @@ fun RemoveBrandingPage(navController: NavController, adjustPadding: PaddingValue navController, adjustPadding, stringResource(R.string.background_image_title), - DataConst.REMOVE_BRANDING_IMAGE_LIST.key + DataConst.REMOVE_BRANDING_IMAGE_LIST.key, + mode ) { item { PreferenceGroup { 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 index 46c0516b..53d6cec1 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/AppListPage.kt @@ -12,6 +12,7 @@ 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 @@ -24,7 +25,7 @@ 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.windowInsetsPadding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -62,6 +63,7 @@ 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 @@ -110,6 +112,7 @@ fun AppListPage( adjustPadding: PaddingValues, title: String, checkedListKey: String?, + mode: BasePageDefaults.Mode, blurEnabled: MutableState = MainActivity.blurEnabled, blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight, blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark, @@ -226,6 +229,14 @@ fun AppListPage( } } } + 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(), @@ -239,6 +250,7 @@ fun AppListPage( navigationIcon = { IconButton( modifier = Modifier + .padding(navigationIconPadding) .padding(start = 21.dp) .size(40.dp), onClick = { @@ -302,6 +314,7 @@ fun AppListPage( ) { IconButton( modifier = Modifier + .padding(actionsPadding) .padding(end = 21.dp) .size(40.dp), onClick = { @@ -315,6 +328,7 @@ fun AppListPage( } } }, + defaultWindowInsetsPadding = false, horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current) ) }, @@ -397,9 +411,7 @@ fun AppListPage( LazyColumn( modifier = Modifier .height(getWindowSize().height.dp) - .background(MiuixTheme.colorScheme.background) - .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) - .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + .background(MiuixTheme.colorScheme.background), state = listState, contentPadding = paddingValues, topAppBarScrollBehavior = scrollBehavior 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 index 9d3d6a41..22ea2e6b 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/component/ColorPickerPage.kt @@ -16,6 +16,7 @@ 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 @@ -28,8 +29,8 @@ 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.layout.windowInsetsPadding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.magnifier import androidx.compose.foundation.shape.CircleShape @@ -92,6 +93,7 @@ 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 @@ -138,9 +140,10 @@ fun ColorPickerPage( pkgName: String, keyLight: String, keyDark: String, + mode: BasePageDefaults.Mode, blurEnabled: MutableState = MainActivity.blurEnabled, blurTintAlphaLight: MutableFloatState = MainActivity.blurTintAlphaLight, - blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark, + blurTintAlphaDark: MutableFloatState = MainActivity.blurTintAlphaDark ) { val topAppBarBackground = MiuixTheme.colorScheme.background val scrollBehavior = MiuixScrollBehavior(rememberTopAppBarState()) @@ -258,6 +261,11 @@ fun ColorPickerPage( 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(), @@ -271,6 +279,7 @@ fun ColorPickerPage( navigationIcon = { IconButton( modifier = Modifier + .padding(navigationIconPadding) .padding(start = 21.dp) .size(40.dp), onClick = { @@ -290,6 +299,7 @@ fun ColorPickerPage( ) } }, + defaultWindowInsetsPadding = false, horizontalPadding = 28.dp + contentPadding.calculateLeftPadding(LocalLayoutDirection.current) ) }, @@ -430,9 +440,7 @@ fun ColorPickerPage( LazyColumn( modifier = Modifier .height(getWindowSize().height.dp) - .background(MiuixTheme.colorScheme.background) - .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)) - .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), + .background(MiuixTheme.colorScheme.background), state = listState, contentPadding = paddingValues, topAppBarScrollBehavior = scrollBehavior 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 index 4be6ba80..0ce4784a 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/AboutPage.kt @@ -41,6 +41,7 @@ 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 @@ -55,7 +56,7 @@ import kotlin.math.min * 关于页面 */ @Composable -fun AboutPage(navController: NavController, adjustPadding: PaddingValues) { +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"), @@ -71,6 +72,7 @@ fun AboutPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { var count = 0 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 index e0e9db7d..3c757ec1 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BackgroundPage.kt @@ -21,6 +21,7 @@ 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 @@ -32,7 +33,7 @@ import dev.lackluster.hyperx.compose.preference.TextPreference * 背景 界面 */ @Composable -fun BackgroundPage(navController: NavController, adjustPadding: PaddingValues) { +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)) } @@ -65,6 +66,7 @@ fun BackgroundPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( 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 index d52cdf9d..a58839ff 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BasicPage.kt @@ -23,6 +23,7 @@ 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 @@ -32,7 +33,7 @@ import java.time.LocalDateTime * 基础设置 界面 */ @Composable -fun BasicPage(navController: NavController, adjustPadding: PaddingValues) { +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) { @@ -67,6 +68,7 @@ fun BasicPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( 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 index 0e79b0f9..6576b0ee 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/BottomPage.kt @@ -18,6 +18,7 @@ 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 @@ -27,7 +28,7 @@ import dev.lackluster.hyperx.compose.preference.TextPreference * 底部 界面 */ @Composable -fun BottomPage(navController: NavController, adjustPadding: PaddingValues) { +fun BottomPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) { var removeBrandingImage by remember { mutableStateOf(SafeSP.getBoolean(DataConst.REMOVE_BRANDING_IMAGE.key)) } BasePage( @@ -37,6 +38,7 @@ fun BottomPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( 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 index c781c623..7ae3002b 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DevPage.kt @@ -19,6 +19,7 @@ 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 @@ -32,7 +33,7 @@ import kotlin.math.roundToInt * 开发者选项 */ @Composable -fun DevPage(navController: NavController, adjustPadding: PaddingValues) { +fun DevPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) { val hookInfos = remember { mutableStateListOf() } LaunchedEffect(Unit) { @@ -66,6 +67,7 @@ fun DevPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { PreferenceGroup( 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 index a5ab6c43..93def098 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/DisplayPage.kt @@ -19,6 +19,7 @@ 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 @@ -28,7 +29,7 @@ import dev.lackluster.hyperx.compose.preference.TextPreference * 显示设置 界面 */ @Composable -fun DisplayPage(navController: NavController, adjustPadding: PaddingValues) { +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)) } @@ -40,6 +41,7 @@ fun DisplayPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( 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 index 308bce3a..31a98f32 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/IconPage.kt @@ -23,6 +23,7 @@ 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 @@ -34,7 +35,7 @@ import dev.lackluster.hyperx.compose.preference.TextPreference * 图标 界面 */ @Composable -fun IconPage(navController: NavController, adjustPadding: PaddingValues) { +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)) } @@ -89,6 +90,7 @@ fun IconPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( 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 index 14ad04be..4a94c5fb 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/MainPage.kt @@ -20,6 +20,8 @@ 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 @@ -36,6 +38,7 @@ 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 @@ -59,7 +62,7 @@ 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) { +fun MainPage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) { val isTopPopupExpanded = remember { mutableStateOf(false) } val showTopPopup = remember { mutableStateOf(false) } val dialogRestartVisibility = remember { mutableStateOf(false) } @@ -101,8 +104,10 @@ fun MainPage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode, navigationIcon = {}, - actions = { + actions = { padding -> + val hapticFeedback = LocalHapticFeedback.current if (isTopPopupExpanded.value) { ListPopup( show = showTopPopup, @@ -138,9 +143,10 @@ fun MainPage(navController: NavController, adjustPadding: PaddingValues) { showTopPopup.value = true } IconButton( - modifier = Modifier.padding(end = 21.dp).size(40.dp), + modifier = Modifier.padding(padding).padding(end = 21.dp).size(40.dp), onClick = { isTopPopupExpanded.value = true + hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) } ) { Icon( 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 index 0d13ec1b..0420b361 100644 --- a/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt +++ b/app/src/main/java/com/gswxxn/restoresplashscreen/ui/page/ScopePage.kt @@ -19,6 +19,7 @@ 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 @@ -28,7 +29,7 @@ import dev.lackluster.hyperx.compose.preference.TextPreference * 作用域 界面 */ @Composable -fun ScopePage(navController: NavController, adjustPadding: PaddingValues) { +fun ScopePage(navController: NavController, adjustPadding: PaddingValues, mode: BasePageDefaults.Mode) { var customScope by remember { mutableStateOf(SafeSP.getBoolean(DataConst.ENABLE_CUSTOM_SCOPE.key)) } BasePage( @@ -38,6 +39,7 @@ fun ScopePage(navController: NavController, adjustPadding: PaddingValues) { MainActivity.blurEnabled, MainActivity.blurTintAlphaLight, MainActivity.blurTintAlphaDark, + mode ) { item { HeaderCard( diff --git a/hyperx-compose b/hyperx-compose index c44c5908..42e8e820 160000 --- a/hyperx-compose +++ b/hyperx-compose @@ -1 +1 @@ -Subproject commit c44c590857f2e32006b50e9bd0e5ac9fcd2d4416 +Subproject commit 42e8e820ee5a42ccdc3c86b4fef750ffb2a03f69 From eb2596fad463ed3857ce52633f3c52fb09b97387 Mon Sep 17 00:00:00 2001 From: howie Date: Wed, 11 Dec 2024 20:26:08 +0800 Subject: [PATCH 7/7] misc: update dependencies; --- app/build.gradle.kts | 3 --- app/proguard-rules.pro | 2 +- gradle/sweet-dependency/sweet-dependency-config.yaml | 11 +---------- hyperx-compose | 2 +- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 53786e46..9ff9e024 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -97,9 +97,6 @@ android { dependencies { implementation(projects.hyperxCompose) - implementation(androidx.activity.activity.compose) - implementation(androidx.navigation.navigation.compose) - implementation(androidx.compose.foundation.foundation) implementation(org.jetbrains.kotlinx.kotlinx.serialization.json) compileOnly(de.robv.android.xposed.api) 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/gradle/sweet-dependency/sweet-dependency-config.yaml b/gradle/sweet-dependency/sweet-dependency-config.yaml index 231bd33c..e660b68a 100644 --- a/gradle/sweet-dependency/sweet-dependency-config.yaml +++ b/gradle/sweet-dependency/sweet-dependency-config.yaml @@ -54,13 +54,4 @@ libraries: version: 1.7.3 androidx.annotation: annotation: - version: 1.9.1 - androidx.activity: - activity-compose: - version: 1.9.3 - androidx.navigation: - navigation-compose: - version: 2.8.4 - androidx.compose.foundation: - foundation: - version: 1.7.5 \ No newline at end of file + version: 1.9.1 \ No newline at end of file diff --git a/hyperx-compose b/hyperx-compose index 42e8e820..e4c30cb7 160000 --- a/hyperx-compose +++ b/hyperx-compose @@ -1 +1 @@ -Subproject commit 42e8e820ee5a42ccdc3c86b4fef750ffb2a03f69 +Subproject commit e4c30cb7b3499375e3d9817ff2ef2aa38b37adca