add dialog with default button

This commit is contained in:
Helium314 2025-02-02 15:04:40 +01:00
parent e2ebd32f25
commit 31b2a36bcc
10 changed files with 183 additions and 82 deletions

View file

@ -14,9 +14,6 @@ import helium314.keyboard.latin.utils.prefs
import kotlinx.coroutines.flow.MutableStateFlow
// todo (roughly in order)
// default buttons for toolbar key(s) customizer, icon customizer, and toolbar reorder dialog
// make a dialog wrapper that has a default button?
// yes, definitely need a 3 button dialog...
// make all prefs actually work
// 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)

View file

@ -56,11 +56,16 @@ fun CustomizeIconsDialog(
else iconName to name
}.sortedBy { it.second }
var showIconDialog: Pair<String, String>? by remember { mutableStateOf(null) }
var showDeletePrefConfirmDialog by remember { mutableStateOf(false) }
val prefs = ctx.prefs()
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = { }, // no confirm button
dismissButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(R.string.dialog_close)) } },
confirmButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(R.string.dialog_close)) } },
dismissButton = {
if (prefs.contains(prefKey))
TextButton(onClick = { showDeletePrefConfirmDialog = true })
{ Text(stringResource(R.string.button_default)) }
},
title = { Text(stringResource(R.string.customize_icons)) },
text = {
LazyColumn(state = state) {
@ -82,24 +87,31 @@ fun CustomizeIconsDialog(
val iconsForName = allIcons[iconName].orEmpty()
val iconsSet = mutableSetOf<Int>()
iconsSet.addAll(iconsForName)
KeyboardIconsSet.getAllIcons(ctx).forEach { iconsSet.addAll(it.value) } // is this called again on UI interaction?
KeyboardIconsSet.getAllIcons(ctx).forEach { iconsSet.addAll(it.value) } // todo: is this called again on UI interaction?
val icons = iconsSet.toList()
var selectedIcon by remember { mutableStateOf(KeyboardIconsSet.instance.iconIds[iconName]) }
AlertDialog(
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = { TextButton(
onClick = {
onDismissRequest()
runCatching {
val newIcons = customIconNames(prefs).toMutableMap()
newIcons[iconName] = selectedIcon?.let { ctx.resources.getResourceEntryName(it) } ?: return@runCatching
prefs.edit().putString(prefKey, Json.encodeToString(newIcons)).apply()
KeyboardIconsSet.instance.loadIcons(ctx)
}
// todo: show outer dialog again and reload icons?
onConfirmed = {
runCatching {
val newIcons = customIconNames(prefs).toMutableMap()
newIcons[iconName] = selectedIcon?.let { ctx.resources.getResourceEntryName(it) } ?: return@runCatching
prefs.edit().putString(prefKey, Json.encodeToString(newIcons)).apply()
KeyboardIconsSet.instance.loadIcons(ctx)
}
) { Text(stringResource(android.R.string.ok)) } },
dismissButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(android.R.string.cancel)) } },
// todo: show outer dialog again and reload icons?
},
neutralButtonText = if (customIconNames(prefs).contains(iconName)) stringResource(R.string.button_default) else null,
onNeutral = {
runCatching {
val icons2 = customIconNames(prefs).toMutableMap()
icons2.remove(iconName)
if (icons2.isEmpty()) prefs.edit().remove(prefKey).apply()
else prefs.edit().putString(prefKey, Json.encodeToString(icons2)).apply()
KeyboardIconsSet.instance.loadIcons(ctx)
}
// todo: show outer dialog again and reload icons?
},
title = { Text(showIconDialog!!.second) },
text = {
LazyVerticalGrid(
@ -129,6 +141,16 @@ fun CustomizeIconsDialog(
},
)
}
if (showDeletePrefConfirmDialog)
ConfirmationDialog(
onDismissRequest = { showDeletePrefConfirmDialog = false },
onConfirmed = {
showDeletePrefConfirmDialog = false
onDismissRequest()
prefs.edit().remove(prefKey).apply()
},
text = { Text(stringResource(R.string.customize_icons_reset_message)) }
)
}
@Preview

View file

@ -28,8 +28,6 @@ fun LayoutEditDialog(
val initialText = startContent ?: file.readText()
var showDeleteConfirmation by remember { mutableStateOf(false) }
// todo: try make it really full width, at least if we have a json file
// todo: ok button should be "save"
// todo: if displayName not null, there is an existing file
TextInputDialog(
onDismissRequest = onDismissRequest,
onConfirmed = {
@ -38,13 +36,20 @@ fun LayoutEditDialog(
onCustomLayoutFileListChanged()
keyboardNeedsReload = true
},
confirmButtonText = stringResource(R.string.save),
neutralButtonText = if (displayName != null && file.exists()) stringResource(R.string.delete) else null,
onNeutral = {
if (!file.exists()) return@TextInputDialog
file.delete()
onCustomLayoutFileListChanged()
keyboardNeedsReload = true
},
initialText = initialText,
singleLine = false,
title = { Text(displayName ?: getLayoutDisplayName(layoutName)) },
checkTextValid = {
checkLayout(it, ctx) // todo: toast with reason why it doesn't work -> should re-do getting the reason
},
// todo: delete button if displayName not null and file exists
)
if (showDeleteConfirmation)
ConfirmationDialog(

View file

@ -43,8 +43,8 @@ fun <T: Any> ReorderDialog(
displayItem: @Composable (T) -> Unit,
modifier: Modifier = Modifier,
title: @Composable (() -> Unit)? = null,
confirmButtonText: String = stringResource(android.R.string.ok),
cancelButtonText: String = stringResource(android.R.string.cancel),
onNeutral: () -> Unit = { },
neutralButtonText: String? = null,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = contentColorFor(backgroundColor),
@ -58,13 +58,12 @@ fun <T: Any> ReorderDialog(
add(to.index, removeAt(from.index))
}
}
AlertDialog(
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
TextButton(onClick = { onConfirmed(reorderableItems); onDismissRequest() }) { Text(confirmButtonText) }
},
onConfirmed = { onConfirmed(reorderableItems) },
onNeutral = onNeutral,
neutralButtonText = neutralButtonText,
modifier = modifier,
dismissButton = { TextButton(onClick = onDismissRequest) { Text(cancelButtonText) } },
title = title,
text = {
LazyColumn(
@ -93,8 +92,8 @@ fun <T: Any> ReorderDialog(
}
},
shape = shape,
containerColor = backgroundColor,
textContentColor = contentColor,
backgroundColor = backgroundColor,
contentColor = contentColor,
properties = properties,
)
}

View file

@ -32,7 +32,7 @@ fun SliderDialog(
range: ClosedFloatingPointRange<Float>,
modifier: Modifier = Modifier,
showDefault: Boolean = false,
onDefault: () -> Unit? = { },
onDefault: () -> Unit = { },
onValueChanged: (Float) -> Unit = { },
title: (@Composable () -> Unit)? = null,
intermediateSteps: Int? = null,
@ -44,21 +44,11 @@ fun SliderDialog(
) {
var sliderPosition by remember { mutableFloatStateOf(initialValue) }
AlertDialog(
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = { // mis-use the confirm button and put everything in there
Row {
if (showDefault)
TextButton(
onClick = { onDismissRequest(); onDefault() }
) { Text(stringResource(R.string.button_default)) }
Spacer(modifier.weight(1f))
TextButton(onClick = onDismissRequest) { Text(stringResource(android.R.string.cancel)) }
TextButton(
onClick = { onDismissRequest(); onDone(sliderPosition) },
) { Text(stringResource(android.R.string.ok)) }
}
},
neutralButtonText = if (showDefault) stringResource(R.string.button_default) else null,
onNeutral = onDefault,
onConfirmed = { onDone(sliderPosition) },
modifier = modifier,
title = title,
text = {
@ -86,8 +76,8 @@ fun SliderDialog(
}
},
shape = shape,
containerColor = backgroundColor,
textContentColor = contentColor,
backgroundColor = backgroundColor,
contentColor = contentColor,
properties = properties,
)
}

View file

@ -2,11 +2,9 @@ package helium314.keyboard.settings.dialogs
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -26,7 +24,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
// taken from StreetComplete / SCEE
// mostly taken from StreetComplete / SCEE
/** Dialog with which to input text. OK button is only clickable if [checkTextValid] returns true. */
@Composable
fun TextInputDialog(
@ -34,6 +32,9 @@ fun TextInputDialog(
onConfirmed: (text: String) -> Unit,
modifier: Modifier = Modifier,
title: @Composable (() -> Unit)? = null,
onNeutral: () -> Unit = { },
neutralButtonText: String? = null,
confirmButtonText: String = stringResource(android.R.string.ok),
initialText: String = "",
textInputLabel: @Composable (() -> Unit)? = null,
shape: Shape = MaterialTheme.shapes.medium,
@ -52,34 +53,30 @@ fun TextInputDialog(
LaunchedEffect(initialText) { focusRequester.requestFocus() }
AlertDialog(
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
TextButton(
enabled = value.text.isNotBlank() && checkTextValid(value.text),
onClick = { onDismissRequest(); onConfirmed(value.text) }
) {
Text(stringResource(android.R.string.ok))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) { Text(stringResource(android.R.string.cancel)) }
},
onConfirmed = { onConfirmed(value.text) },
confirmButtonText = confirmButtonText,
checkOk = { checkTextValid(value.text) },
neutralButtonText = neutralButtonText,
onNeutral = onNeutral,
modifier = modifier,
title = title,
text = {
OutlinedTextField(
value = value,
onValueChange = { value = it },
modifier = Modifier.fillMaxWidth().focusRequester(focusRequester),
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
label = textInputLabel,
keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
singleLine = singleLine
)
},
shape = shape,
containerColor = backgroundColor,
textContentColor = contentColor,
backgroundColor = backgroundColor,
contentColor = contentColor,
properties = properties,
)
}

View file

@ -0,0 +1,58 @@
package helium314.keyboard.settings.dialogs
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.AlertDialog
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.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.window.DialogProperties
@Composable
fun ThreeButtonAlertDialog(
onDismissRequest: () -> Unit,
onConfirmed: () -> Unit,
modifier: Modifier = Modifier,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
onNeutral: () -> Unit = { },
checkOk: () -> Boolean = { true },
confirmButtonText: String = stringResource(android.R.string.ok),
cancelButtonText: String = stringResource(android.R.string.cancel),
neutralButtonText: String? = null,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = contentColorFor(backgroundColor),
properties: DialogProperties = DialogProperties(),
) {
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = { // mis-use the confirm button and put everything in there
Row {
if (neutralButtonText != null)
TextButton(
onClick = { onDismissRequest(); onNeutral() }
) { Text(neutralButtonText) }
Spacer(modifier.weight(1f))
TextButton(onClick = onDismissRequest) { Text(cancelButtonText) }
TextButton(
enabled = checkOk(),
onClick = { onDismissRequest(); onConfirmed() },
) { Text(confirmButtonText) }
}
},
modifier = modifier,
title = title,
text = text,
shape = shape,
containerColor = backgroundColor,
textContentColor = contentColor,
properties = properties,
)
}

View file

@ -25,6 +25,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
import androidx.core.content.edit
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode.checkAndConvertCode
import helium314.keyboard.latin.R
@ -39,21 +40,28 @@ import helium314.keyboard.latin.utils.readCustomLongpressCodes
import helium314.keyboard.latin.utils.writeCustomKeyCodes
import helium314.keyboard.latin.utils.writeCustomLongpressCodes
import helium314.keyboard.settings.screens.GetIcon
import kotlinx.serialization.json.Json
// todo:
// reading and writing prefs should be done in the preference, or at least with the provided (single!) key
// todo (later): reading and writing prefs should be done in the preference, or at least with the provided (single!) pref key
@Composable
fun ToolbarKeysCustomizer(
onDismissRequest: () -> Unit
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
var showKeyCustomizer: ToolbarKey? by remember { mutableStateOf(null) }
var showDeletePrefConfirmDialog by remember { mutableStateOf(false) }
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
TextButton(onClick = onDismissRequest) { Text(stringResource(R.string.dialog_close)) }
},
dismissButton = { },
dismissButton = {
if (readCustomKeyCodes(prefs).isNotEmpty() || readCustomLongpressCodes(prefs).isNotEmpty())
TextButton(
onClick = { showDeletePrefConfirmDialog = true }
) { Text(stringResource(R.string.button_default)) }
},
title = { Text(stringResource(R.string.customize_toolbar_key_codes)) },
text = {
LazyColumn {
@ -78,8 +86,22 @@ fun ToolbarKeysCustomizer(
if (shownKey != null)
ToolbarKeyCustomizer(shownKey) { showKeyCustomizer = null }
}
if (showDeletePrefConfirmDialog)
ConfirmationDialog(
onDismissRequest = { showDeletePrefConfirmDialog = false },
onConfirmed = {
showDeletePrefConfirmDialog = false
onDismissRequest()
prefs.edit {
remove(Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES)
remove(Settings.PREF_TOOLBAR_CUSTOM_LONGPRESS_CODES)
}
},
text = { Text(stringResource(R.string.customize_toolbar_key_code_reset_message)) }
)
}
// todo: show updated ToolbarKeysCustomizer after ok / default? because default button
@Composable
private fun ToolbarKeyCustomizer(
key: ToolbarKey,
@ -89,19 +111,24 @@ private fun ToolbarKeyCustomizer(
val prefs = ctx.prefs()
var code by remember { mutableStateOf(TextFieldValue(getCodeForToolbarKey(key).toString())) }
var longPressCode by remember { mutableStateOf(TextFieldValue(getCodeForToolbarKeyLongClick(key).toString())) }
AlertDialog(
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
TextButton(
onClick = {
writeCustomKeyCodes(prefs, readCustomKeyCodes(prefs) + (key.name to checkCode(code)))
writeCustomLongpressCodes(prefs, readCustomLongpressCodes(prefs) + (key.name to checkCode(longPressCode)))
onDismissRequest()
},
enabled = checkCode(code) != null && checkCode(longPressCode) != null
) { Text(stringResource(android.R.string.ok)) }
onConfirmed = {
writeCustomKeyCodes(prefs, readCustomKeyCodes(prefs) + (key.name to checkCode(code)))
writeCustomLongpressCodes(prefs, readCustomLongpressCodes(prefs) + (key.name to checkCode(longPressCode)))
},
checkOk = { checkCode(code) != null && checkCode(longPressCode) != null },
neutralButtonText = if (readCustomKeyCodes(prefs).containsKey(key.name) || readCustomLongpressCodes(prefs).containsKey(key.name))
stringResource(R.string.button_default)
else null,
onNeutral = {
val keys = readCustomKeyCodes(prefs).toMutableMap()
keys.remove(key.name)
prefs.edit().putString(Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES, Json.encodeToString(keys)).apply()
val longpressKeys = readCustomLongpressCodes(prefs).toMutableMap()
longpressKeys.remove(key.name)
prefs.edit().putString(Settings.PREF_TOOLBAR_CUSTOM_LONGPRESS_CODES, Json.encodeToString(longpressKeys)).apply()
},
dismissButton = { TextButton(onClick = onDismissRequest) { Text(stringResource(android.R.string.cancel)) } },
title = { Text(key.name.lowercase().getStringResourceOrName("", ctx)) },
text = {
Column {
@ -126,8 +153,8 @@ private fun ToolbarKeyCustomizer(
}
},
shape = MaterialTheme.shapes.medium,
containerColor = MaterialTheme.colorScheme.surface,
textContentColor = contentColorFor(MaterialTheme.colorScheme.surface),
backgroundColor = MaterialTheme.colorScheme.surface,
contentColor = contentColorFor(MaterialTheme.colorScheme.surface),
properties = DialogProperties(),
)
}

View file

@ -131,6 +131,10 @@ fun createAppearancePrefs(context: Context) = listOf(
onClick = { showDialog = true }
)
if (showDialog) {
if (keyboardNeedsReload) {
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(LocalContext.current)
keyboardNeedsReload = false
}
CustomizeIconsDialog(def.key) { showDialog = false }
}
},

View file

@ -165,6 +165,8 @@ fun ToolbarKeyReorderDialog(
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 ->