diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
index 9e74b31a..0f6e1ec2 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
@@ -1,14 +1,46 @@
package com.sukisu.ultra.ui.screen
import android.annotation.SuppressLint
-import androidx.compose.animation.*
-import androidx.compose.animation.core.*
-import androidx.compose.foundation.background
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.expandHorizontally
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.scaleIn
+import androidx.compose.animation.scaleOut
+import androidx.compose.animation.shrinkHorizontally
+import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowRow
+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.fillMaxSize
+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.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
@@ -20,10 +52,46 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.*
-import androidx.compose.material3.*
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.Archive
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.GridView
+import androidx.compose.material.icons.filled.MoreVert
+import androidx.compose.material.icons.filled.Refresh
+import androidx.compose.material.icons.filled.RestoreFromTrash
+import androidx.compose.material.icons.filled.Save
+import androidx.compose.material.icons.filled.SearchOff
+import androidx.compose.material.icons.filled.Visibility
+import androidx.compose.material.icons.filled.VisibilityOff
+import androidx.compose.material3.Checkbox
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FilterChip
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LinearProgressIndicator
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SheetState
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.SnackbarHostState
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
-import androidx.compose.runtime.*
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.material3.rememberTopAppBarState
+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.rememberCoroutineScope
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
@@ -87,9 +155,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
LaunchedEffect(navigator) {
viewModel.search = ""
- if (viewModel.appList.isEmpty()) {
- // viewModel.fetchAppList()
- }
}
LaunchedEffect(viewModel.selectedApps, viewModel.showBatchActions) {
@@ -344,18 +409,20 @@ private fun SuperUserContent(
appGroup.packageNames.forEach { viewModel.toggleAppSelection(it) }
}
},
- viewModel = viewModel,
- navigator = navigator,
- isExpanded = expandedGroups.value.contains(appGroup.uid)
+ viewModel = viewModel
)
}
- if (expandedGroups.value.contains(appGroup.uid) && appGroup.apps.size > 1) {
- items(appGroup.apps.drop(1), key = { it.packageName }) { app ->
+ items(appGroup.apps, key = { it.packageName }) { app ->
+ AnimatedVisibility(
+ visible = expandedGroups.value.contains(appGroup.uid) && appGroup.apps.size > 1,
+ enter = fadeIn() + expandVertically(),
+ exit = fadeOut() + shrinkVertically()
+ ) {
ListItem(
modifier = Modifier
.fillMaxWidth()
- .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f))
+ .padding(start = 10.dp)
.clickable {
navigator.navigate(AppProfileScreenDestination(app))
},
@@ -786,9 +853,7 @@ private fun AppGroupItem(
onToggleSelection: () -> Unit,
onClick: () -> Unit,
onLongClick: () -> Unit,
- viewModel: SuperUserViewModel,
- navigator: DestinationsNavigator,
- isExpanded: Boolean = false
+ viewModel: SuperUserViewModel
) {
val mainApp = appGroup.mainApp
@@ -800,37 +865,16 @@ private fun AppGroupItem(
)
},
headlineContent = {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Text(mainApp.label)
- if (appGroup.apps.size > 1) {
- Spacer(modifier = Modifier.width(8.dp))
- Surface(
- shape = RoundedCornerShape(12.dp),
- color = MaterialTheme.colorScheme.secondaryContainer,
- ) {
- Text(
- text = "${appGroup.apps.size} apps",
- style = MaterialTheme.typography.labelSmall,
- modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
- color = MaterialTheme.colorScheme.onSecondaryContainer
- )
- }
- Icon(
- imageVector = if (isExpanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
- contentDescription = null,
- modifier = Modifier.size(20.dp)
- )
- }
- }
+ Text(mainApp.label)
},
supportingContent = {
Column {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Text("UID: ${appGroup.uid}")
- }
- if (appGroup.apps.size == 1) {
- Text(mainApp.packageName)
+ val summaryText = if (appGroup.apps.size > 1) {
+ stringResource(R.string.group_contains_apps, appGroup.apps.size)
+ } else {
+ mainApp.packageName
}
+ Text(summaryText)
Spacer(modifier = Modifier.height(4.dp))
@@ -864,6 +908,17 @@ private fun AppGroupItem(
)
)
}
+ if (appGroup.apps.size > 1) {
+ Natives.getUserName(appGroup.uid)?.let {
+ LabelItem(
+ text = it,
+ style = LabelItemDefaults.style.copy(
+ containerColor = MaterialTheme.colorScheme.primaryContainer,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ )
+ )
+ }
+ }
}
}
},
@@ -878,7 +933,17 @@ private fun AppGroupItem(
)
},
trailingContent = {
- if (viewModel.showBatchActions) {
+ AnimatedVisibility(
+ visible = viewModel.showBatchActions,
+ enter = fadeIn(animationSpec = tween(200)) + scaleIn(
+ animationSpec = tween(200),
+ initialScale = 0.6f
+ ),
+ exit = fadeOut(animationSpec = tween(200)) + scaleOut(
+ animationSpec = tween(200),
+ targetScale = 0.6f
+ )
+ ) {
val checkboxInteractionSource = remember { MutableInteractionSource() }
val isCheckboxPressed by checkboxInteractionSource.collectIsPressedAsState()
diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml
index d15ee8d1..7cba39f8 100644
--- a/manager/app/src/main/res/values-zh-rCN/strings.xml
+++ b/manager/app/src/main/res/values-zh-rCN/strings.xml
@@ -750,4 +750,5 @@
清除自定义
应用配置
配置已应用到内核
+ 包含 %1$d 个应用