feat: refine home service controls

This commit is contained in:
二刺螈
2026-08-06 17:53:35 +08:00
parent 5eb7c684d2
commit aec7c4b32b
5 changed files with 154 additions and 70 deletions

View File

@@ -278,29 +278,13 @@ fun AdvancedPage() {
.verticalScroll(rememberScrollState())
.padding(contentPadding),
) {
Text(
text = "特权服务",
modifier = Modifier.titleItemPadding(showTop = false),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary,
)
SettingItem(
title = "特权服务",
subtitle = "管理授权与启动方式",
imageVector = PerfIcon.ArrowForward,
onClickLabel = "打开高级授权页面",
onClick = {
mainVm.navigatePage(PrivilegePageRoute)
},
)
val server by HttpService.httpServerFlow.collectAsState()
val httpServerRunning = server != null
val localNetworkIps by HttpService.localNetworkIpsFlow.collectAsState()
Text(
text = "HTTP",
modifier = Modifier.titleItemPadding(),
modifier = Modifier.titleItemPadding(showTop = false),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary,
)

View File

@@ -14,7 +14,6 @@ import li.songe.gkd.priv.gkdPrivilegeUiConfig
import li.songe.gkd.ui.component.PerfIcon
import li.songe.gkd.ui.component.PerfIconButton
import li.songe.gkd.ui.component.PerfTopAppBar
import li.songe.gkd.ui.icon.GitHub
import li.songe.gkd.ui.share.LocalMainViewModel
import priv.kit.ui.PrivilegeScaffold
import priv.kit.ui.PrivilegeUiViewModel
@@ -23,8 +22,6 @@ import priv.kit.ui.R as PrivilegeUiR
@Serializable
data object PrivilegePageRoute : NavKey
private const val PRIV_KIT_REPOSITORY_URL = "https://github.com/priv-kit/priv-kit"
@Composable
fun PrivilegePage() {
val mainVm = LocalMainViewModel.current
@@ -48,15 +45,6 @@ fun PrivilegePage() {
title = {
Text(text = stringResource(PrivilegeUiR.string.priv_ui_title))
},
actions = {
PerfIconButton(
imageVector = GitHub,
contentDescription = "GitHub",
onClick = {
mainVm.openUrl(PRIV_KIT_REPOSITORY_URL)
},
)
},
)
},
)

View File

@@ -18,6 +18,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -70,6 +72,7 @@ import li.songe.gkd.ui.style.EmptyHeight
import li.songe.gkd.ui.style.itemHorizontalPadding
import li.songe.gkd.ui.style.itemVerticalPadding
import li.songe.gkd.ui.style.surfaceCardColors
import li.songe.gkd.util.AutomatorModeOption
import li.songe.gkd.util.HOME_PAGE_URL
import li.songe.gkd.util.ShortUrlSet
import li.songe.gkd.util.latestRecordDescFlow
@@ -82,6 +85,8 @@ fun useControlPage(): ScaffoldExt {
val context = LocalActivity.current as MainActivity
val mainVm = LocalMainViewModel.current
val vm = viewModel<HomeVm>()
val privilegeContext by privilegeContextFlow.collectAsState()
val automatorMode by mainVm.automatorModeFlow.collectAsState()
val scrollKey = rememberSaveable { mutableIntStateOf(0) }
val (scrollBehavior, scrollState) = useScrollBehaviorState(scrollKey)
LaunchedEffect(null) {
@@ -102,10 +107,21 @@ fun useControlPage(): ScaffoldExt {
}, actions = {
PerfIconButton(
imageVector = PerfIcon.RocketLaunch,
onClickLabel = "前往工作模式页面",
contentDescription = "工作模式",
onClickLabel = "前往特权服务页面",
contentDescription = if (privilegeContext == null) {
"特权服务,未连接"
} else {
"特权服务,已连接"
},
colors = IconButtonDefaults.iconButtonColors(
contentColor = when {
privilegeContext != null -> MaterialTheme.colorScheme.primary
automatorMode == AutomatorModeOption.AutomationMode -> MaterialTheme.colorScheme.error
else -> MaterialTheme.colorScheme.onSurfaceVariant
},
),
onClick = throttle {
mainVm.navigatePage(AuthA11yRoute)
mainVm.navigatePage(PrivilegePageRoute)
},
)
})
@@ -154,9 +170,7 @@ fun useControlPage(): ScaffoldExt {
}
}
if (store.useA11y || actualA11yScopeAppList.contains(topAppIdFlow.collectAsState().value)) {
PageSwitchItemCard(
imageVector = PerfIcon.Memory,
title = "服务状态",
ServiceStatusCard(
subtitle = if (a11yRunning) {
"无障碍正在运行"
} else if (mainVm.a11yServiceEnabledFlow.collectAsState().value) {
@@ -178,13 +192,14 @@ fun useControlPage(): ScaffoldExt {
switchAutomatorService()
}
},
mode = automatorMode.label,
onModeClick = {
mainVm.navigatePage(AuthA11yRoute)
},
)
} else {
val automation by uiAutomationFlow.collectAsState()
val privilegeContext by privilegeContextFlow.collectAsState()
PageSwitchItemCard(
imageVector = PerfIcon.Memory,
title = "服务状态",
ServiceStatusCard(
subtitle = if (automation != null) {
"自动化正在运行"
} else if (privilegeContext == null) {
@@ -204,6 +219,10 @@ fun useControlPage(): ScaffoldExt {
switchAutomatorService()
}
},
mode = automatorMode.label,
onModeClick = {
mainVm.navigatePage(AuthA11yRoute)
},
)
}
@@ -224,16 +243,7 @@ fun useControlPage(): ScaffoldExt {
},
)
ServerStatusCard()
PageItemCard(
title = "触发记录",
subtitle = "规则误触可定位关闭",
imageVector = PerfIcon.History,
onClickLabel = "打开触发记录页面",
onClick = {
mainVm.navigatePage(ActionLogRoute())
})
TriggerOverviewCard()
if (ActivityService.isRunning.collectAsState().value) {
PageItemCard(
@@ -342,12 +352,108 @@ private fun PageSwitchItemCard(
}
}
@Composable
private fun ServiceStatusCard(
subtitle: String,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
mode: String,
onModeClick: () -> Unit,
) {
val onStatusClick = throttle { onCheckedChange(!checked) }
val onModeRowClick = throttle(onModeClick)
Card(
modifier = Modifier.fillMaxWidth(),
shape = MaterialTheme.shapes.large,
colors = surfaceCardColors,
) {
IconTextCard(
imageVector = PerfIcon.Memory,
modifier = Modifier
.semantics(mergeDescendants = true) {}
.clickable(
onClickLabel = "切换服务状态",
onClick = onStatusClick,
),
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "服务状态",
style = MaterialTheme.typography.bodyLarge,
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
Spacer(Modifier.width(8.dp))
PerfSwitch(
checked = checked,
onCheckedChange = null,
)
}
HorizontalDivider(
modifier = Modifier.padding(
start = itemVerticalPadding + 40.dp + itemHorizontalPadding,
end = itemVerticalPadding,
),
)
Row(
modifier = Modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) {}
.clickable(
onClickLabel = "前往工作模式页面",
onClick = onModeRowClick,
)
.padding(
start = itemVerticalPadding,
end = itemVerticalPadding,
top = 10.dp,
bottom = 10.dp,
),
verticalAlignment = Alignment.CenterVertically,
) {
PerfIcon(
imageVector = PerfIcon.AutoMode,
modifier = Modifier
.padding(horizontal = 10.dp)
.size(20.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
contentDescription = null,
)
Spacer(modifier = Modifier.width(itemHorizontalPadding))
Text(
text = "工作模式",
style = MaterialTheme.typography.bodyMedium,
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = mode,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
PerfIcon(
imageVector = PerfIcon.KeyboardArrowRight,
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
contentDescription = null,
)
}
}
}
@Composable
private fun IconTextCard(
imageVector: ImageVector, content: @Composable () -> Unit
imageVector: ImageVector,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Row(
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.padding(itemVerticalPadding),
verticalAlignment = Alignment.CenterVertically
@@ -368,18 +474,25 @@ private fun IconTextCard(
}
@Composable
private fun ServerStatusCard() {
private fun TriggerOverviewCard() {
val mainVm = LocalMainViewModel.current
val vm = viewModel<HomeVm>()
val openActionLog = throttle {
mainVm.navigatePage(ActionLogRoute())
}
Card(
modifier = Modifier
.fillMaxWidth()
.semantics {
onClick(label = "不执行操作", action = null)
}, shape = RoundedCornerShape(20.dp), colors = surfaceCardColors, onClick = {}) {
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
colors = surfaceCardColors,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) {}
.clickable(
onClickLabel = "打开触发记录页面",
onClick = openActionLog,
)
.padding(
start = itemVerticalPadding,
end = itemVerticalPadding,
@@ -401,18 +514,20 @@ private fun ServerStatusCard() {
modifier = Modifier.weight(1f)
) {
Text(
text = "数据概览",
text = "触发记录",
style = MaterialTheme.typography.bodyLarge,
)
val usedSubsItemCount by vm.usedSubsItemCountFlow.collectAsState()
AnimatedVisibility(usedSubsItemCount > 0) {
Text(
text = "已开启 $usedSubsItemCount 条订阅",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
Text(
text = "规则误触可定位关闭",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
PerfIcon(
imageVector = PerfIcon.KeyboardArrowRight,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
contentDescription = null,
)
}
Column(
modifier = Modifier

View File

@@ -13,7 +13,6 @@ import li.songe.gkd.util.EMPTY_RULE_TIP
import li.songe.gkd.util.findOption
import li.songe.gkd.util.getSubsStatus
import li.songe.gkd.util.ruleSummaryFlow
import li.songe.gkd.util.usedSubsEntriesFlow
class HomeVm : BaseViewModel() {
@@ -23,8 +22,6 @@ class HomeVm : BaseViewModel() {
}.stateInit(EMPTY_RULE_TIP)
}
val usedSubsItemCountFlow = usedSubsEntriesFlow.mapNew { it.size }
val sortTypeFlow = storeFlow.asMutableStateFlow(
getter = { AppSortOption.objects.findOption(it.appSort) },
setter = {

View File

@@ -14,7 +14,7 @@ coil = "3.5.0"
telephoto = "0.19.0"
remap = "0.1.4"
shizuku = "13.1.5"
priv-kit = "0.3.2"
priv-kit = "0.3.3"
loc = "0.7.1"
[libraries]