Compare commits

...

4 Commits

Author SHA1 Message Date
lisonge
e5a2f44521 feat: update dependency
Some checks failed
Build-Apk / build (push) Has been cancelled
2024-06-14 22:22:19 +08:00
lisonge
0ad0e1d9e7 perf: increase app item padding 2024-06-14 22:21:56 +08:00
lisonge
eaa7ee0ee1 feat: tow line text, inner disable explain, 2024-06-14 22:21:22 +08:00
lisonge
6f2d47ea04 perf: app search bar style 2024-06-14 20:49:33 +08:00
12 changed files with 147 additions and 122 deletions

View File

@ -1,6 +1,7 @@
package li.songe.gkd.ui
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
@ -19,6 +20,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Sort
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton
@ -30,6 +32,7 @@ import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
@ -177,6 +180,7 @@ fun AppConfigPage(appId: String) {
}
val checked = getChecked(excludeData, g.group, appId, appInfo)
AppGroupCard(
vm = vm,
group = g.group,
checked = checked,
onClick = {
@ -211,15 +215,20 @@ fun AppConfigPage(appId: String) {
}
}
items(appGroups) { g ->
AppGroupCard(g.group, g.enable, onClick = {
navController.navigate(
AppItemPageDestination(
g.subsItem.id,
appId,
g.group.key,
AppGroupCard(
vm = vm,
group = g.group,
checked = g.enable,
onClick = {
navController.navigate(
AppItemPageDestination(
g.subsItem.id,
appId,
g.group.key,
)
)
)
}) {
}
) {
vm.viewModelScope.launchTry {
DbSet.subsConfigDao.insert(
g.config?.copy(enable = it) ?: SubsConfig(
@ -248,10 +257,28 @@ fun AppConfigPage(appId: String) {
}
}
}
val innerDisabledDlg by vm.innerDisabledDlgFlow.collectAsState()
if (innerDisabledDlg) {
AlertDialog(
title = { Text(text = "内置禁用") },
text = {
Text(text = "此规则组已经在其 apps 字段中配置对当前应用的禁用, 因此无法手动开启规则组\n\n提示: 这种情况一般在此全局规则无法适配/跳过适配当前应用时出现")
},
onDismissRequest = { vm.innerDisabledDlgFlow.value = false },
confirmButton = {
TextButton(onClick = { vm.innerDisabledDlgFlow.value = false }) {
Text(text = "我知道了")
}
}
)
}
}
@Composable
private fun AppGroupCard(
vm: AppConfigVm,
group: RawSubscription.RawGroupProps,
checked: Boolean?,
onClick: () -> Unit,
@ -313,7 +340,13 @@ private fun AppGroupCard(
Switch(
checked = false,
enabled = false,
onCheckedChange = onCheckedChange
onCheckedChange = null,
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
) {
vm.innerDisabledDlgFlow.value = true
}
)
}
}

View File

@ -74,5 +74,7 @@ class AppConfigVm @Inject constructor(stateHandle: SavedStateHandle) : ViewModel
}
}.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
val innerDisabledDlgFlow = MutableStateFlow(false)
}

View File

@ -67,6 +67,7 @@ import li.songe.gkd.data.RawSubscription
import li.songe.gkd.data.SubsConfig
import li.songe.gkd.data.stringify
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.TowLineText
import li.songe.gkd.ui.component.getDialogResult
import li.songe.gkd.ui.destinations.GroupItemPageDestination
import li.songe.gkd.ui.style.itemPadding
@ -132,19 +133,10 @@ fun AppItemPage(
)
}
}, title = {
Column {
Text(
text = subsRaw?.name ?: subsItemId.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = appInfoCache[appId]?.name ?: appRaw.name ?: appId,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyMedium,
)
}
TowLineText(
title = subsRaw?.name ?: subsItemId.toString(),
subTitle = appInfoCache[appId]?.name ?: appRaw.name ?: appId
)
}, actions = {})
}, floatingActionButton = {
if (editable) {

View File

@ -40,7 +40,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
@ -50,6 +49,7 @@ import kotlinx.coroutines.Dispatchers
import li.songe.gkd.data.CategoryConfig
import li.songe.gkd.data.RawSubscription
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.TowLineText
import li.songe.gkd.ui.component.getDialogResult
import li.songe.gkd.ui.style.itemPadding
import li.songe.gkd.util.EnableGroupOption
@ -94,14 +94,10 @@ fun CategoryPage(subsItemId: Long) {
)
}
}, title = {
Column {
Text(
text = subsRaw?.name ?: subsItemId.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(text = "规则类别", style = MaterialTheme.typography.bodyMedium)
}
TowLineText(
title = subsRaw?.name ?: subsItemId.toString(),
subTitle = "规则类别"
)
}, actions = {})
}, floatingActionButton = {
if (editable) {

View File

@ -69,6 +69,7 @@ import li.songe.gkd.data.stringify
import li.songe.gkd.db.DbSet
import li.songe.gkd.service.launcherAppId
import li.songe.gkd.ui.component.AppBarTextField
import li.songe.gkd.ui.component.TowLineText
import li.songe.gkd.ui.style.appItemPadding
import li.songe.gkd.ui.style.menuPadding
import li.songe.gkd.util.LocalNavController
@ -129,19 +130,10 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
modifier = Modifier.focusRequester(focusRequester)
)
} else {
Column {
Text(
text = rawSubs?.name ?: subsItemId.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = (group?.name ?: groupKey.toString()),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyMedium
)
}
TowLineText(
title = rawSubs?.name ?: subsItemId.toString(),
subTitle = (group?.name ?: groupKey.toString())
)
}
}, actions = {
if (showSearchBar) {

View File

@ -63,6 +63,7 @@ import kotlinx.coroutines.Dispatchers
import li.songe.gkd.data.RawSubscription
import li.songe.gkd.data.SubsConfig
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.TowLineText
import li.songe.gkd.ui.component.getDialogResult
import li.songe.gkd.ui.destinations.GlobalRuleExcludePageDestination
import li.songe.gkd.ui.destinations.GroupItemPageDestination
@ -116,14 +117,10 @@ fun GlobalRulePage(subsItemId: Long, focusGroupKey: Int? = null) {
)
}
}, title = {
Column {
Text(
text = rawSubs?.name ?: subsItemId.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(text = "全局规则", style = MaterialTheme.typography.bodyMedium)
}
TowLineText(
title = rawSubs?.name ?: subsItemId.toString(),
subTitle = "全局规则"
)
})
},
floatingActionButton = {

View File

@ -1,7 +1,6 @@
package li.songe.gkd.ui
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -46,7 +45,6 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
@ -58,6 +56,7 @@ import li.songe.gkd.data.SubsConfig
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.AppBarTextField
import li.songe.gkd.ui.component.SubsAppCard
import li.songe.gkd.ui.component.TowLineText
import li.songe.gkd.ui.component.getDialogResult
import li.songe.gkd.ui.destinations.AppItemPageDestination
import li.songe.gkd.ui.style.menuPadding
@ -150,14 +149,10 @@ fun SubsPage(
modifier = Modifier.focusRequester(focusRequester)
)
} else {
Column {
Text(
text = subsRaw?.name ?: subsItemId.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(text = "应用规则", style = MaterialTheme.typography.bodyMedium)
}
TowLineText(
title = subsRaw?.name ?: subsItemId.toString(),
subTitle = "应用规则",
)
}
}, actions = {
if (showSearchBar) {

View File

@ -7,14 +7,12 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TextFieldDefaults.indicatorLine
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -22,9 +20,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
@ -42,19 +38,17 @@ fun AppBarTextField(
keyboardActions: KeyboardActions = KeyboardActions.Default,
) {
val interactionSource = remember { MutableInteractionSource() }
val textStyle = LocalTextStyle.current
// make sure there is no background color in the decoration box
val colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Unspecified,
unfocusedContainerColor = Color.Unspecified,
disabledContainerColor = Color.Unspecified,
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
)
// If color is not provided via the text style, use content color as a default
val textColor = textStyle.color.takeOrElse {
MaterialTheme.colorScheme.onSurface
}
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
val mergedTextStyle = LocalTextStyle.current.merge(MaterialTheme.typography.titleMedium)
// request focus when this composable is first initialized
// val focusRequester = FocusRequester()
@ -68,47 +62,43 @@ fun AppBarTextField(
}
textFieldValue = textFieldValue.copy(text = value) // make sure to keep the value updated
CompositionLocalProvider(
LocalTextSelectionColors provides LocalTextSelectionColors.current
) {
BasicTextField(
value = textFieldValue,
onValueChange = {
textFieldValue = it
// remove newlines to avoid strange layout issues, and also because singleLine=true
onValueChange(it.text.replace("\n", ""))
},
modifier = modifier
.fillMaxWidth()
.heightIn(32.dp)
.indicatorLine(
enabled = true,
isError = false,
interactionSource = interactionSource,
colors = colors
),
BasicTextField(
value = textFieldValue,
onValueChange = {
textFieldValue = it
// remove newlines to avoid strange layout issues, and also because singleLine=true
onValueChange(it.text.replace("\n", ""))
},
modifier = modifier
.fillMaxWidth()
.heightIn(32.dp)
.indicatorLine(
enabled = true,
isError = false,
interactionSource = interactionSource,
colors = colors
),
// .focusRequester(focusRequester),
textStyle = mergedTextStyle,
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = true,
decorationBox = { innerTextField ->
// places text field with placeholder and appropriate bottom padding
TextFieldDefaults.DecorationBox(
value = value,
innerTextField = innerTextField,
enabled = true,
singleLine = true,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
isError = false,
placeholder = { Text(text = hint) },
colors = colors,
contentPadding = PaddingValues(bottom = 4.dp),
)
},
)
}
textStyle = mergedTextStyle,
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = true,
decorationBox = { innerTextField ->
// places text field with placeholder and appropriate bottom padding
TextFieldDefaults.DecorationBox(
value = value,
innerTextField = innerTextField,
enabled = true,
singleLine = true,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
isError = false,
placeholder = { Text(text = hint) },
colors = colors,
contentPadding = PaddingValues(bottom = 4.dp),
)
},
)
}

View File

@ -0,0 +1,28 @@
package li.songe.gkd.ui.component
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.style.TextOverflow
@Composable
fun TowLineText(
title: String,
subTitle: String
) {
Column {
Text(
text = title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleMedium
)
Text(
text = subTitle,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleSmall
)
}
}

View File

@ -7,7 +7,7 @@ import androidx.compose.ui.unit.dp
fun Modifier.itemPadding() = this then padding(16.dp, 12.dp)
fun Modifier.appItemPadding() = this then padding(10.dp, 8.dp)
fun Modifier.appItemPadding() = this then padding(10.dp, 10.dp)
fun Modifier.menuPadding() =
this then padding(MenuDefaults.DropdownMenuItemContentPadding).padding(vertical = 8.dp)

View File

@ -189,8 +189,8 @@ val ruleSummaryFlow by lazy {
val subGlobalGroupToRules =
mutableMapOf<RawSubscription.RawGlobalGroup, List<GlobalRule>>()
rawSubs.globalGroups.filter { g ->
g.valid && (subGlobalSubsConfigs.find { c -> c.groupKey == g.key }?.enable
?: g.enable ?: true)
(subGlobalSubsConfigs.find { c -> c.groupKey == g.key }?.enable
?: g.enable ?: true) && g.valid
}.forEach { groupRaw ->
val config = subGlobalSubsConfigs.find { c -> c.groupKey == groupRaw.key }
val g = ResolvedGlobalGroup(

View File

@ -6,7 +6,7 @@ targetSdk = "34"
buildToolsVersion = "34.0.0"
minSdk = "26"
android = "8.4.2"
compose = "1.6.7"
compose = "1.6.8"
rikka = "4.4.0"
room = "2.6.1"
paging = "3.3.0"
@ -39,7 +39,7 @@ others_jankson = { module = "blue.endless:jankson", version = "1.2.3" }
others_floating_bubble_view = { module = "io.github.torrydo:floating-bubble-view", version = "0.6.5" }
androidx_appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" }
androidx_core_ktx = { module = "androidx.core:core-ktx", version = "1.13.1" }
androidx_lifecycle_runtime_ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version = "2.8.1" }
androidx_lifecycle_runtime_ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version = "2.8.2" }
androidx_junit = { module = "androidx.test.ext:junit", version = "1.1.5" }
androidx_espresso = { module = "androidx.test.espresso:espresso-core", version = "3.5.1" }
androidx_room_runtime = { module = "androidx.room:room-runtime", version.ref = "room" }