From 89dc4b80b12c0f851adca25c4f08fe91aef8e358 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Sun, 24 Nov 2024 22:51:43 +0800 Subject: [PATCH] migrate to compose --- app/build.gradle.kts | 17 +- app/src/main/AndroidManifest.xml | 2 +- .../com/qhy040404/fxxkmiuiad/MainActivity.kt | 227 --------------- .../fxxkmiuiad/MainComposeActivity.kt | 261 ++++++++++++++++++ .../qhy040404/fxxkmiuiad/base/BaseActivity.kt | 21 -- .../com/qhy040404/fxxkmiuiad/base/IBinding.kt | 34 --- .../com/qhy040404/fxxkmiuiad/theme/Theme.kt | 62 +++++ app/src/main/res/layout/activity_main.xml | 86 ------ app/src/main/res/values-night/themes.xml | 14 +- app/src/main/res/values/colors.xml | 10 - app/src/main/res/values/themes.xml | 14 +- build.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- hidden-api/build.gradle.kts | 2 - 14 files changed, 338 insertions(+), 416 deletions(-) delete mode 100644 app/src/main/java/com/qhy040404/fxxkmiuiad/MainActivity.kt create mode 100644 app/src/main/java/com/qhy040404/fxxkmiuiad/MainComposeActivity.kt delete mode 100644 app/src/main/java/com/qhy040404/fxxkmiuiad/base/BaseActivity.kt delete mode 100644 app/src/main/java/com/qhy040404/fxxkmiuiad/base/IBinding.kt create mode 100644 app/src/main/java/com/qhy040404/fxxkmiuiad/theme/Theme.kt delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100644 app/src/main/res/values/colors.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3bc1a02..31967b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") - id("dev.rikka.tools.refine") + id("org.jetbrains.kotlin.plugin.compose") } android { @@ -12,13 +12,13 @@ android { applicationId = "com.qhy040404.fxxkmiuiad" minSdk = 29 targetSdk = 35 - versionCode = 9 - versionName = "1.3.1" + versionCode = 10 + versionName = "1.4.0" } buildFeatures { buildConfig = true - viewBinding = true + compose = true } buildTypes { @@ -55,10 +55,13 @@ dependencies { compileOnly(project(":hidden-api")) implementation("androidx.annotation:annotation:1.9.1") - implementation("com.google.android.material:material:1.12.0") - implementation("dev.rikka.rikkax.appcompat:appcompat:1.6.1") implementation("dev.rikka.shizuku:api:13.1.5") implementation("dev.rikka.shizuku:provider:13.1.5") - implementation("dev.rikka.tools.refine:runtime:4.4.0") implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3") + + implementation(platform("androidx.compose:compose-bom:2024.11.00")) + implementation("androidx.compose.runtime:runtime") + implementation("androidx.activity:activity-compose") + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.material3:material3") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c402ff1..d4ad9a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ android:theme="@style/Theme.FxxkMIUIAd" tools:targetApi="31"> diff --git a/app/src/main/java/com/qhy040404/fxxkmiuiad/MainActivity.kt b/app/src/main/java/com/qhy040404/fxxkmiuiad/MainActivity.kt deleted file mode 100644 index 4d72c3b..0000000 --- a/app/src/main/java/com/qhy040404/fxxkmiuiad/MainActivity.kt +++ /dev/null @@ -1,227 +0,0 @@ -package com.qhy040404.fxxkmiuiad - -import android.annotation.SuppressLint -import android.content.Intent -import android.content.pm.PackageManager -import android.widget.Toast -import androidx.core.net.toUri -import androidx.core.view.isVisible -import com.qhy040404.fxxkmiuiad.base.BaseActivity -import com.qhy040404.fxxkmiuiad.databinding.ActivityMainBinding -import com.qhy040404.fxxkmiuiad.utils.OsUtils -import com.qhy040404.fxxkmiuiad.utils.PackageUtils -import com.qhy040404.fxxkmiuiad.utils.PackageUtils.getApplicationEnableStateAsString -import com.qhy040404.fxxkmiuiad.utils.ShizukuStatus -import com.qhy040404.fxxkmiuiad.utils.ShizukuUtils -import rikka.shizuku.Shizuku -import kotlin.concurrent.thread - -@SuppressLint("SetTextI18n") -class MainActivity : BaseActivity() { - private val callback = Shizuku.OnRequestPermissionResultListener { _, result -> - if (result == PackageManager.PERMISSION_GRANTED) { - this@MainActivity.refreshView() - } else { - runCatching { - PackageUtils.startLaunchAppActivity(this, Constants.SHIZUKU) - Toast.makeText(this, "授权失败,跳转到 Shizuku 手动授权", Toast.LENGTH_LONG).show() - }.onFailure { - Toast.makeText(this, "未检测到 Shizuku, 请手动前往 Sui 授权", Toast.LENGTH_LONG).show() - } - } - } - - private lateinit var packageList: List - - override fun init() { - Shizuku.addRequestPermissionResultListener(callback) - initView() - - packageList = Constants.FUCKLIST.filter { - try { - packageManager.getPackageInfo(it, 0) - true - } catch (e: PackageManager.NameNotFoundException) { - false - } - } - } - - override fun onResume() { - super.onResume() - refreshView() - } - - override fun onDestroy() { - Shizuku.removeRequestPermissionResultListener(callback) - super.onDestroy() - } - - private fun refreshView() { - if (!OsUtils.isMiui(this)) { - binding.info.text = "非 MIUI 或 澎湃 OS" - binding.enableBtn.apply { - isClickable = false - isVisible = false - } - binding.disableBtn.apply { - isClickable = false - isVisible = false - } - return - } - - when (ShizukuUtils.checkStatus(this)) { - ShizukuStatus.Ok -> { - binding.runningInfo.text = "Shizuku 已运行" - binding.permittedInfo.text = "Shizuku 已授权" - - binding.enableBtn.apply { - isClickable = true - isVisible = true - } - binding.disableBtn.apply { - isClickable = true - isVisible = true - } - - binding.installBtn.isVisible = false - binding.jumpBtn.isVisible = false - binding.requestPermissionBtn.isVisible = false - - val states = mutableMapOf() - - packageList.forEach { - states[it] = packageManager.getApplicationEnableStateAsString(it) - } - - binding.info.text = buildString { - states.forEach { (name, state) -> - append("${name}: ${state}\n") - } - } - } - - ShizukuStatus.Outdated -> { - binding.runningInfo.text = "Shizuku 已运行" - binding.permittedInfo.text = "Shizuku 已授权" - binding.info.text = "Shizuku 版本过低,请更新" - - binding.enableBtn.apply { - isClickable = false - isVisible = false - } - binding.disableBtn.apply { - isClickable = false - isVisible = false - } - - binding.installBtn.isVisible = true - binding.jumpBtn.isVisible = false - binding.requestPermissionBtn.isVisible = false - } - - ShizukuStatus.NotRunning -> { - binding.runningInfo.text = "Shizuku 未运行" - binding.permittedInfo.text = "Shizuku 未授权" - - binding.enableBtn.apply { - isClickable = false - isVisible = false - } - binding.disableBtn.apply { - isClickable = false - isVisible = false - } - - binding.installBtn.isVisible = false - binding.jumpBtn.isVisible = true - binding.requestPermissionBtn.isVisible = false - } - - ShizukuStatus.NotAuthorized -> { - binding.runningInfo.text = "Shizuku 已运行" - binding.permittedInfo.text = "Shizuku 未授权" - - binding.enableBtn.apply { - isClickable = false - isVisible = false - } - binding.disableBtn.apply { - isClickable = false - isVisible = false - } - - binding.installBtn.isVisible = false - binding.jumpBtn.isVisible = false - binding.requestPermissionBtn.isVisible = true - } - - ShizukuStatus.NotInstalled -> { - binding.runningInfo.text = "Shizuku 未运行" - binding.permittedInfo.text = "Shizuku 未授权" - binding.info.text = "Shizuku 未安装" - - binding.enableBtn.apply { - isClickable = false - isVisible = false - } - binding.disableBtn.apply { - isClickable = false - isVisible = false - } - - binding.installBtn.isVisible = true - binding.jumpBtn.isVisible = false - binding.requestPermissionBtn.isVisible = false - } - } - } - - @SuppressLint("SetTextI18n") - private fun initView() { - binding.installBtn.setOnClickListener { - runCatching { startActivity(Intent(Intent.ACTION_VIEW).apply { data = Constants.SHIZUKU_RELEASE.toUri() }) } - } - binding.jumpBtn.setOnClickListener { - runCatching { PackageUtils.startLaunchAppActivity(this, Constants.SHIZUKU) } - } - binding.requestPermissionBtn.setOnClickListener { - runCatching { Shizuku.requestPermission(0) } - } - binding.enableBtn.setOnClickListener { - packageList.forEach { - PackageUtils.setApplicationEnabledSetting(it, PackageManager.COMPONENT_ENABLED_STATE_ENABLED) - PackageUtils.setPackagesSuspendedAsUser(it, false) - } - - thread { - Thread.sleep(200L) - runOnUiThread { - Toast.makeText(this, "已启用", Toast.LENGTH_SHORT).show() - refreshView() - } - } - } - binding.disableBtn.setOnClickListener { - packageList.forEach { pkgName -> - runCatching { - PackageUtils.setApplicationEnabledSetting( - pkgName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER - ) - }.onFailure { - PackageUtils.setPackagesSuspendedAsUser(pkgName, true) - } - } - - thread { - Thread.sleep(200L) - runOnUiThread { - Toast.makeText(this, "已禁用", Toast.LENGTH_SHORT).show() - refreshView() - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/qhy040404/fxxkmiuiad/MainComposeActivity.kt b/app/src/main/java/com/qhy040404/fxxkmiuiad/MainComposeActivity.kt new file mode 100644 index 0000000..3bfdc77 --- /dev/null +++ b/app/src/main/java/com/qhy040404/fxxkmiuiad/MainComposeActivity.kt @@ -0,0 +1,261 @@ +package com.qhy040404.fxxkmiuiad + +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Bundle +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.core.net.toUri +import com.qhy040404.fxxkmiuiad.theme.DayNightTheme +import com.qhy040404.fxxkmiuiad.utils.OsUtils +import com.qhy040404.fxxkmiuiad.utils.PackageUtils +import com.qhy040404.fxxkmiuiad.utils.PackageUtils.getApplicationEnableStateAsString +import com.qhy040404.fxxkmiuiad.utils.ShizukuStatus +import com.qhy040404.fxxkmiuiad.utils.ShizukuUtils +import rikka.shizuku.Shizuku + +lateinit var packageList: List + +val trigger = mutableStateOf(false) + +class MainComposeActivity : ComponentActivity() { + private val callback = Shizuku.OnRequestPermissionResultListener { _, result -> + if (result == PackageManager.PERMISSION_GRANTED) { + trigger.value = !trigger.value + } else { + runCatching { + PackageUtils.startLaunchAppActivity(this, Constants.SHIZUKU) + Toast.makeText(this, "授权失败,跳转到 Shizuku 手动授权", Toast.LENGTH_LONG).show() + }.onFailure { + Toast.makeText(this, "未检测到 Shizuku, 请手动前往 Sui 授权", Toast.LENGTH_LONG).show() + } + } + } + + @OptIn(ExperimentalMaterial3Api::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Shizuku.addRequestPermissionResultListener(callback) + packageList = Constants.FUCKLIST.filter { + try { + packageManager.getPackageInfo(it, 0) + true + } catch (e: PackageManager.NameNotFoundException) { + false + } + } + + enableEdgeToEdge() + setContent { + DayNightTheme { + Scaffold(topBar = { + TopAppBar(title = { Text("FxxkMIUIAd") }) + }) { innerPadding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), contentAlignment = Alignment.Center + ) { + val context = LocalContext.current + if (!OsUtils.isMiui(context)) { + Text( + "非 MIUI 或 澎湃 OS", + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge + ) + return@Scaffold + } + + InternalRefresh(trigger.value) + val shizukuStatus = ShizukuUtils.checkStatus(context) + Column { + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) { + Text( + text = when (shizukuStatus) { + ShizukuStatus.Ok, ShizukuStatus.Outdated, ShizukuStatus.NotAuthorized -> "Shizuku 已运行" + ShizukuStatus.NotRunning, ShizukuStatus.NotInstalled -> "Shizuku 未运行" + }, textAlign = TextAlign.Center + ) + + Text( + text = when (shizukuStatus) { + ShizukuStatus.Ok, ShizukuStatus.Outdated -> "Shizuku 已授权" + ShizukuStatus.NotRunning, ShizukuStatus.NotAuthorized, ShizukuStatus.NotInstalled -> "Shizuku 未授权" + }, textAlign = TextAlign.Center + ) + } + + Box( + modifier = Modifier + .size(300.dp, 120.dp) + .align(Alignment.CenterHorizontally), + contentAlignment = Alignment.Center + ) { + Text(text = when (shizukuStatus) { + ShizukuStatus.Ok -> packageList.associateWith { + packageManager.getApplicationEnableStateAsString(it) + }.entries.joinToString("\n") { (name, state) -> "$name: $state" } + + ShizukuStatus.Outdated -> "Shizuku 版本过低,请更新" + ShizukuStatus.NotInstalled -> "Shizuku 未安装" + ShizukuStatus.NotRunning, ShizukuStatus.NotAuthorized -> "" + }, textAlign = TextAlign.Center) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally), + horizontalArrangement = Arrangement.SpaceAround + ) { + when (shizukuStatus) { + ShizukuStatus.Ok -> { + EnableBtn() + DisableBtn() + } + + ShizukuStatus.Outdated, ShizukuStatus.NotInstalled -> InstallBtn() + ShizukuStatus.NotRunning -> JumpBtn() + ShizukuStatus.NotAuthorized -> RequestPermissionBtn() + } + } + } + } + } + } + } + } + + override fun onResume() { + super.onResume() + trigger.value = !trigger.value + } + + override fun onDestroy() { + super.onDestroy() + Shizuku.removeRequestPermissionResultListener(callback) + } +} + +@Composable +fun EnableBtn() { + val context = LocalContext.current + val showToast = remember { mutableStateOf(false) } + + Button(onClick = { + packageList.forEach { + PackageUtils.setApplicationEnabledSetting(it, PackageManager.COMPONENT_ENABLED_STATE_ENABLED) + PackageUtils.setPackagesSuspendedAsUser(it, false) + } + + showToast.value = true + }) { + Text(stringResource(id = R.string.enable)) + } + + LaunchedEffect(showToast.value) { + if (showToast.value) { + Toast.makeText(context, "已启用", Toast.LENGTH_SHORT).show() + trigger.value = !trigger.value + showToast.value = false + } + } +} + +@Composable +fun DisableBtn() { + val context = LocalContext.current + val showToast = remember { mutableStateOf(false) } + + Button(onClick = { + packageList.forEach { pkgName -> + runCatching { + PackageUtils.setApplicationEnabledSetting( + pkgName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER + ) + }.onFailure { + PackageUtils.setPackagesSuspendedAsUser(pkgName, true) + } + } + + showToast.value = true + }) { + Text(stringResource(id = R.string.disable)) + } + + LaunchedEffect(showToast.value) { + if (showToast.value) { + Toast.makeText(context, "已禁用", Toast.LENGTH_SHORT).show() + trigger.value = !trigger.value + showToast.value = false + } + } +} + +@Composable +fun InstallBtn() { + val context = LocalContext.current + Button(onClick = { + runCatching { + context.startActivity(Intent(Intent.ACTION_VIEW).apply { + data = Constants.SHIZUKU_RELEASE.toUri() + }) + } + }) { + Text(stringResource(id = R.string.install_shizuku)) + } +} + +@Composable +fun JumpBtn() { + val context = LocalContext.current + Button(onClick = { + runCatching { + PackageUtils.startLaunchAppActivity(context, Constants.SHIZUKU) + } + }) { + Text(stringResource(id = R.string.open_shizuku)) + } +} + +@Composable +fun RequestPermissionBtn() { + Button(onClick = { + runCatching { + Shizuku.requestPermission(0) + } + }) { + Text(stringResource(id = R.string.request_shizuku)) + } +} + +@Composable +fun InternalRefresh(trigger: Any) { +} diff --git a/app/src/main/java/com/qhy040404/fxxkmiuiad/base/BaseActivity.kt b/app/src/main/java/com/qhy040404/fxxkmiuiad/base/BaseActivity.kt deleted file mode 100644 index 3543bec..0000000 --- a/app/src/main/java/com/qhy040404/fxxkmiuiad/base/BaseActivity.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.qhy040404.fxxkmiuiad.base - -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.viewbinding.ViewBinding - -abstract class BaseActivity : AppCompatActivity(), IBinding { - override lateinit var binding: VB - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = inflateBinding(layoutInflater).also { - setContentView(it.root) - } - - init() - } - - protected abstract fun init() -} \ No newline at end of file diff --git a/app/src/main/java/com/qhy040404/fxxkmiuiad/base/IBinding.kt b/app/src/main/java/com/qhy040404/fxxkmiuiad/base/IBinding.kt deleted file mode 100644 index f7070bc..0000000 --- a/app/src/main/java/com/qhy040404/fxxkmiuiad/base/IBinding.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.qhy040404.fxxkmiuiad.base - -import android.view.LayoutInflater -import androidx.viewbinding.ViewBinding -import java.lang.reflect.Method -import java.lang.reflect.ParameterizedType - -internal sealed interface IBinding { - val binding: VB - - fun inflateBinding(inflater: LayoutInflater): T { - var method: Method? - var clazz: Class<*> = javaClass - while (clazz.superclass != null) { - method = clazz.filterBindingMethod() - if (method == null) { - clazz = clazz.superclass - } else { - @Suppress("UNCHECKED_CAST") - return method.invoke(null, inflater) as T - } - } - error("No Binding type argument found.") - } - - private fun Class<*>.filterBindingMethod(): Method? { - return (genericSuperclass as? ParameterizedType)?.actualTypeArguments - ?.asSequence() - ?.filterIsInstance>() - ?.firstOrNull { it.simpleName.endsWith("Binding") } - ?.getDeclaredMethod("inflate", LayoutInflater::class.java) - ?.also { it.isAccessible = true } - } -} diff --git a/app/src/main/java/com/qhy040404/fxxkmiuiad/theme/Theme.kt b/app/src/main/java/com/qhy040404/fxxkmiuiad/theme/Theme.kt new file mode 100644 index 0000000..32e80cd --- /dev/null +++ b/app/src/main/java/com/qhy040404/fxxkmiuiad/theme/Theme.kt @@ -0,0 +1,62 @@ +package com.qhy040404.fxxkmiuiad.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Typography +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +private val DarkColorScheme = darkColorScheme( + primary = Color(0xFFD0BCFF), + secondary = Color(0xFFCCC2DC), + tertiary = Color(0xFFEFB8C8) +) + +private val LightColorScheme = lightColorScheme( + primary = Color(0xFF6650a4), + secondary = Color(0xFF625b71), + tertiary = Color(0xFF7D5260) +) + +private val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) +) + +@Composable +fun DayNightTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = true, + content: @Composable () -> Unit, +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index aecc3d9..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - -