Optimize the HomeScreen component, refactor the device model acquisition logic, add anti-shake scrolling processing, clean up unused imports

This commit is contained in:
ShirkNeko
2025-04-30 20:01:39 +08:00
parent f3c77bdb3b
commit 45ed4708c9

View File

@@ -6,61 +6,124 @@ import android.os.Build
import android.os.PowerManager import android.os.PowerManager
import android.system.Os import android.system.Os
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.* import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.* import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.outlined.* import androidx.compose.material.icons.filled.Archive
import androidx.compose.material3.* import androidx.compose.material.icons.filled.Code
import androidx.compose.runtime.* import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Memory
import androidx.compose.material.icons.filled.PhoneAndroid
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.School
import androidx.compose.material.icons.filled.Security
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Storage
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material.icons.outlined.Block
import androidx.compose.material.icons.outlined.CheckCircle
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.* import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.edit
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination import com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers import com.sukisu.ultra.KernelVersion
import kotlinx.coroutines.withContext import com.sukisu.ultra.Natives
import com.sukisu.ultra.*
import com.sukisu.ultra.R import com.sukisu.ultra.R
import com.sukisu.ultra.getKernelVersion
import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.component.rememberConfirmDialog import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.util.*
import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import com.sukisu.ultra.ui.theme.getCardColors
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.CardConfig
import androidx.core.content.edit import com.sukisu.ultra.ui.theme.getCardColors
import com.sukisu.ultra.ui.util.checkNewVersion
import com.sukisu.ultra.ui.util.getKpmModuleCount
import com.sukisu.ultra.ui.util.getKpmVersion
import com.sukisu.ultra.ui.util.getModuleCount
import com.sukisu.ultra.ui.util.getSELinuxStatus
import com.sukisu.ultra.ui.util.getSuSFS
import com.sukisu.ultra.ui.util.getSuSFSFeatures
import com.sukisu.ultra.ui.util.getSuSFSVariant
import com.sukisu.ultra.ui.util.getSuSFSVersion
import com.sukisu.ultra.ui.util.getSuperuserCount
import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import com.sukisu.ultra.ui.util.reboot
import com.sukisu.ultra.ui.util.rootAvailable
import com.sukisu.ultra.ui.util.susfsSUS_SU_Mode
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.withContext
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import kotlin.random.Random import kotlin.random.Random
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
@Destination<RootGraph>(start = true) @Destination<RootGraph>(start = true)
@Composable @Composable
fun HomeScreen(navigator: DestinationsNavigator) { fun HomeScreen(navigator: DestinationsNavigator) {
@@ -89,7 +152,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
val isManager = Natives.becomeManager(ksuApp.packageName) val isManager = Natives.becomeManager(ksuApp.packageName)
val deviceModel = getDeviceModel(context) val deviceModel = getDeviceModel()
val ksuVersion = if (isManager) Natives.version else null val ksuVersion = if (isManager) Natives.version else null
val zako = "一.*加.*A.*c.*e.*5.*P.*r.*o".toRegex().matches(deviceModel) val zako = "一.*加.*A.*c.*e.*5.*P.*r.*o".toRegex().matches(deviceModel)
val isVersion = ksuVersion == 12777 val isVersion = ksuVersion == 12777
@@ -106,6 +169,10 @@ fun HomeScreen(navigator: DestinationsNavigator) {
} }
} }
val scrollState = rememberScrollState()
val debounceTime = 100L
var lastScrollTime by remember { mutableLongStateOf(0L) }
Scaffold( Scaffold(
topBar = { topBar = {
TopBar( TopBar(
@@ -121,10 +188,9 @@ fun HomeScreen(navigator: DestinationsNavigator) {
Column( Column(
modifier = Modifier modifier = Modifier
.padding(innerPadding) .padding(innerPadding)
.graphicsLayer(clip = true)
.disableOverscroll() .disableOverscroll()
.nestedScroll(scrollBehavior.nestedScrollConnection) .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState()) .verticalScroll(scrollState)
.padding(top = 12.dp) .padding(top = 12.dp)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
@@ -221,6 +287,21 @@ fun HomeScreen(navigator: DestinationsNavigator) {
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
} }
} }
// 防抖逻辑
LaunchedEffect(scrollState) {
snapshotFlow { scrollState.isScrollInProgress }
.debounce(debounceTime)
.collect { isScrolling ->
if (isScrolling) {
val currentTime = System.currentTimeMillis()
if (currentTime - lastScrollTime > debounceTime) {
lastScrollTime = currentTime
// 在这里可以添加滚动时的逻辑
}
}
}
}
} }
@Composable @Composable
@@ -761,9 +842,7 @@ private fun InfoCard() {
fun InfoCardItem( fun InfoCardItem(
label: String, label: String,
content: String, content: String,
icon: ImageVector = Icons.Default.Info, icon: ImageVector = Icons.Default.Info
maxLines: Int = 2,
overflow: TextOverflow = TextOverflow.Ellipsis
) { ) {
contents.appendLine(label).appendLine(content).appendLine() contents.appendLine(label).appendLine(content).appendLine()
Row( Row(
@@ -814,7 +893,7 @@ private fun InfoCard() {
) )
} }
val deviceModel = getDeviceModel(context) val deviceModel = getDeviceModel()
InfoCardItem( InfoCardItem(
stringResource(R.string.home_device_model), stringResource(R.string.home_device_model),
deviceModel, deviceModel,
@@ -853,9 +932,7 @@ private fun InfoCard() {
InfoCardItem( InfoCardItem(
stringResource(R.string.home_kpm_version), stringResource(R.string.home_kpm_version),
displayVersion, displayVersion,
icon = Icons.Default.Code, icon = Icons.Default.Code
Int.MAX_VALUE,
TextOverflow.Clip
) )
} }
} }
@@ -883,9 +960,7 @@ private fun InfoCard() {
InfoCardItem( InfoCardItem(
stringResource(R.string.home_susfs_version), stringResource(R.string.home_susfs_version),
infoText, infoText,
icon = Icons.Default.Storage, icon = Icons.Default.Storage
Int.MAX_VALUE,
TextOverflow.Clip
) )
} }
} }
@@ -924,7 +999,7 @@ private fun WarningCardPreview() {
} }
@SuppressLint("PrivateApi") @SuppressLint("PrivateApi")
private fun getDeviceModel(context: Context): String { private fun getDeviceModel(): String {
return try { return try {
val systemProperties = Class.forName("android.os.SystemProperties") val systemProperties = Class.forName("android.os.SystemProperties")
val getMethod = systemProperties.getMethod("get", String::class.java, String::class.java) val getMethod = systemProperties.getMethod("get", String::class.java, String::class.java)