mirror of
https://mirror.skon.top/github.com/gkd-kit/gkd
synced 2026-04-20 21:00:12 +08:00
perf: dialog layout
This commit is contained in:
@@ -25,7 +25,7 @@ data class SettingsStore(
|
||||
val captureVolumeChange: Boolean = false,
|
||||
val toastWhenClick: Boolean = true,
|
||||
val actionToast: String = META.appName,
|
||||
val autoClearMemorySubs: Boolean = true,
|
||||
val autoClearMemorySubs: Boolean = false,
|
||||
val hideSnapshotStatusBar: Boolean = false,
|
||||
val enableDarkTheme: Boolean? = null,
|
||||
val enableDynamicColor: Boolean = true,
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
@@ -34,6 +35,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -70,7 +72,6 @@ import li.songe.gkd.ui.component.CustomOutlinedTextField
|
||||
import li.songe.gkd.ui.component.PerfCustomIconButton
|
||||
import li.songe.gkd.ui.component.PerfIcon
|
||||
import li.songe.gkd.ui.component.PerfIconButton
|
||||
import li.songe.gkd.ui.component.PerfSwitch
|
||||
import li.songe.gkd.ui.component.PerfTopAppBar
|
||||
import li.songe.gkd.ui.component.SettingItem
|
||||
import li.songe.gkd.ui.component.TextSwitch
|
||||
@@ -286,6 +287,7 @@ fun AdvancedPage() {
|
||||
}
|
||||
})
|
||||
}
|
||||
var showHttpSettingDlg by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
Scaffold(
|
||||
@@ -373,84 +375,91 @@ fun AdvancedPage() {
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.itemPadding(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = "HTTP服务",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
TextSwitch(
|
||||
title = "HTTP服务",
|
||||
subtitle = "在浏览器下连接调试",
|
||||
suffixIcon = {
|
||||
PerfCustomIconButton(
|
||||
size = 32.dp,
|
||||
iconSize = 20.dp,
|
||||
onClickLabel = "打开HTTP设置弹窗",
|
||||
onClick = { showHttpSettingDlg = !showHttpSettingDlg },
|
||||
id = R.drawable.ic_page_info,
|
||||
contentDescription = "HTTP设置",
|
||||
tint = if (showHttpSettingDlg) MaterialTheme.colorScheme.primary else LocalContentColor.current,
|
||||
)
|
||||
CompositionLocalProvider(
|
||||
LocalTextStyle provides MaterialTheme.typography.bodyMedium
|
||||
},
|
||||
checked = httpServerRunning,
|
||||
onCheckedChange = throttle(fn = vm.viewModelScope.launchAsFn<Boolean> {
|
||||
if (it) {
|
||||
requiredPermission(context, foregroundServiceSpecialUseState)
|
||||
requiredPermission(context, notificationState)
|
||||
HttpService.start()
|
||||
} else {
|
||||
HttpService.stop()
|
||||
}
|
||||
})
|
||||
)
|
||||
AnimatedVisibility(visible = httpServerRunning) {
|
||||
CompositionLocalProvider(
|
||||
LocalTextStyle provides MaterialTheme.typography.bodyMedium
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.itemPadding()
|
||||
) {
|
||||
Text(text = if (httpServerRunning) "点击链接打开即可自动连接" else "在浏览器下连接调试工具")
|
||||
AnimatedVisibility(httpServerRunning) {
|
||||
Column {
|
||||
Row {
|
||||
val localUrl = "http://127.0.0.1:${store.httpServerPort}"
|
||||
Text(
|
||||
text = localUrl,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
|
||||
modifier = Modifier.clickable(onClick = throttle {
|
||||
mainVm.openUrl(localUrl)
|
||||
}),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
Text(text = "仅本设备可访问")
|
||||
}
|
||||
localNetworkIps.forEach { host ->
|
||||
val lanUrl = "http://${host}:${store.httpServerPort}"
|
||||
Text(
|
||||
text = lanUrl,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
|
||||
modifier = Modifier.clickable(onClick = throttle {
|
||||
mainVm.openUrl(lanUrl)
|
||||
})
|
||||
)
|
||||
}
|
||||
Text(text = "点击下方链接即可连接")
|
||||
Row {
|
||||
val localUrl = "http://127.0.0.1:${store.httpServerPort}"
|
||||
Text(
|
||||
text = localUrl,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
|
||||
modifier = Modifier.clickable(onClick = throttle {
|
||||
mainVm.openUrl(localUrl)
|
||||
}),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
Text(text = "仅本设备访问")
|
||||
}
|
||||
localNetworkIps.forEach { host ->
|
||||
val lanUrl = "http://${host}:${store.httpServerPort}"
|
||||
Text(
|
||||
text = lanUrl,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
|
||||
modifier = Modifier.clickable(onClick = throttle {
|
||||
mainVm.openUrl(lanUrl)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(visible = showHttpSettingDlg) {
|
||||
Column {
|
||||
SettingItem(
|
||||
title = "服务端口",
|
||||
subtitle = store.httpServerPort.toString(),
|
||||
imageVector = PerfIcon.Edit,
|
||||
onClickLabel = "编辑服务端口",
|
||||
onClick = {
|
||||
showHttpSettingDlg = false
|
||||
showEditPortDlg = true
|
||||
}
|
||||
)
|
||||
TextSwitch(
|
||||
title = "清除订阅",
|
||||
subtitle = "关闭服务时删除内存订阅",
|
||||
checked = store.autoClearMemorySubs,
|
||||
onCheckedChange = {
|
||||
storeFlow.update {
|
||||
it.copy(autoClearMemorySubs = !it.autoClearMemorySubs)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
PerfSwitch(
|
||||
checked = httpServerRunning,
|
||||
onCheckedChange = throttle(fn = vm.viewModelScope.launchAsFn<Boolean> {
|
||||
if (it) {
|
||||
requiredPermission(context, foregroundServiceSpecialUseState)
|
||||
requiredPermission(context, notificationState)
|
||||
HttpService.start()
|
||||
} else {
|
||||
HttpService.stop()
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
SettingItem(
|
||||
title = "服务端口",
|
||||
subtitle = store.httpServerPort.toString(),
|
||||
imageVector = PerfIcon.Edit,
|
||||
onClickLabel = "编辑服务端口",
|
||||
onClick = {
|
||||
showEditPortDlg = true
|
||||
}
|
||||
)
|
||||
|
||||
TextSwitch(
|
||||
title = "清除订阅",
|
||||
subtitle = "关闭服务时删除内存订阅",
|
||||
checked = store.autoClearMemorySubs,
|
||||
onCheckedChange = {
|
||||
storeFlow.update {
|
||||
it.copy(autoClearMemorySubs = !it.autoClearMemorySubs)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "快照",
|
||||
modifier = Modifier.titleItemPadding(),
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -60,6 +61,7 @@ fun PerfCustomIconButton(
|
||||
onClickLabel: String? = null,
|
||||
@DrawableRes id: Int,
|
||||
contentDescription: String? = null,
|
||||
tint: Color = LocalContentColor.current,
|
||||
) = TooltipIconButtonBox(
|
||||
contentDescription = contentDescription,
|
||||
) {
|
||||
@@ -72,6 +74,7 @@ fun PerfCustomIconButton(
|
||||
modifier = Modifier.size(iconSize),
|
||||
id = id,
|
||||
contentDescription = contentDescription,
|
||||
tint = tint,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package li.songe.gkd.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun ScaffoldDialog(
|
||||
title: String,
|
||||
onClose: () -> Unit,
|
||||
content: @Composable (ColumnScope.() -> Unit)
|
||||
) = FullscreenDialog(onDismissRequest = onClose) {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
PerfTopAppBar(
|
||||
title = { Text(text = title) },
|
||||
actions = {
|
||||
PerfIconButton(
|
||||
imageVector = PerfIcon.Close,
|
||||
onClick = onClose,
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(it),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
@@ -294,44 +295,6 @@ fun useSettingsPage(): ScaffoldExt {
|
||||
})
|
||||
}
|
||||
|
||||
var showToastSettingsDlg by vm.showToastSettingsDlgFlow.asMutableState()
|
||||
if (showToastSettingsDlg) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showToastSettingsDlg = false },
|
||||
title = { Text("提示设置") },
|
||||
text = {
|
||||
TextSwitch(
|
||||
paddingDisabled = true,
|
||||
title = "系统提示",
|
||||
subtitle = "系统样式触发提示",
|
||||
suffix = "查看限制",
|
||||
onSuffixClick = {
|
||||
showToastSettingsDlg = false
|
||||
val confirmAction = {
|
||||
mainVm.dialogFlow.value = null
|
||||
showToastSettingsDlg = true
|
||||
}
|
||||
mainVm.dialogFlow.updateDialogOptions(
|
||||
title = "限制说明",
|
||||
text = "系统 Toast 存在频率限制, 触发过于频繁会被系统强制不显示\n\n如果只使用开屏一类低频率规则可使用系统提示, 否则建议关闭此项使用自定义样式提示",
|
||||
confirmAction = confirmAction,
|
||||
onDismissRequest = confirmAction,
|
||||
)
|
||||
},
|
||||
checked = store.useSystemToast,
|
||||
onCheckedChange = {
|
||||
storeFlow.value = store.copy(
|
||||
useSystemToast = it
|
||||
)
|
||||
})
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = { showToastSettingsDlg = false }) {
|
||||
Text("关闭")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var showA11yBlockDlg by vm.showA11yBlockDlgFlow.asMutableState()
|
||||
if (showA11yBlockDlg) {
|
||||
@@ -404,7 +367,7 @@ fun useSettingsPage(): ScaffoldExt {
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
|
||||
val showToastSettingsDlg by vm.showToastSettingsDlgFlow.asMutableState()
|
||||
TextSwitch(
|
||||
title = "触发提示",
|
||||
subtitle = store.actionToast,
|
||||
@@ -418,9 +381,10 @@ fun useSettingsPage(): ScaffoldExt {
|
||||
size = 32.dp,
|
||||
iconSize = 20.dp,
|
||||
onClickLabel = "打开提示设置弹窗",
|
||||
onClick = throttle { showToastSettingsDlg = true },
|
||||
onClick = { vm.showToastSettingsDlgFlow.update { !it } },
|
||||
id = R.drawable.ic_page_info,
|
||||
contentDescription = "提示设置",
|
||||
tint = if (showToastSettingsDlg) MaterialTheme.colorScheme.primary else LocalContentColor.current,
|
||||
)
|
||||
},
|
||||
onCheckedChange = {
|
||||
@@ -429,6 +393,27 @@ fun useSettingsPage(): ScaffoldExt {
|
||||
)
|
||||
})
|
||||
|
||||
AnimatedVisibility(visible = showToastSettingsDlg) {
|
||||
Column {
|
||||
TextSwitch(
|
||||
title = "提示样式",
|
||||
subtitle = "使用系统样式",
|
||||
suffix = "查看限制",
|
||||
onSuffixClick = {
|
||||
mainVm.dialogFlow.updateDialogOptions(
|
||||
title = "限制说明",
|
||||
text = "系统 Toast 存在频率限制, 触发过于频繁会被系统强制不显示\n\n如果只使用开屏一类低频率规则可使用系统提示, 否则建议关闭此项使用自定义样式提示",
|
||||
)
|
||||
},
|
||||
checked = store.useSystemToast,
|
||||
onCheckedChange = {
|
||||
storeFlow.value = store.copy(
|
||||
useSystemToast = it
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val subsStatus by vm.subsStatusFlow.collectAsState()
|
||||
TextSwitch(
|
||||
title = "通知文案",
|
||||
|
||||
@@ -7,7 +7,6 @@ import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -18,8 +17,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
@@ -27,7 +24,6 @@ import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -44,11 +40,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.semantics.onClick
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.stateDescription
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import kotlinx.coroutines.flow.update
|
||||
@@ -64,14 +56,15 @@ import li.songe.gkd.ui.component.AnimationFloatingActionButton
|
||||
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.component.ScaffoldDialog
|
||||
import li.songe.gkd.ui.component.SubsItemCard
|
||||
import li.songe.gkd.ui.component.TextMenu
|
||||
import li.songe.gkd.ui.component.TextSwitch
|
||||
import li.songe.gkd.ui.component.usePinnedScrollBehaviorState
|
||||
import li.songe.gkd.ui.component.waitResult
|
||||
import li.songe.gkd.ui.share.ListPlaceholder
|
||||
import li.songe.gkd.ui.share.LocalMainViewModel
|
||||
import li.songe.gkd.ui.style.EmptyHeight
|
||||
import li.songe.gkd.ui.style.itemVerticalPadding
|
||||
import li.songe.gkd.util.LOCAL_SUBS_ID
|
||||
import li.songe.gkd.util.ShortUrlSet
|
||||
import li.songe.gkd.util.UpdateTimeOption
|
||||
@@ -128,60 +121,25 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||
|
||||
var showSettingsDlg by remember { mutableStateOf(false) }
|
||||
if (showSettingsDlg) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showSettingsDlg = false },
|
||||
title = { Text("订阅设置") },
|
||||
text = {
|
||||
ScaffoldDialog(
|
||||
onClose = { showSettingsDlg = false },
|
||||
title = "订阅设置",
|
||||
content = {
|
||||
val store by storeFlow.collectAsState()
|
||||
Column {
|
||||
TextMenu(
|
||||
modifier = Modifier.padding(0.dp, itemVerticalPadding),
|
||||
title = "更新订阅",
|
||||
option = UpdateTimeOption.objects.findOption(store.updateSubsInterval)
|
||||
) {
|
||||
storeFlow.update { s -> s.copy(updateSubsInterval = it.value) }
|
||||
}
|
||||
val updateValue = throttle {
|
||||
storeFlow.update { it.copy(subsPowerWarn = !it.subsPowerWarn) }
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(0.dp, itemVerticalPadding)
|
||||
.clickable(
|
||||
onClickLabel = if (store.subsPowerWarn) "关闭警告" else "开启警告",
|
||||
onClick = updateValue
|
||||
)
|
||||
.semantics(mergeDescendants = true) {
|
||||
stateDescription = if (store.subsPowerWarn) "已开启" else "已关闭"
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = "耗电警告",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
Text(
|
||||
text = "启用多条订阅时弹窗确认",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
Checkbox(
|
||||
checked = store.subsPowerWarn,
|
||||
onCheckedChange = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = { showSettingsDlg = false }, modifier = Modifier.semantics {
|
||||
onClick(label = "关闭弹窗", action = null)
|
||||
}) {
|
||||
Text("关闭")
|
||||
TextMenu(
|
||||
title = "更新订阅",
|
||||
option = UpdateTimeOption.objects.findOption(store.updateSubsInterval)
|
||||
) {
|
||||
storeFlow.update { s -> s.copy(updateSubsInterval = it.value) }
|
||||
}
|
||||
TextSwitch(
|
||||
title = "耗电警告",
|
||||
subtitle = "启用多条订阅时弹窗确认",
|
||||
checked = store.subsPowerWarn,
|
||||
onCheckedChange = throttle<Boolean> {
|
||||
storeFlow.update { s -> s.copy(subsPowerWarn = it) }
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user