diff --git a/app/src/main/java/helium314/keyboard/settings/Preference.kt b/app/src/main/java/helium314/keyboard/settings/Preference.kt index 7d4b692c..11783b26 100644 --- a/app/src/main/java/helium314/keyboard/settings/Preference.kt +++ b/app/src/main/java/helium314/keyboard/settings/Preference.kt @@ -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 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 getPrefOfType(prefs: SharedPreferences, key: String, default: T): T = when (default) { is String -> prefs.getString(key, default) diff --git a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt index 831ed0c2..b1c0978f 100644 --- a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt +++ b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt @@ -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) diff --git a/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt index 555e48f7..92dbf002 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt @@ -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() - SettingsActivity2.allPrefs.map[Settings.PREF_VIBRATION_DURATION_SETTINGS]!!.Preference() - SettingsActivity2.allPrefs.map[Settings.PREF_KEYPRESS_SOUND_VOLUME]!!.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() { diff --git a/app/src/main/java/helium314/keyboard/settings/screens/ToolbarScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/ToolbarScreen.kt index 617d0e50..221df271 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/ToolbarScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/ToolbarScreen.kt @@ -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() {