complete preferences screen

This commit is contained in:
Helium314 2025-02-06 15:52:54 +01:00
parent 8f5ef56f60
commit ae461fe8b6
4 changed files with 205 additions and 83 deletions

View file

@ -31,17 +31,22 @@ 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.res.stringResource
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 androidx.core.content.edit
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
import helium314.keyboard.latin.R
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.dialogs.ListPickerDialog
import helium314.keyboard.settings.dialogs.ReorderDialog
import helium314.keyboard.settings.dialogs.SliderDialog
import helium314.keyboard.settings.screens.GetIcon
// taken from StreetComplete (and a bit SCEE)
@ -256,6 +261,91 @@ fun <T: Any> ListPreference(
}
}
@Composable
fun ReorderSwitchPreference(def: PrefDef, default: String) {
var showDialog by remember { mutableStateOf(false) }
Preference(
name = def.title,
description = def.description,
onClick = { showDialog = true },
)
if (showDialog) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
val items = prefs.getString(def.key, default)!!.split(";").mapTo(ArrayList()) {
val both = it.split(",")
KeyAndState(both.first(), both.last().toBoolean())
}
ReorderDialog(
onConfirmed = { reorderedItems ->
val value = reorderedItems.joinToString(";") { it.name + "," + it.state }
prefs.edit().putString(def.key, value).apply()
keyboardNeedsReload = true
},
onDismissRequest = { showDialog = false },
onNeutral = { prefs.edit().remove(def.key).apply() },
neutralButtonText = if (prefs.contains(def.key)) stringResource(R.string.button_default) else null,
items = items,
title = { Text(def.title) },
displayItem = { item ->
var checked by remember { mutableStateOf(item.state) }
Row(verticalAlignment = Alignment.CenterVertically) {
KeyboardIconsSet.instance.GetIcon(item.name)
val text = item.name.lowercase().getStringResourceOrName("", ctx)
Text(text, Modifier.weight(1f))
Switch(
checked = checked,
onCheckedChange = { item.state = it; checked = it }
)
}
},
getKey = { it.name }
)
}
}
@Composable
fun ToolbarKeyReorderDialog(
prefKey: String,
default: String,
title: String,
onDismiss: () -> Unit
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
val items = prefs.getString(prefKey, default)!!.split(";").mapTo(ArrayList()) {
val both = it.split(",")
KeyAndState(both.first(), both.last().toBoolean())
}
ReorderDialog(
onConfirmed = { reorderedItems ->
val value = reorderedItems.joinToString(";") { it.name + "," + it.state }
prefs.edit().putString(prefKey, value).apply()
keyboardNeedsReload = true
},
onDismissRequest = onDismiss,
onNeutral = { prefs.edit().remove(prefKey).apply() },
neutralButtonText = if (prefs.contains(prefKey)) stringResource(R.string.button_default) else null,
items = items,
title = { Text(title) },
displayItem = { item ->
var checked by remember { mutableStateOf(item.state) }
Row(verticalAlignment = Alignment.CenterVertically) {
KeyboardIconsSet.instance.GetIcon(item.name)
val text = item.name.lowercase().getStringResourceOrName("", ctx)
Text(text, Modifier.weight(1f))
Switch(
checked = checked,
onCheckedChange = { item.state = it; checked = it }
)
}
},
getKey = { it.name }
)
}
private class KeyAndState(var name: String, var state: Boolean)
private fun <T: Any> getPrefOfType(prefs: SharedPreferences, key: String, default: T): T =
when (default) {
is String -> prefs.getString(key, default)

View file

@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
// todo (roughly in order)
// make all prefs actually work
// preferences
// advanced (not much)
// 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)
@ -23,12 +22,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
// more similar dialog style args (for all dialogs, or for none)
// 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?
// yes/no/default can now be confirmDialog
// 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
// calling KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) while keyboard is showing shows just full screen background
// but reload while keyboard is showing would be great (isn't it at least semi-done when changing one-handed mode?)
// use better / more structured and clear names and arrangement of files
// the prefDef and AllPrefs, also be clear about pref <-> key <-> prefKey (all used, probably should be latter)
// there is a lot more ambiguous naming...
@ -64,6 +63,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
// color settings (should at least change how colors are stored, and have a color search/filter)
// allow users to add custom themes instead of only having a single one (maybe also switchable in colors settings)
// one single place for default values (to be used in composables and settings)
// does it make sense to put this into PrefDef?
// make auto_correct_threshold a float directly with the list pref (needs pref upgrade)
// using context.prefs() outside settings
// merge PREF_TOOLBAR_CUSTOM_KEY_CODES and PREF_TOOLBAR_CUSTOM_LONGPRESS_CODES into one pref (don't forget settings upgrade)

View file

@ -4,18 +4,34 @@ import android.content.Context
import android.media.AudioManager
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.latin.AudioAndHapticFeedbackManager
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT
import helium314.keyboard.latin.utils.POPUP_KEYS_ORDER_DEFAULT
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getEnabledSubtypes
import helium314.keyboard.latin.utils.locale
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.AllPrefs
import helium314.keyboard.settings.ListPreference
import helium314.keyboard.settings.PrefDef
import helium314.keyboard.settings.PreferenceCategory
import helium314.keyboard.settings.ReorderSwitchPreference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SettingsActivity2
import helium314.keyboard.settings.SliderPreference
import helium314.keyboard.settings.SwitchPreference
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.keyboardNeedsReload
@Composable
fun PreferencesScreen(
@ -25,13 +41,100 @@ fun PreferencesScreen(
onClickBack = onClickBack,
title = stringResource(R.string.settings_screen_preferences),
) {
SettingsActivity2.allPrefs.map[Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME]!!.Preference()
val prefs = LocalContext.current.prefs()
val b = (LocalContext.current.getActivity() as? SettingsActivity2)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
PreferenceCategory(stringResource(R.string.settings_category_input)) {
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_HINTS]!!.Preference()
if (prefs.getBoolean(Settings.PREF_SHOW_HINTS, true))
SettingsActivity2.allPrefs.map[Settings.PREF_POPUP_KEYS_LABELS_ORDER]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_POPUP_KEYS_ORDER]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_POPUP_HINTS]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_POPUP_ON]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_VIBRATE_ON]!!.Preference()
if (prefs.getBoolean(Settings.PREF_VIBRATE_ON, true))
SettingsActivity2.allPrefs.map[Settings.PREF_VIBRATION_DURATION_SETTINGS]!!.Preference()
if (prefs.getBoolean(Settings.PREF_VIBRATE_ON, true))
SettingsActivity2.allPrefs.map[Settings.PREF_VIBRATE_IN_DND_MODE]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SOUND_ON]!!.Preference()
if (prefs.getBoolean(Settings.PREF_SOUND_ON, true))
SettingsActivity2.allPrefs.map[Settings.PREF_KEYPRESS_SOUND_VOLUME]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME]!!.Preference()
}
PreferenceCategory(stringResource(R.string.settings_category_additional_keys)) {
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_NUMBER_ROW]!!.Preference()
if (getEnabledSubtypes(prefs, true).any { it.locale().language in localesWithLocalizedNumberRow })
SettingsActivity2.allPrefs.map[Settings.PREF_LOCALIZED_NUMBER_ROW]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_LANGUAGE_SWITCH_KEY]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_SHOW_EMOJI_KEY]!!.Preference()
SettingsActivity2.allPrefs.map[Settings.PREF_REMOVE_REDUNDANT_POPUPS]!!.Preference()
}
PreferenceCategory(stringResource(R.string.settings_category_clipboard_history)) {
SettingsActivity2.allPrefs.map[Settings.PREF_ENABLE_CLIPBOARD_HISTORY]!!.Preference()
if (prefs.getBoolean(Settings.PREF_ENABLE_CLIPBOARD_HISTORY, true))
SettingsActivity2.allPrefs.map[Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME]!!.Preference()
}
}
}
fun createPreferencesPrefs(context: Context) = listOf(
PrefDef(context, Settings.PREF_SHOW_HINTS, R.string.show_hints, R.string.show_hints_summary) {
SwitchPreference(it, true)
},
PrefDef(context, Settings.PREF_POPUP_KEYS_LABELS_ORDER, R.string.hint_source) {
ReorderSwitchPreference(it, POPUP_KEYS_LABEL_DEFAULT)
},
PrefDef(context, Settings.PREF_POPUP_KEYS_ORDER, R.string.popup_order) {
ReorderSwitchPreference(it, POPUP_KEYS_ORDER_DEFAULT)
},
PrefDef(context, Settings.PREF_SHOW_POPUP_HINTS, R.string.show_popup_hints, R.string.show_popup_hints_summary) {
SwitchPreference(it, false) { keyboardNeedsReload = true }
},
PrefDef(context, Settings.PREF_POPUP_ON, R.string.popup_on_keypress) {
val dm = LocalContext.current.resources.displayMetrics
val px600 = with(LocalDensity.current) { 600.dp.toPx() }
SwitchPreference(it, dm.widthPixels >= px600 || dm.heightPixels >= px600)
},
PrefDef(context, Settings.PREF_VIBRATE_ON, R.string.vibrate_on_keypress) {
SwitchPreference(it, false)
},
PrefDef(context, Settings.PREF_VIBRATE_IN_DND_MODE, R.string.vibrate_in_dnd_mode) {
SwitchPreference(it, false)
},
PrefDef(context, Settings.PREF_SOUND_ON, R.string.sound_on_keypress) {
SwitchPreference(it, false)
},
PrefDef(context, Settings.PREF_ENABLE_CLIPBOARD_HISTORY, R.string.enable_clipboard_history, R.string.enable_clipboard_history_summary) {
SwitchPreference(it, true)
},
PrefDef(context, Settings.PREF_SHOW_NUMBER_ROW, R.string.number_row, R.string.number_row_summary) {
SwitchPreference(it, false) { keyboardNeedsReload = true }
},
PrefDef(context, Settings.PREF_LOCALIZED_NUMBER_ROW, R.string.localized_number_row, R.string.localized_number_row_summary) {
SwitchPreference(it, true) { KeyboardLayoutSet.onSystemLocaleChanged() }
},
PrefDef(context, Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, R.string.show_language_switch_key) {
SwitchPreference(it, false) { keyboardNeedsReload = true }
},
PrefDef(context, Settings.PREF_LANGUAGE_SWITCH_KEY, R.string.language_switch_key_behavior) {
ListPreference(
it,
listOf(
"internal" to stringResource(R.string.switch_language),
"input_method" to stringResource(R.string.language_switch_key_switch_input_method),
"both" to stringResource(R.string.language_switch_key_switch_both)
),
"internal"
) { keyboardNeedsReload = true }
},
PrefDef(context, Settings.PREF_SHOW_EMOJI_KEY, R.string.show_emoji_key) {
SwitchPreference(it, false)
},
PrefDef(context, Settings.PREF_REMOVE_REDUNDANT_POPUPS, R.string.remove_redundant_popups, R.string.remove_redundant_popups_summary) {
SwitchPreference(it, false) { keyboardNeedsReload = true }
},
PrefDef(context, Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, R.string.clipboard_history_retention_time) { def ->
SliderPreference(
name = def.title,
@ -73,6 +176,9 @@ fun createPreferencesPrefs(context: Context) = listOf(
},
)
// todo: not good to have it hardcoded, but reading a bunch of files may be noticeably slow
private val localesWithLocalizedNumberRow = listOf("ar", "bn", "fa", "gu", "hi", "kn", "mr", "ne", "ur")
@Preview
@Composable
private fun Preview() {

View file

@ -37,6 +37,7 @@ import helium314.keyboard.settings.AllPrefs
import helium314.keyboard.settings.NonSettingsPrefs
import helium314.keyboard.settings.PrefDef
import helium314.keyboard.settings.Preference
import helium314.keyboard.settings.ReorderSwitchPreference
import helium314.keyboard.settings.SearchPrefScreen
import helium314.keyboard.settings.SettingsActivity2
import helium314.keyboard.settings.SwitchPreference
@ -66,46 +67,13 @@ fun ToolbarScreen(
fun createToolbarPrefs(context: Context) = listOf(
PrefDef(context, Settings.PREF_TOOLBAR_KEYS, R.string.toolbar_keys) { def ->
var showDialog by remember { mutableStateOf(false) }
Preference(
name = def.title,
onClick = { showDialog = true },
)
if (showDialog) {
ToolbarKeyReorderDialog(
def.key,
defaultToolbarPref,
def.title,
) { showDialog = false }
}
ReorderSwitchPreference(def, defaultToolbarPref)
},
PrefDef(context, Settings.PREF_PINNED_TOOLBAR_KEYS, R.string.pinned_toolbar_keys) { def ->
var showDialog by remember { mutableStateOf(false) }
Preference(
name = def.title,
onClick = { showDialog = true },
)
if (showDialog) {
ToolbarKeyReorderDialog(
def.key,
defaultPinnedToolbarPref,
def.title,
) { showDialog = false }
}
ReorderSwitchPreference(def, defaultPinnedToolbarPref)
},
PrefDef(context, Settings.PREF_CLIPBOARD_TOOLBAR_KEYS, R.string.clipboard_toolbar_keys) { def ->
var showDialog by remember { mutableStateOf(false) }
Preference(
name = def.title,
onClick = { showDialog = true },
)
if (showDialog) {
ToolbarKeyReorderDialog(
def.key,
defaultClipboardToolbarPref,
def.title,
) { showDialog = false }
}
ReorderSwitchPreference(def, defaultClipboardToolbarPref)
},
PrefDef(context, NonSettingsPrefs.CUSTOM_KEY_CODES, R.string.customize_toolbar_key_codes) { def ->
var showDialog by remember { mutableStateOf(false) }
@ -145,48 +113,6 @@ fun createToolbarPrefs(context: Context) = listOf(
}
)
@Composable
fun ToolbarKeyReorderDialog(
prefKey: String,
default: String,
title: String,
onDismiss: () -> Unit
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
val items = prefs.getString(prefKey, default)!!.split(";").mapTo(ArrayList()) {
val both = it.split(",")
KeyAndState(both.first(), both.last().toBoolean())
}
ReorderDialog(
onConfirmed = { reorderedItems ->
val value = reorderedItems.joinToString(";") { it.name + "," + it.state }
prefs.edit().putString(prefKey, value).apply()
keyboardNeedsReload = true
},
onDismissRequest = onDismiss,
onNeutral = { prefs.edit().remove(prefKey).apply() },
neutralButtonText = if (prefs.contains(prefKey)) stringResource(R.string.button_default) else null,
items = items,
title = { Text(title) },
displayItem = { item ->
var checked by remember { mutableStateOf(item.state) }
Row(verticalAlignment = Alignment.CenterVertically) {
KeyboardIconsSet.instance.GetIcon(item.name)
val text = item.name.lowercase().getStringResourceOrName("", ctx)
Text(text, Modifier.weight(1f))
Switch(
checked = checked,
onCheckedChange = { item.state = it; checked = it }
)
}
},
getKey = { it.name }
)
}
private class KeyAndState(var name: String, var state: Boolean)
@Preview
@Composable
private fun Preview() {