mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-25 17:16:43 +00:00
some todos in SubtypeDialog
This commit is contained in:
parent
e3fa210031
commit
4edaa485b6
2 changed files with 114 additions and 96 deletions
|
@ -21,6 +21,7 @@ import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
@ -51,6 +52,7 @@ import helium314.keyboard.latin.utils.LayoutType
|
||||||
import helium314.keyboard.latin.utils.LayoutType.Companion.displayNameId
|
import helium314.keyboard.latin.utils.LayoutType.Companion.displayNameId
|
||||||
import helium314.keyboard.latin.utils.LayoutUtils
|
import helium314.keyboard.latin.utils.LayoutUtils
|
||||||
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
||||||
|
import helium314.keyboard.latin.utils.Log
|
||||||
import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_LATIN
|
import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_LATIN
|
||||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||||
import helium314.keyboard.latin.utils.SettingsSubtype
|
import helium314.keyboard.latin.utils.SettingsSubtype
|
||||||
|
@ -58,22 +60,21 @@ import helium314.keyboard.latin.utils.SettingsSubtype.Companion.toSettingsSubtyp
|
||||||
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
|
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
|
||||||
import helium314.keyboard.latin.utils.SubtypeSettings
|
import helium314.keyboard.latin.utils.SubtypeSettings
|
||||||
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
||||||
|
import helium314.keyboard.latin.utils.getActivity
|
||||||
import helium314.keyboard.latin.utils.getDictionaryLocales
|
import helium314.keyboard.latin.utils.getDictionaryLocales
|
||||||
import helium314.keyboard.latin.utils.getSecondaryLocales
|
import helium314.keyboard.latin.utils.getSecondaryLocales
|
||||||
import helium314.keyboard.latin.utils.getStringResourceOrName
|
import helium314.keyboard.latin.utils.getStringResourceOrName
|
||||||
import helium314.keyboard.latin.utils.mainLayoutName
|
import helium314.keyboard.latin.utils.mainLayoutName
|
||||||
import helium314.keyboard.latin.utils.prefs
|
import helium314.keyboard.latin.utils.prefs
|
||||||
|
import helium314.keyboard.settings.SettingsActivity
|
||||||
import helium314.keyboard.settings.layoutFilePicker
|
import helium314.keyboard.settings.layoutFilePicker
|
||||||
import helium314.keyboard.settings.layoutIntent
|
import helium314.keyboard.settings.layoutIntent
|
||||||
import helium314.keyboard.settings.screens.GetIcon
|
import helium314.keyboard.settings.screens.GetIcon
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
// todo:
|
// todo:
|
||||||
// fix the display name (why is the layout always added now e.g. after adding a secondary locale, when it's not there initially?)
|
// layout edit dialog does not care about ime padding when called from here, why?
|
||||||
// dropdown content is not refreshed on deleting a layout, maybe need to do the pref listener trick
|
|
||||||
// layout edit dialog does not care about ime padding when called from here
|
|
||||||
// rotating closes the dialog
|
// rotating closes the dialog
|
||||||
// split this up a little, it's too long... and maybe we could re-use parts other dialogs?
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SubtypeDialog(
|
fun SubtypeDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
|
@ -83,6 +84,9 @@ fun SubtypeDialog(
|
||||||
// todo: make sure the values are always correct (e.g. if using rememberSaveable and rotating)
|
// todo: make sure the values are always correct (e.g. if using rememberSaveable and rotating)
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
val prefs = ctx.prefs()
|
val prefs = ctx.prefs()
|
||||||
|
val b = (LocalContext.current.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
|
||||||
|
if ((b?.value ?: 0) < 0)
|
||||||
|
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
|
||||||
var currentSubtype by remember { mutableStateOf(subtype.toSettingsSubtype()) }
|
var currentSubtype by remember { mutableStateOf(subtype.toSettingsSubtype()) }
|
||||||
val availableLocalesForScript = getAvailableSecondaryLocales(ctx, currentSubtype.locale).sortedBy { it.toLanguageTag() }
|
val availableLocalesForScript = getAvailableSecondaryLocales(ctx, currentSubtype.locale).sortedBy { it.toLanguageTag() }
|
||||||
var showSecondaryLocaleDialog by remember { mutableStateOf(false) }
|
var showSecondaryLocaleDialog by remember { mutableStateOf(false) }
|
||||||
|
@ -90,6 +94,7 @@ fun SubtypeDialog(
|
||||||
var showHintOrderDialog by remember { mutableStateOf(false) }
|
var showHintOrderDialog by remember { mutableStateOf(false) }
|
||||||
var showMorePopupsDialog by remember { mutableStateOf(false) }
|
var showMorePopupsDialog by remember { mutableStateOf(false) }
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
val customMainLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name }
|
||||||
ThreeButtonAlertDialog(
|
ThreeButtonAlertDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
onConfirmed = { onConfirmed(currentSubtype) },
|
onConfirmed = { onConfirmed(currentSubtype) },
|
||||||
|
@ -105,91 +110,7 @@ fun SubtypeDialog(
|
||||||
modifier = Modifier.verticalScroll(scrollState),
|
modifier = Modifier.verticalScroll(scrollState),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
WithSmallTitle(stringResource(R.string.keyboard_layout_set)) {
|
MainLayoutRow(subtype, currentSubtype, customMainLayouts) { currentSubtype = it }
|
||||||
val appLayouts = LayoutUtils.getAvailableLayouts(LayoutType.MAIN, ctx, currentSubtype.locale)
|
|
||||||
val customLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name }
|
|
||||||
var showAddLayoutDialog by remember { mutableStateOf(false) }
|
|
||||||
var showLayoutEditDialog: Pair<String, String?>? by remember { mutableStateOf(null) }
|
|
||||||
val layoutPicker = layoutFilePicker { content, name ->
|
|
||||||
showLayoutEditDialog = (name ?: "new layout") to content
|
|
||||||
}
|
|
||||||
DropDownField(
|
|
||||||
items = appLayouts + customLayouts,
|
|
||||||
selectedItem = currentSubtype.mainLayoutName() ?: "qwerty",
|
|
||||||
onSelected = {
|
|
||||||
currentSubtype = currentSubtype.withLayout(LayoutType.MAIN, it)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
var showLayoutDeleteDialog by remember { mutableStateOf(false) }
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale))
|
|
||||||
Row (verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = it to null })
|
|
||||||
if (it in customLayouts && subtype.mainLayoutName() != it) // don't allow current main layout
|
|
||||||
Icon(painterResource(R.drawable.ic_bin), stringResource(R.string.delete), Modifier.clickable { showLayoutDeleteDialog = true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (showLayoutDeleteDialog) {
|
|
||||||
val others = SubtypeSettings.getAdditionalSubtypes().filter { st -> st.mainLayoutName() == it }.any { it != subtype }
|
|
||||||
ConfirmationDialog(
|
|
||||||
onDismissRequest = { showLayoutDeleteDialog = false },
|
|
||||||
confirmButtonText = stringResource(R.string.delete),
|
|
||||||
title = { Text(stringResource(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(it))) },
|
|
||||||
text = { if (others) Text(stringResource(R.string.layout_in_use)) },
|
|
||||||
onConfirmed = {
|
|
||||||
if (it == currentSubtype.mainLayoutName())
|
|
||||||
currentSubtype = currentSubtype.withoutLayout(LayoutType.MAIN)
|
|
||||||
LayoutUtilsCustom.deleteLayout(it, LayoutType.MAIN, ctx)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// todo: should be in same row as DropDownField
|
|
||||||
// maybe make the default button more customizable
|
|
||||||
IconButton(
|
|
||||||
{ showAddLayoutDialog = true }
|
|
||||||
) { Icon(painterResource(R.drawable.ic_plus), stringResource(R.string.button_title_add_custom_layout)) }
|
|
||||||
if (showLayoutEditDialog != null) {
|
|
||||||
val layoutName = showLayoutEditDialog!!.first
|
|
||||||
val startContent = showLayoutEditDialog?.second
|
|
||||||
?: if (layoutName in appLayouts) LayoutUtils.getContent(LayoutType.MAIN, layoutName, ctx)
|
|
||||||
else null
|
|
||||||
LayoutEditDialog(
|
|
||||||
onDismissRequest = { showLayoutEditDialog = null },
|
|
||||||
layoutType = LayoutType.MAIN,
|
|
||||||
initialLayoutName = layoutName,
|
|
||||||
startContent = startContent,
|
|
||||||
locale = currentSubtype.locale,
|
|
||||||
// only can edit name for new custom layout
|
|
||||||
isNameValid = if (layoutName in customLayouts) null else ({ it !in customLayouts }),
|
|
||||||
onEdited = {
|
|
||||||
if (layoutName !in customLayouts)
|
|
||||||
currentSubtype = currentSubtype.withLayout(LayoutType.MAIN, it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (showAddLayoutDialog) {
|
|
||||||
// todo: maybe supply link to discussion section for layouts
|
|
||||||
// todo: no html for compose, so message is broken
|
|
||||||
// try annotatedString
|
|
||||||
val link = "<a href='$LAYOUT_FORMAT_URL'>" + ctx.getString(R.string.dictionary_link_text) + "</a>"
|
|
||||||
ConfirmationDialog(
|
|
||||||
onDismissRequest = { showAddLayoutDialog = false },
|
|
||||||
title = { Text(stringResource(R.string.button_title_add_custom_layout)) },
|
|
||||||
text = { Text(stringResource(R.string.message_add_custom_layout, link)) },
|
|
||||||
onConfirmed = { showLayoutEditDialog = "new layout" to "" },
|
|
||||||
neutralButtonText = stringResource(R.string.button_load_custom),
|
|
||||||
onNeutral = {
|
|
||||||
showAddLayoutDialog = false
|
|
||||||
layoutPicker.launch(layoutIntent)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (availableLocalesForScript.size > 1) {
|
if (availableLocalesForScript.size > 1) {
|
||||||
WithSmallTitle(stringResource(R.string.secondary_locale)) {
|
WithSmallTitle(stringResource(R.string.secondary_locale)) {
|
||||||
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
|
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
|
||||||
|
@ -261,8 +182,10 @@ fun SubtypeDialog(
|
||||||
onSelected = {
|
onSelected = {
|
||||||
currentSubtype = currentSubtype.withLayout(type, it)
|
currentSubtype = currentSubtype.withLayout(type, it)
|
||||||
},
|
},
|
||||||
onDefault = { currentSubtype = currentSubtype.withoutLayout(type) },
|
extraButton = { DefaultButton(
|
||||||
isDefault = explicitLayout == null
|
onDefault = { currentSubtype = currentSubtype.withoutLayout(type) },
|
||||||
|
isDefault = explicitLayout == null
|
||||||
|
) },
|
||||||
) {
|
) {
|
||||||
val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it)
|
val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it)
|
||||||
else it.getStringResourceOrName("layout_", ctx)
|
else it.getStringResourceOrName("layout_", ctx)
|
||||||
|
@ -296,7 +219,7 @@ fun SubtypeDialog(
|
||||||
currentSubtype = if (newValue.isEmpty()) currentSubtype.without(ExtraValue.SECONDARY_LOCALES)
|
currentSubtype = if (newValue.isEmpty()) currentSubtype.without(ExtraValue.SECONDARY_LOCALES)
|
||||||
else currentSubtype.with(ExtraValue.SECONDARY_LOCALES, newValue)
|
else currentSubtype.with(ExtraValue.SECONDARY_LOCALES, newValue)
|
||||||
},
|
},
|
||||||
title = { Text("languages with dictionaries") }, // todo: string resource
|
title = { Text(stringResource(R.string.locales_with_dict)) },
|
||||||
items = availableLocalesForScript,
|
items = availableLocalesForScript,
|
||||||
initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
|
initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
|
||||||
?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(),
|
?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(),
|
||||||
|
@ -382,6 +305,100 @@ private fun PopupOrderDialog(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun MainLayoutRow(
|
||||||
|
subtype: InputMethodSubtype,
|
||||||
|
currentSubtype: SettingsSubtype,
|
||||||
|
customLayouts: List<String>,
|
||||||
|
setCurrentSubtype: (SettingsSubtype) -> Unit,
|
||||||
|
) {
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
WithSmallTitle(stringResource(R.string.keyboard_layout_set)) {
|
||||||
|
val appLayouts = LayoutUtils.getAvailableLayouts(LayoutType.MAIN, ctx, currentSubtype.locale)
|
||||||
|
var showAddLayoutDialog by remember { mutableStateOf(false) }
|
||||||
|
var showLayoutEditDialog: Pair<String, String?>? by remember { mutableStateOf(null) }
|
||||||
|
val layoutPicker = layoutFilePicker { content, name ->
|
||||||
|
showLayoutEditDialog = (name ?: "new layout") to content
|
||||||
|
}
|
||||||
|
DropDownField(
|
||||||
|
items = appLayouts + customLayouts,
|
||||||
|
selectedItem = currentSubtype.mainLayoutName() ?: SubtypeLocaleUtils.QWERTY,
|
||||||
|
onSelected = {
|
||||||
|
setCurrentSubtype(currentSubtype.withLayout(LayoutType.MAIN, it))
|
||||||
|
},
|
||||||
|
extraButton = {
|
||||||
|
IconButton({ showAddLayoutDialog = true })
|
||||||
|
{ Icon(painterResource(R.drawable.ic_plus), stringResource(R.string.button_title_add_custom_layout)) }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
var showLayoutDeleteDialog by remember { mutableStateOf(false) }
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale))
|
||||||
|
Row (verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = it to null })
|
||||||
|
if (it in customLayouts && subtype.mainLayoutName() != it) // don't allow current main layout
|
||||||
|
Icon(painterResource(R.drawable.ic_bin), stringResource(R.string.delete), Modifier.clickable { showLayoutDeleteDialog = true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (showLayoutDeleteDialog) {
|
||||||
|
val others = SubtypeSettings.getAdditionalSubtypes().filter { st -> st.mainLayoutName() == it }.any { it != subtype }
|
||||||
|
ConfirmationDialog(
|
||||||
|
onDismissRequest = { showLayoutDeleteDialog = false },
|
||||||
|
confirmButtonText = stringResource(R.string.delete),
|
||||||
|
title = { Text(stringResource(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(it))) },
|
||||||
|
text = { if (others) Text(stringResource(R.string.layout_in_use)) },
|
||||||
|
onConfirmed = {
|
||||||
|
if (it == currentSubtype.mainLayoutName())
|
||||||
|
setCurrentSubtype(currentSubtype.withoutLayout(LayoutType.MAIN))
|
||||||
|
LayoutUtilsCustom.deleteLayout(it, LayoutType.MAIN, ctx)
|
||||||
|
(ctx.getActivity() as? SettingsActivity)?.prefChanged?.value = 1234
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (showLayoutEditDialog != null) {
|
||||||
|
val layoutName = showLayoutEditDialog!!.first
|
||||||
|
val startContent = showLayoutEditDialog?.second
|
||||||
|
?: if (layoutName in appLayouts) LayoutUtils.getContent(LayoutType.MAIN, layoutName, ctx)
|
||||||
|
else null
|
||||||
|
LayoutEditDialog(
|
||||||
|
onDismissRequest = { showLayoutEditDialog = null },
|
||||||
|
layoutType = LayoutType.MAIN,
|
||||||
|
initialLayoutName = layoutName,
|
||||||
|
startContent = startContent,
|
||||||
|
locale = currentSubtype.locale,
|
||||||
|
// only can edit name for new custom layout
|
||||||
|
isNameValid = if (layoutName in customLayouts) null else ({ it !in customLayouts }),
|
||||||
|
onEdited = {
|
||||||
|
if (layoutName !in customLayouts)
|
||||||
|
setCurrentSubtype(currentSubtype.withLayout(LayoutType.MAIN, it))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (showAddLayoutDialog) {
|
||||||
|
// todo: maybe supply link to discussion section for layouts
|
||||||
|
// todo: no html for compose, so message is broken
|
||||||
|
// try annotatedString
|
||||||
|
val link = "<a href='$LAYOUT_FORMAT_URL'>" + ctx.getString(R.string.dictionary_link_text) + "</a>"
|
||||||
|
ConfirmationDialog(
|
||||||
|
onDismissRequest = { showAddLayoutDialog = false },
|
||||||
|
title = { Text(stringResource(R.string.button_title_add_custom_layout)) },
|
||||||
|
text = { Text(stringResource(R.string.message_add_custom_layout, link)) },
|
||||||
|
onConfirmed = { showLayoutEditDialog = "new layout" to "" },
|
||||||
|
neutralButtonText = stringResource(R.string.button_load_custom),
|
||||||
|
onNeutral = {
|
||||||
|
showAddLayoutDialog = false
|
||||||
|
layoutPicker.launch(layoutIntent)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun WithSmallTitle(
|
private fun WithSmallTitle(
|
||||||
description: String,
|
description: String,
|
||||||
|
@ -398,8 +415,7 @@ fun <T>DropDownField(
|
||||||
items: List<T>,
|
items: List<T>,
|
||||||
selectedItem: T,
|
selectedItem: T,
|
||||||
onSelected: (T) -> Unit,
|
onSelected: (T) -> Unit,
|
||||||
isDefault: Boolean? = null,
|
extraButton: @Composable (() -> Unit)? = null,
|
||||||
onDefault: () -> Unit = {},
|
|
||||||
itemContent: @Composable (T) -> Unit,
|
itemContent: @Composable (T) -> Unit,
|
||||||
) {
|
) {
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
@ -423,8 +439,8 @@ fun <T>DropDownField(
|
||||||
Modifier.rotate(-90f)
|
Modifier.rotate(-90f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (isDefault != null)
|
if (extraButton != null)
|
||||||
DefaultButton(onDefault, isDefault)
|
extraButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
|
|
|
@ -196,6 +196,8 @@
|
||||||
<string name="button_restore">Restore</string>
|
<string name="button_restore">Restore</string>
|
||||||
<!-- Preferences item for choosing secondary language -->
|
<!-- Preferences item for choosing secondary language -->
|
||||||
<string name="secondary_locale">Multilingual typing</string>
|
<string name="secondary_locale">Multilingual typing</string>
|
||||||
|
<!-- Clarification which locales are available for multilingual typing -->
|
||||||
|
<string name="locales_with_dict">Languages with dictionaries</string>
|
||||||
<!-- Preferences item for loading an external gesture typing library -->
|
<!-- Preferences item for loading an external gesture typing library -->
|
||||||
<string name="load_gesture_library">Load gesture typing library</string>
|
<string name="load_gesture_library">Load gesture typing library</string>
|
||||||
<!-- Description for "load_gesture_library" option -->
|
<!-- Description for "load_gesture_library" option -->
|
||||||
|
|
Loading…
Add table
Reference in a new issue