From 22878578a7de6fbb870f1934411b4949e59efa2b Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sun, 2 Feb 2025 19:57:09 +0100 Subject: [PATCH] work on appearance screen --- .../helium314/keyboard/settings/Preference.kt | 10 +- .../keyboard/settings/SettingsActivity.kt | 10 ++ .../settings/dialogs/CustomizeIconsDialog.kt | 53 +++++-- .../settings/dialogs/ListPickerDialog.kt | 26 +++- .../dialogs/SimpleListPickerDialog.kt | 138 ------------------ .../settings/screens/AppearanceScreen.kt | 28 ++-- .../keyboard/settings/screens/DebugScreen.kt | 4 +- 7 files changed, 92 insertions(+), 177 deletions(-) delete mode 100644 app/src/main/java/helium314/keyboard/settings/dialogs/SimpleListPickerDialog.kt diff --git a/app/src/main/java/helium314/keyboard/settings/Preference.kt b/app/src/main/java/helium314/keyboard/settings/Preference.kt index f4fb8eb16..131035c05 100644 --- a/app/src/main/java/helium314/keyboard/settings/Preference.kt +++ b/app/src/main/java/helium314/keyboard/settings/Preference.kt @@ -40,7 +40,7 @@ import helium314.keyboard.latin.R import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.getActivity import helium314.keyboard.latin.utils.prefs -import helium314.keyboard.settings.dialogs.SimpleListPickerDialog +import helium314.keyboard.settings.dialogs.ListPickerDialog import helium314.keyboard.settings.dialogs.SliderDialog // taken from StreetComplete (and a bit SCEE) @@ -230,6 +230,7 @@ fun ListPreference( def: PrefDef, items: List>, default: T, + onChanged: (T) -> Unit = { } ) { var showDialog by remember { mutableStateOf(false) } val prefs = LocalContext.current.prefs() @@ -240,12 +241,13 @@ fun ListPreference( onClick = { showDialog = true } ) if (showDialog) { - SimpleListPickerDialog( + ListPickerDialog( onDismissRequest = { showDialog = false }, items = items, onItemSelected = { - if (it != selected) - putPrefOfType(prefs, def.key, it.second) + if (it == selected) return@ListPickerDialog + putPrefOfType(prefs, def.key, it.second) + onChanged(it.second) }, selectedItem = selected, title = { Text(def.title) }, diff --git a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt index 9483ba24c..3e5373470 100644 --- a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt +++ b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt @@ -16,12 +16,22 @@ import kotlinx.coroutines.flow.MutableStateFlow // todo (roughly in order) // make all prefs actually work // appearance +// holo white selectable for non-holo style if we had selected holo theme before +// the list just stays the old one after changing the setting +// also, even if selected it should not be used... +// click on bg image does nothing when already set (but works after reload) +// split spacer scale setting does not reload? +// narrow key gaps setting is not changing properly? +// custom font loading not implemented +// have large bg image, and first-time load the keyboard on new search field -> bg image expands full size // advanced // preferences // try moving the recomposition of pref change somewhere else, so it's not duplicated everywhere // make the pref lists more compact (compare with old settings) // try making text size similar to old state (also in dialogs) // check whether dialogs have the same colors, i think currently it's a bit inconsistent +// see all the properties for each alertDialog -> any way to set it in a single place? +// title too huge for bg image and text on spacebar dialogs, also maybe somewhere else -> where to set in one place? // check dark and light theme (don't have dynamic) // rename both settingsActivities // work on todos in other files diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/CustomizeIconsDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/CustomizeIconsDialog.kt index de1148722..c3eb7bb35 100644 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/CustomizeIconsDialog.kt +++ b/app/src/main/java/helium314/keyboard/settings/dialogs/CustomizeIconsDialog.kt @@ -4,6 +4,7 @@ import android.graphics.drawable.VectorDrawable import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -18,6 +19,7 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue @@ -32,6 +34,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.DialogProperties import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap import androidx.core.util.TypedValueCompat @@ -50,26 +53,40 @@ fun CustomizeIconsDialog( ) { val state = rememberLazyListState() val ctx = LocalContext.current - val iconsAndNames = KeyboardIconsSet.getAllIcons(ctx).keys.map { iconName -> - val name = iconName.getStringResourceOrName("", ctx) - if (name == iconName) iconName to iconName.getStringResourceOrName("label_", ctx) - else iconName to name - }.sortedBy { it.second } + var iconsAndNames by remember { mutableStateOf( + KeyboardIconsSet.getAllIcons(ctx).keys.map { iconName -> + val name = iconName.getStringResourceOrName("", ctx) + if (name == iconName) iconName to iconName.getStringResourceOrName("label_", ctx) + else iconName to name + }.sortedBy { it.second } + ) } + fun reloadItem(iconName: String) { + iconsAndNames = iconsAndNames.map { item -> + if (item.first == iconName) { + item.first to if (item.second.endsWith(" ")) item.second.trimEnd() else item.second + " " + } + else item + } + } var showIconDialog: Pair? by remember { mutableStateOf(null) } var showDeletePrefConfirmDialog by remember { mutableStateOf(false) } val prefs = ctx.prefs() AlertDialog( onDismissRequest = onDismissRequest, - confirmButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(R.string.dialog_close)) } }, + confirmButton = { }, dismissButton = { - if (prefs.contains(prefKey)) - TextButton(onClick = { showDeletePrefConfirmDialog = true }) - { Text(stringResource(R.string.button_default)) } + Row { + if (prefs.contains(prefKey)) + TextButton(onClick = { showDeletePrefConfirmDialog = true }) + { Text(stringResource(R.string.button_default)) } + Spacer(Modifier.weight(1f)) + TextButton(onClick = onDismissRequest) { Text(stringResource(R.string.dialog_close)) } + } }, title = { Text(stringResource(R.string.customize_icons)) }, text = { LazyColumn(state = state) { - items(iconsAndNames, key = { it.first }) { (iconName, displayName) -> + items(iconsAndNames, key = { it.second }) { (iconName, displayName) -> Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { showIconDialog = iconName to displayName } @@ -80,6 +97,11 @@ fun CustomizeIconsDialog( } } }, + shape = MaterialTheme.shapes.medium, + containerColor = MaterialTheme.colorScheme.surface, + textContentColor = contentColorFor(MaterialTheme.colorScheme.surface), + properties = DialogProperties(), + ) if (showIconDialog != null) { val iconName = showIconDialog!!.first @@ -91,7 +113,7 @@ fun CustomizeIconsDialog( val icons = iconsSet.toList() var selectedIcon by remember { mutableStateOf(KeyboardIconsSet.instance.iconIds[iconName]) } ThreeButtonAlertDialog( - onDismissRequest = onDismissRequest, + onDismissRequest = { showIconDialog = null }, onConfirmed = { runCatching { val newIcons = customIconNames(prefs).toMutableMap() @@ -99,7 +121,7 @@ fun CustomizeIconsDialog( prefs.edit().putString(prefKey, Json.encodeToString(newIcons)).apply() KeyboardIconsSet.instance.loadIcons(ctx) } - // todo: show outer dialog again and reload icons? + reloadItem(iconName) }, neutralButtonText = if (customIconNames(prefs).contains(iconName)) stringResource(R.string.button_default) else null, onNeutral = { @@ -110,7 +132,7 @@ fun CustomizeIconsDialog( else prefs.edit().putString(prefKey, Json.encodeToString(icons2)).apply() KeyboardIconsSet.instance.loadIcons(ctx) } - // todo: show outer dialog again and reload icons? + reloadItem(iconName) }, title = { Text(showIconDialog!!.second) }, text = { @@ -141,16 +163,19 @@ fun CustomizeIconsDialog( }, ) } - if (showDeletePrefConfirmDialog) + if (showDeletePrefConfirmDialog) { + val ctx = LocalContext.current ConfirmationDialog( onDismissRequest = { showDeletePrefConfirmDialog = false }, onConfirmed = { showDeletePrefConfirmDialog = false onDismissRequest() prefs.edit().remove(prefKey).apply() + KeyboardIconsSet.instance.loadIcons(ctx) }, text = { Text(stringResource(R.string.customize_icons_reset_message)) } ) + } } @Preview diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/ListPickerDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/ListPickerDialog.kt index f5687d73f..6ae65cab4 100644 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/ListPickerDialog.kt +++ b/app/src/main/java/helium314/keyboard/settings/dialogs/ListPickerDialog.kt @@ -41,6 +41,7 @@ fun ListPickerDialog( title: (@Composable () -> Unit)? = null, selectedItem: T? = null, getItemName: (@Composable (T) -> String) = { it.toString() }, + confirmImmediately: Boolean = true, width: Dp? = null, height: Dp? = null, shape: Shape = MaterialTheme.shapes.medium, @@ -58,10 +59,11 @@ fun ListPickerDialog( AlertDialog( onDismissRequest = onDismissRequest, confirmButton = { - TextButton( - onClick = { onDismissRequest(); selected?.let { onItemSelected(it) } }, - enabled = selected != null, - ) { Text(stringResource(android.R.string.ok)) } + if (!confirmImmediately) + TextButton( + onClick = { onDismissRequest(); selected?.let { onItemSelected(it) } }, + enabled = selected != null, + ) { Text(stringResource(android.R.string.ok)) } }, modifier = modifier, dismissButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(android.R.string.cancel)) } }, @@ -76,7 +78,13 @@ fun ListPickerDialog( horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .clickable { selected = item } + .clickable { + if (confirmImmediately) { + onDismissRequest() + onItemSelected(item) + } + selected = item + } .padding(horizontal = 24.dp) ) { Text( @@ -86,7 +94,13 @@ fun ListPickerDialog( ) RadioButton( selected = selected == item, - onClick = { selected = item } + onClick = { + if (confirmImmediately) { + onDismissRequest() + onItemSelected(item) + } + selected = item + } ) } } diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/SimpleListPickerDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/SimpleListPickerDialog.kt deleted file mode 100644 index a606a6e5c..000000000 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/SimpleListPickerDialog.kt +++ /dev/null @@ -1,138 +0,0 @@ -package helium314.keyboard.settings.dialogs - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.contentColorFor -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties - -// taken from StreetComplete -/** Similar to ListPickerDialog, but tapping on one item immediately closes the dialog - * (no OK button, no cancel button) - * - * This dialog doesn't have the caveat of the ListPickerDialog in that it takes as much width - * as possible */ -@Composable -fun SimpleListPickerDialog( - onDismissRequest: () -> Unit, - items: List, - onItemSelected: (T) -> Unit, - title: (@Composable () -> Unit)? = null, - selectedItem: T? = null, - getItemName: (@Composable (T) -> String) = { it.toString() }, - shape: Shape = MaterialTheme.shapes.medium, - backgroundColor: Color = MaterialTheme.colorScheme.surface, - contentColor: Color = contentColorFor(backgroundColor), - properties: DialogProperties = DialogProperties() -) { - val selected by remember { mutableStateOf(selectedItem) } - val state = rememberLazyListState() - - fun select(item: T) { - onDismissRequest() - onItemSelected(item) - } - - LaunchedEffect(selectedItem) { - val index = items.indexOf(selectedItem) - if (index != -1) state.scrollToItem(index, -state.layoutInfo.viewportSize.height / 3) - } - - Dialog( - onDismissRequest = onDismissRequest, - properties = properties - ) { - Surface( - shape = shape, - color = backgroundColor, - contentColor = contentColor - ) { - Column(Modifier.padding(vertical = 24.dp)) { - if (title != null) { - CompositionLocalProvider( - LocalTextStyle provides MaterialTheme.typography.titleLarge - ) { - Column(Modifier.padding(start = 24.dp, bottom = 16.dp, end = 24.dp)) { - title() - } - } - } - if (state.canScrollBackward) HorizontalDivider() - CompositionLocalProvider( - LocalTextStyle provides MaterialTheme.typography.bodyLarge - ) { - LazyColumn(state = state) { - items(items) { item -> - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clickable { select(item) } - .padding(horizontal = 24.dp) - ) { - Text( - text = getItemName(item), - style = MaterialTheme.typography.bodyLarge, - modifier = Modifier.weight(1f), - ) - RadioButton( - selected = selected == item, - onClick = { select(item) } - ) - } - } - } - } - if (state.canScrollForward) HorizontalDivider() - // todo: button not visible when there are many entries - Row(Modifier.padding(end = 24.dp)) { - Spacer(Modifier.weight(1f)) - TextButton( - onClick = onDismissRequest, - ) { Text(stringResource(android.R.string.cancel)) } - } - } - } - } -} - -@Preview -@Composable -private fun PreviewSimpleListPickerDialog() { - val items = remember { (0..<5).toList() } - SimpleListPickerDialog( - onDismissRequest = {}, - items = items, - onItemSelected = {}, - title = { Text("Select something") }, - selectedItem = 2, - getItemName = { "Item $it" }, - ) -} diff --git a/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt index 0785cde9f..6e7676671 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt @@ -34,7 +34,6 @@ import helium314.keyboard.latin.settings.SettingsValues import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.getActivity import helium314.keyboard.latin.utils.getStringResourceOrName -import helium314.keyboard.latin.utils.infoDialog import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.switchTo import helium314.keyboard.settings.AllPrefs @@ -92,7 +91,6 @@ fun AppearanceScreen( SettingsActivity2.allPrefs.map[Settings.PREF_ENABLE_SPLIT_KEYBOARD]!!.Preference() SettingsActivity2.allPrefs.map[Settings.PREF_SPLIT_SPACER_SCALE]!!.Preference() SettingsActivity2.allPrefs.map[Settings.PREF_NARROW_KEY_GAPS]!!.Preference() - SettingsActivity2.allPrefs.map[Settings.PREF_NARROW_KEY_GAPS]!!.Preference() SettingsActivity2.allPrefs.map[Settings.PREF_KEYBOARD_HEIGHT_SCALE]!!.Preference() SettingsActivity2.allPrefs.map[Settings.PREF_BOTTOM_PADDING_SCALE]!!.Preference() SettingsActivity2.allPrefs.map[Settings.PREF_SPACE_BAR_TEXT]!!.Preference() @@ -122,7 +120,7 @@ fun createAppearancePrefs(context: Context) = listOf( def, items, KeyboardTheme.STYLE_MATERIAL - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_CUSTOM_ICON_NAMES, R.string.customize_icons) { def -> var showDialog by remember { mutableStateOf(false) } @@ -142,7 +140,7 @@ fun createAppearancePrefs(context: Context) = listOf( val ctx = LocalContext.current val currentStyle = ctx.prefs().getString(Settings.PREF_THEME_STYLE, KeyboardTheme.STYLE_MATERIAL) val items = KeyboardTheme.COLORS.mapNotNull { - if (it == KeyboardTheme.THEME_HOLO_WHITE && currentStyle == KeyboardTheme.STYLE_HOLO) + if (it == KeyboardTheme.THEME_HOLO_WHITE && currentStyle != KeyboardTheme.STYLE_HOLO) return@mapNotNull null it.getStringResourceOrName("theme_name_", ctx) to it } @@ -150,7 +148,7 @@ fun createAppearancePrefs(context: Context) = listOf( def, items, KeyboardTheme.THEME_LIGHT - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_THEME_COLORS_NIGHT, R.string.theme_colors_night) { def -> val ctx = LocalContext.current @@ -164,7 +162,7 @@ fun createAppearancePrefs(context: Context) = listOf( def, items, KeyboardTheme.THEME_DARK - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, NonSettingsPrefs.ADJUST_COLORS, R.string.select_user_colors, R.string.select_user_colors_summary) { def -> val ctx = LocalContext.current @@ -192,7 +190,7 @@ fun createAppearancePrefs(context: Context) = listOf( SwitchPreference(def, false) }, PrefDef(context, Settings.PREF_THEME_DAY_NIGHT, R.string.day_night_mode, R.string.day_night_mode_summary) { def -> - SwitchPreference(def, Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + SwitchPreference(def, Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_NAVBAR_COLOR, R.string.theme_navbar, R.string.day_night_mode_summary) { def -> SwitchPreference(def, Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) @@ -280,10 +278,10 @@ fun createAppearancePrefs(context: Context) = listOf( default = SettingsValues.DEFAULT_SIZE_SCALE, range = 0.5f..2f, description = { "${(100 * it).toInt()}%" } - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_NARROW_KEY_GAPS, R.string.prefs_narrow_key_gaps) { - SwitchPreference(it, false) + SwitchPreference(it, false) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_KEYBOARD_HEIGHT_SCALE, R.string.prefs_keyboard_height_scale) { SliderPreference( @@ -292,7 +290,7 @@ fun createAppearancePrefs(context: Context) = listOf( default = SettingsValues.DEFAULT_SIZE_SCALE, range = 0.5f..1.5f, description = { "${(100 * it).toInt()}%" } - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_BOTTOM_PADDING_SCALE, R.string.prefs_bottom_padding_scale) { SliderPreference( @@ -301,7 +299,7 @@ fun createAppearancePrefs(context: Context) = listOf( default = SettingsValues.DEFAULT_SIZE_SCALE, range = 0f..5f, description = { "${(100 * it).toInt()}%" } - ) + ) { keyboardNeedsReload = true } }, PrefDef(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) { def -> var showDialog by remember { mutableStateOf(false) } @@ -314,9 +312,13 @@ fun createAppearancePrefs(context: Context) = listOf( if (showDialog) { TextInputDialog( onDismissRequest = { showDialog = false }, - onConfirmed = { prefs.edit().putString(def.key, it).apply() }, + onConfirmed = { + prefs.edit().putString(def.key, it).apply() + keyboardNeedsReload = true + }, initialText = prefs.getString(def.key, "") ?: "", - title = { Text(def.title) } + title = { Text(def.title) }, + checkTextValid = { true } ) } }, diff --git a/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt index 7bbb47f68..4233fed3c 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt @@ -73,7 +73,7 @@ fun createDebugPrefs(context: Context) = listOf( if (!it) prefs.edit().putBoolean(DebugSettings.PREF_SHOW_SUGGESTION_INFOS, false).apply() showConfirmDialog = true } - if (showConfirmDialog) { + if (showConfirmDialog) { // todo: maybe do it differently? ConfirmationDialog( onDismissRequest = { showConfirmDialog = false }, onConfirmed = { Runtime.getRuntime().exit(0) }, @@ -87,7 +87,7 @@ fun createDebugPrefs(context: Context) = listOf( PrefDef(context, DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, R.string.prefs_force_non_distinct_multitouch) { def -> var showConfirmDialog by remember { mutableStateOf(false) } SwitchPreference(def, false) { showConfirmDialog = true } - if (showConfirmDialog) { + if (showConfirmDialog) { // todo: maybe do it differently? ConfirmationDialog( onDismissRequest = { showConfirmDialog = false }, onConfirmed = { Runtime.getRuntime().exit(0) },