dialogs don't just disappear after rotating device

This commit is contained in:
Helium314 2025-02-08 19:51:42 +01:00
parent ebc0947af7
commit f5c3fca8c6
18 changed files with 70 additions and 43 deletions

View file

@ -34,6 +34,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
@ -83,12 +84,9 @@ fun <T: Any> SearchScreen(
itemContent: @Composable (T) -> Unit,
content: @Composable (ColumnScope.() -> Unit)? = null,
) {
var searchText by remember { mutableStateOf(TextFieldValue()) } // must be outside the column to work without messing up cursor position
var searchText by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
Column(Modifier.fillMaxSize()) {
// rememberSaveable would be better, but does not work with TextFieldValue
// if we just store the string, the cursor is messed up
// hmm... no, sth else is messing up that thing, and I just didn't notice
var showSearch by remember { mutableStateOf(false) }
var showSearch by rememberSaveable { mutableStateOf(false) }
fun setShowSearch(value: Boolean) {
showSearch = value

View file

@ -14,8 +14,6 @@ import helium314.keyboard.latin.utils.prefs
import kotlinx.coroutines.flow.MutableStateFlow
// todo (roughly in order)
// try implementation("com.github.skydoves:colorpicker-compose:1.1.2")
// dialogs should be rememberSaveable to survive display orientation change and stuff?
// check dark and light theme (don't have dynamic)
// any way to get rid of the "old" background on starting settings? probably comes from app theme, can we avoid it?
// try making old fragment back stuff work better, and try the different themes (with and without top bar, it should only appear for old fragments)

View file

@ -11,6 +11,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Icon
@ -19,9 +20,11 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
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.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -64,8 +67,8 @@ fun CustomizeIconsDialog(
else item
}
}
var showIconDialog: Pair<String, String>? by remember { mutableStateOf(null) }
var showDeletePrefConfirmDialog by remember { mutableStateOf(false) }
var showIconDialog: Pair<String, String>? by rememberSaveable { mutableStateOf(null) }
var showDeletePrefConfirmDialog by rememberSaveable { mutableStateOf(false) }
val prefs = ctx.prefs()
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
@ -97,7 +100,13 @@ fun CustomizeIconsDialog(
iconsSet.addAll(iconsForName)
KeyboardIconsSet.getAllIcons(ctx).forEach { iconsSet.addAll(it.value) }
val icons = iconsSet.toList()
var selectedIcon by remember { mutableStateOf(KeyboardIconsSet.instance.iconIds[iconName]) }
var selectedIcon by rememberSaveable { mutableStateOf(KeyboardIconsSet.instance.iconIds[iconName]) }
val gridState = rememberLazyGridState()
LaunchedEffect(selectedIcon) {
val index = icons.indexOf(selectedIcon)
if (index != -1) gridState.scrollToItem(index, -state.layoutInfo.viewportSize.height / 3)
}
ThreeButtonAlertDialog(
onDismissRequest = { showIconDialog = null },
onConfirmed = {
@ -123,7 +132,8 @@ fun CustomizeIconsDialog(
title = { Text(showIconDialog!!.second) },
text = {
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 64.dp)
columns = GridCells.Adaptive(minSize = 64.dp),
state = gridState
) {
items(icons, key = { it }) { resId ->
val drawable = ContextCompat.getDrawable(ctx, resId)?.mutate() ?: return@items

View file

@ -9,6 +9,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@ -36,7 +37,7 @@ fun LayoutEditDialog(
val file = getCustomLayoutFile(layoutName, ctx)
val scope = rememberCoroutineScope()
var job: Job? = null
var showDeleteConfirmation by remember { mutableStateOf(false) }
var showDeleteConfirmation by rememberSaveable { mutableStateOf(false) }
TextInputDialog(
onDismissRequest = onDismissRequest,
onConfirmed = {

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
@ -40,12 +41,19 @@ fun TextInputDialog(
checkTextValid: (text: String) -> Boolean = { it.isNotBlank() }
) {
val focusRequester = remember { FocusRequester() }
var value by remember {
mutableStateOf(TextFieldValue(initialText, selection = TextRange(if (singleLine) initialText.length else 0)))
// crappy workaround because otherwise we get a disappearing dialog and a crash
// but doesn't work perfectly, dialog doesn't nicely show up again...
// todo: understand why it works in ExpandableSearchField, but not here
var done by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(initialText) {
if (done) return@LaunchedEffect
focusRequester.requestFocus()
done = true
}
LaunchedEffect(initialText) { focusRequester.requestFocus() }
var value by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(initialText, selection = TextRange(if (singleLine) initialText.length else 0)))
}
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,

View file

@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -47,8 +48,8 @@ fun ToolbarKeysCustomizer(
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
var showKeyCustomizer: ToolbarKey? by remember { mutableStateOf(null) }
var showDeletePrefConfirmDialog by remember { mutableStateOf(false) }
var showKeyCustomizer: ToolbarKey? by rememberSaveable { mutableStateOf(null) }
var showDeletePrefConfirmDialog by rememberSaveable { mutableStateOf(false) }
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
cancelButtonText = stringResource(R.string.dialog_close),
@ -100,8 +101,8 @@ private fun ToolbarKeyCustomizer(
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
var code by remember { mutableStateOf(TextFieldValue(getCodeForToolbarKey(key).toString())) }
var longPressCode by remember { mutableStateOf(TextFieldValue(getCodeForToolbarKeyLongClick(key).toString())) }
var code by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(getCodeForToolbarKey(key).toString())) }
var longPressCode by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(getCodeForToolbarKeyLongClick(key).toString())) }
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
onConfirmed = {

View file

@ -14,6 +14,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -33,10 +34,10 @@ import kotlinx.coroutines.launch
@Composable
fun BackgroundImagePref(setting: Setting, isLandscape: Boolean) {
var showDayNightDialog by remember { mutableStateOf(false) }
var showSelectionDialog by remember { mutableStateOf(false) }
var showErrorDialog by remember { mutableStateOf(false) }
var isNight by remember { mutableStateOf(false) }
var showDayNightDialog by rememberSaveable { mutableStateOf(false) }
var showSelectionDialog by rememberSaveable { mutableStateOf(false) }
var showErrorDialog by rememberSaveable { mutableStateOf(false) }
var isNight by rememberSaveable { mutableStateOf(false) }
val ctx = LocalContext.current
fun getFile() = Settings.getCustomBackgroundFile(ctx, isNight, isLandscape)
val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -55,10 +56,10 @@ import java.util.zip.ZipOutputStream
@Composable
fun BackupRestorePreference(setting: Setting) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
val ctx = LocalContext.current
val prefs = ctx.prefs()
var error: String? by remember { mutableStateOf(null) }
var error: String? by rememberSaveable { mutableStateOf(null) }
val backupFilePatterns by lazy { listOf(
"blacklists/.*\\.txt".toRegex(),
"layouts/$CUSTOM_LAYOUT_PREFIX+\\..{0,4}".toRegex(), // can't expect a period at the end, as this would break restoring older backups

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -26,8 +27,8 @@ import java.io.File
@Composable
fun CustomFontPreference(setting: Setting) {
val ctx = LocalContext.current
var showDialog by remember { mutableStateOf(false) }
var showErrorDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
var showErrorDialog by rememberSaveable { mutableStateOf(false) }
val fontFile = Settings.getCustomFontFile(ctx)
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult

View file

@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
@ -21,9 +22,9 @@ fun LayoutEditPreference(
getItemName: @Composable (String) -> String,
getDefaultLayout: @Composable (String?) -> String?,
) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
val ctx = LocalContext.current
var layout: String? by remember { mutableStateOf(null) }
var layout: String? by rememberSaveable { mutableStateOf(null) }
Preference(
name = setting.title,
onClick = { showDialog = true }

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -29,7 +30,7 @@ import java.io.IOException
@Composable
fun LoadGestureLibPreference(setting: Setting) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
val ctx = LocalContext.current
val prefs = ctx.prefs()
val abi = Build.SUPPORTED_ABIS[0]
@ -41,7 +42,7 @@ fun LoadGestureLibPreference(setting: Setting) {
file.renameTo(libFile)
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
}
var tempFilePath: String? by remember { mutableStateOf(null) }
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
val uri = result.data?.data ?: return@rememberLauncherForActivityResult

View file

@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -23,7 +24,7 @@ import helium314.keyboard.settings.screens.GetIcon
@Composable
fun ReorderSwitchPreference(setting: Setting, default: String) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
Preference(
name = setting.title,
description = setting.description,
@ -48,7 +49,7 @@ fun ReorderSwitchPreference(setting: Setting, default: String) {
items = items,
title = { Text(setting.title) },
displayItem = { item ->
var checked by remember { mutableStateOf(item.state) }
var checked by rememberSaveable { mutableStateOf(item.state) }
Row(verticalAlignment = Alignment.CenterVertically) {
KeyboardIconsSet.instance.GetIcon(item.name)
val text = item.name.lowercase().getStringResourceOrName("", ctx)

View file

@ -7,6 +7,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@ -41,7 +42,7 @@ fun <T: Number> SliderPreference(
getPrefOfType(prefs, key, default)
else throw IllegalArgumentException("only float and int are supported")
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
Preference(
name = name,
onClick = { showDialog = true },
@ -79,7 +80,7 @@ fun <T: Any> ListPreference(
default: T,
onChanged: (T) -> Unit = { }
) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
val prefs = LocalContext.current.prefs()
val selected = items.firstOrNull { it.second == getPrefOfType(prefs, setting.key, default) }
Preference(

View file

@ -165,7 +165,7 @@ fun createAdvancedSettings(context: Context) = listOf(
SwitchPreference(it, false)
},
Setting(context, Settings.PREF_CUSTOM_CURRENCY_KEY, R.string.customize_currencies) { setting ->
var showDialog by remember { mutableStateOf(false) }
var showDialog by remember { mutableStateOf(false) } // todo: textInputDialog...
Preference(
name = setting.title,
onClick = { showDialog = true }

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -122,7 +123,7 @@ fun createAppearanceSettings(context: Context) = listOf(
) { keyboardNeedsReload = true }
},
Setting(context, Settings.PREF_CUSTOM_ICON_NAMES, R.string.customize_icons) { setting ->
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
Preference(
name = setting.title,
onClick = { showDialog = true }
@ -269,7 +270,7 @@ fun createAppearanceSettings(context: Context) = listOf(
) { keyboardNeedsReload = true }
},
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) { setting ->
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) } // todo: textInputDialog...
val prefs = LocalContext.current.prefs()
Preference(
name = setting.title,

View file

@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -57,7 +58,7 @@ fun createDebugSettings(context: Context) = listOf(
},
Setting(context, DebugSettings.PREF_DEBUG_MODE, R.string.prefs_debug_mode) { setting ->
val prefs = LocalContext.current.prefs()
var showConfirmDialog by remember { mutableStateOf(false) }
var showConfirmDialog by rememberSaveable { mutableStateOf(false) }
SwitchPreference(
name = setting.title,
key = setting.key,
@ -79,7 +80,7 @@ fun createDebugSettings(context: Context) = listOf(
SwitchPreference(it, false) { keyboardNeedsReload = true }
},
Setting(context, DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, R.string.prefs_force_non_distinct_multitouch) {
var showConfirmDialog by remember { mutableStateOf(false) }
var showConfirmDialog by rememberSaveable { mutableStateOf(false) }
SwitchPreference(it, false) { showConfirmDialog = true }
if (showConfirmDialog) {
ConfirmationDialog(

View file

@ -13,6 +13,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
@ -149,7 +150,7 @@ fun createCorrectionSettings(context: Context) = listOf(
Setting(context, Settings.PREF_KEY_USE_PERSONALIZED_DICTS,
R.string.use_personalized_dicts, R.string.use_personalized_dicts_summary
) { setting ->
var showConfirmDialog by remember { mutableStateOf(false) }
var showConfirmDialog by rememberSaveable { mutableStateOf(false) }
SwitchPreference(setting, true,
allowCheckedChange = {
showConfirmDialog = !it

View file

@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -73,7 +74,7 @@ fun createToolbarSettingss(context: Context) = listOf(
ReorderSwitchPreference(it, defaultClipboardToolbarPref)
},
Setting(context, SettingsWithoutKey.CUSTOM_KEY_CODES, R.string.customize_toolbar_key_codes) {
var showDialog by remember { mutableStateOf(false) }
var showDialog by rememberSaveable { mutableStateOf(false) }
Preference(
name = it.title,
onClick = { showDialog = true },