add new settings with search functionality (WIP)

This commit is contained in:
Helium314 2025-01-25 22:07:56 +01:00
parent fc12877795
commit e1be94112e
21 changed files with 1539 additions and 11 deletions

View file

@ -0,0 +1,237 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings
import androidx.annotation.DrawableRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.Hyphens
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import helium314.keyboard.latin.R
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.Log
// taken from StreetComplete (and a bit SCEE)
@Composable
fun PreferenceCategory(
title: String?,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) {
Column {
HorizontalDivider()
if (title != null) {
Text(
text = title,
modifier = modifier.padding(top = 12.dp, start = 16.dp, end = 8.dp, bottom = 8.dp),
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.titleSmall
)
}
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodyLarge) {
Column {
content()
}
}
}
}
@Composable
fun Preference(
name: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
description: String? = null,
@DrawableRes icon: Int? = null,
value: @Composable (RowScope.() -> Unit)? = null,
) {
Column(
modifier = modifier
.fillMaxWidth()
.clickable { onClick() }
.heightIn(min = 48.dp)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(
space = 0.dp,
alignment = Alignment.CenterVertically
)
) {
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (icon != null)
Icon(painterResource(icon), name, modifier = Modifier.size(48.dp).padding(end = 8.dp))
Column(modifier = Modifier.weight(2 / 3f)) {
Text(text = name,)
if (description != null) {
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.bodyMedium,
LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant
) {
Text(
text = description,
modifier = Modifier.padding(top = 8.dp)
)
}
}
}
if (value != null) {
CompositionLocalProvider(
LocalTextStyle provides LocalTextStyle.current.copy(
textAlign = TextAlign.End,
hyphens = Hyphens.Auto
),
LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant
) {
Row(
horizontalArrangement = Arrangement.spacedBy(
space = 8.dp,
alignment = Alignment.End
),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1 / 3f)
) { value() }
}
}
}
}
}
@Composable
fun SwitchPreference(
name: String,
modifier: Modifier = Modifier,
pref: String,
default: Boolean,
description: String? = null,
allowCheckedChange: (Boolean) -> Boolean = { true }, // true means ok, usually for showing some dialog
onCheckedChange: (Boolean) -> Unit = { },
) {
val ctx = LocalContext.current
val prefs = DeviceProtectedUtils.getSharedPreferences(ctx)
val b = (ctx.getActivity() as SettingsActivity2).prefChanged.collectAsState()
var value = prefs.getBoolean(pref, default)
if (b.value < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
fun switched(newValue: Boolean) {
if (!allowCheckedChange(newValue)) {
value = !newValue
return
}
value = newValue
prefs.edit().putBoolean(pref, newValue).apply()
onCheckedChange(newValue)
}
Preference(
name = name,
onClick = { switched(!value) },
modifier = modifier,
description = description
) {
Switch(
checked = value,
onCheckedChange = { switched(it) },
// switch is really ugly... how
// colors = SwitchDefaults.colors(uncheckedBorderColor = Color.Transparent)
)
}
}
@Composable
fun SwitchPreference(
def: PrefDef,
default: Boolean,
modifier: Modifier = Modifier,
allowCheckedChange: (Boolean) -> Boolean = { true },
onCheckedChange: (Boolean) -> Unit = { }
) {
SwitchPreference(
name = def.title,
description = def.description,
pref = def.key,
default = default,
modifier = modifier,
allowCheckedChange = allowCheckedChange,
onCheckedChange = onCheckedChange
)
}
@Preview
@Composable
private fun PreferencePreview() {
PreferenceCategory("Preference Category") {
Preference(
name = "Preference",
onClick = {},
)
Preference(
name = "Preference with icon",
onClick = {},
icon = R.drawable.ic_settings_about_foreground
)
Preference(
name = "Preference with icon and description",
description = "some text",
onClick = {},
icon = R.drawable.ic_settings_about_foreground
)
Preference(
name = "Preference with switch",
onClick = {}
) {
Switch(checked = true, onCheckedChange = {})
}
SwitchPreference(
name = "SwitchPreference",
pref = "none",
default = true
)
Preference(
name = "Preference",
onClick = {},
description = "A long description which may actually be several lines long, so it should wrap."
) {
Icon(painterResource(R.drawable.ic_arrow_left), null)
}
Preference(
name = "Long preference name that wraps",
onClick = {},
) {
Text("Long preference value")
}
Preference(
name = "Long preference name 2",
onClick = {},
description = "hello I am description"
) {
Text("Long preference value")
}
}
}