diff --git a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtils.kt index b4d78dd95..bc249574b 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtils.kt @@ -18,7 +18,7 @@ object LayoutUtils { .apply { addAll(context.resources.getStringArray(R.array.predefined_layouts)) } if (locale.script() == ScriptUtils.SCRIPT_LATIN) return context.resources.getStringArray(R.array.predefined_layouts).toList() - return SubtypeSettings.getSubtypesForLocale(locale).mapNotNullTo(HashSet()) { it.mainLayoutName() } + return SubtypeSettings.getResourceSubtypesForLocale(locale).mapNotNullTo(HashSet()) { it.mainLayoutName() } } fun getLMainLayoutsForLocales(locales: List, context: Context): Collection = diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeLocaleUtils.java b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeLocaleUtils.java index 5d7513517..65fe4d017 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeLocaleUtils.java +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeLocaleUtils.java @@ -224,8 +224,21 @@ public final class SubtypeLocaleUtils { } @NonNull - public static String getSubtypeDisplayNameInSystemLocale( - @NonNull final InputMethodSubtype subtype) { + public static String getDisplayNameInSystemLocale(@NonNull final String mainLayoutName, @NonNull final Locale locale) { + final String displayName = getMainLayoutDisplayName(mainLayoutName); + if (displayName != null) // works for custom and latin layouts + return displayName; + // we have some locale-specific layout + for (InputMethodSubtype subtype : SubtypeSettings.INSTANCE.getResourceSubtypesForLocale(locale)) { + final String main = LayoutType.Companion.getMainLayoutFromExtraValue(subtype.getExtraValue()); + if (mainLayoutName.equals(main)) + return getSubtypeDisplayNameInSystemLocale(subtype); + } + return mainLayoutName; // should never happen... + } + + @NonNull + public static String getSubtypeDisplayNameInSystemLocale(@NonNull final InputMethodSubtype subtype) { final Locale displayLocale = ConfigurationCompatKt.locale(sResources.getConfiguration()); return getSubtypeDisplayNameInternal(subtype, displayLocale); } diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt index 8b7b51215..20fa3ca2e 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt @@ -137,7 +137,7 @@ object SubtypeSettings { return !resourceSubtypesByLocale[locale].isNullOrEmpty() } - fun getSubtypesForLocale(locale: Locale): List = resourceSubtypesByLocale[locale].orEmpty() + fun getResourceSubtypesForLocale(locale: Locale): List = resourceSubtypesByLocale[locale].orEmpty() fun getAvailableSubtypeLocales(): Collection { require(initialized) diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/SubtypeDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/SubtypeDialog.kt index 63ad0ad24..9c2833dce 100644 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/SubtypeDialog.kt +++ b/app/src/main/java/helium314/keyboard/settings/dialogs/SubtypeDialog.kt @@ -3,6 +3,7 @@ package helium314.keyboard.settings.dialogs import android.content.Context import android.view.inputmethod.InputMethodSubtype import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,6 +13,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -58,20 +60,16 @@ import helium314.keyboard.latin.utils.SubtypeSettings import helium314.keyboard.latin.utils.SubtypeUtilsAdditional import helium314.keyboard.latin.utils.getDictionaryLocales import helium314.keyboard.latin.utils.getStringResourceOrName +import helium314.keyboard.latin.utils.locale import helium314.keyboard.latin.utils.prefs import helium314.keyboard.settings.screens.GetIcon import java.util.Locale // todo: // save when "editing" a resource subtypes is not working -// default buttons missing -// string resources -// dialog doesn't look good... // settings upgrade to move the override settings to extra values, and actually use them (via getSelectedSubtype, not RichIMM) @Composable fun SubtypeDialog( - // could also use InputMethodSubtype if there is any advantage - // but as soon as anything is changed we will need an additional subtype anyway... onDismissRequest: () -> Unit, subtype: InputMethodSubtype, onConfirmed: (SettingsSubtype) -> Unit, @@ -99,8 +97,9 @@ fun SubtypeDialog( text = { Column( modifier = Modifier.verticalScroll(scrollState), + verticalArrangement = Arrangement.spacedBy(8.dp), ) { - WithSmallTitle("main layout") { + WithSmallTitle(stringResource(R.string.keyboard_layout_set)) { val appLayouts = LayoutUtils.getAvailableLayouts(LayoutType.MAIN, ctx, currentSubtype.locale) val customLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name } DropDownField( @@ -110,10 +109,9 @@ fun SubtypeDialog( currentSubtype = currentSubtype.withLayout(LayoutType.MAIN, it) } ) { - // todo: displayName can be complicated and may require an inputmethodsubtype... - // maybe search for stuff in resource subtypes? - Text(it) + Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale)) // todo: edit button? or only for selected layout? and delete button? + // yes, even just to make clear what is custom } } WithSmallTitle(stringResource(R.string.secondary_locale)) { @@ -121,7 +119,7 @@ fun SubtypeDialog( val text = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES) ?.split(Separators.KV)?.joinToString(", ") { LocaleUtils.getLocaleDisplayNameInSystemLocale(it.constructLocale(), ctx) - } ?: "none" + } ?: stringResource(R.string.action_none) Text(text, Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge) } } @@ -131,32 +129,56 @@ fun SubtypeDialog( Text("not yet implemented") } // todo: this looks strange without the title - TextButton(onClick = { showKeyOrderDialog = true }) - { Text(stringResource(R.string.popup_order), Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge) } - TextButton(onClick = { showHintOrderDialog = true }) - { Text(stringResource(R.string.hint_source), Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge) } - if (currentSubtype.locale.script() == SCRIPT_LATIN) + Row { + TextButton(onClick = { showKeyOrderDialog = true }, Modifier.weight(1f)) + { Text(stringResource(R.string.popup_order), style = MaterialTheme.typography.bodyLarge) } + DefaultButton( + { currentSubtype = currentSubtype.without(ExtraValue.POPUP_ORDER) }, + currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) == null + ) + } + Row { + TextButton(onClick = { showHintOrderDialog = true }, Modifier.weight(1f)) + { Text(stringResource(R.string.hint_source), style = MaterialTheme.typography.bodyLarge) } + DefaultButton( + { currentSubtype = currentSubtype.without(ExtraValue.HINT_ORDER) }, + currentSubtype.getExtraValueOf(ExtraValue.HINT_ORDER) == null + ) + } + if (currentSubtype.locale.script() == SCRIPT_LATIN) { WithSmallTitle(stringResource(R.string.show_popup_keys_title)) { val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS) val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)!! - TextButton(onClick = { showMorePopupsDialog = true }, Modifier.fillMaxWidth()) + Row { + TextButton(onClick = { showMorePopupsDialog = true }, Modifier.weight(1f)) { Text(stringResource(morePopupKeysResId(value))) } + DefaultButton( + { currentSubtype = currentSubtype.without(ExtraValue.MORE_POPUPS) }, + explicitValue == null + ) + } } - if (hasLocalizedNumberRow(currentSubtype.locale, ctx)) + } + if (hasLocalizedNumberRow(currentSubtype.locale, ctx)) { Row { + val checked = currentSubtype.getExtraValueOf(ExtraValue.LOCALIZED_NUMBER_ROW)?.toBoolean() Text(stringResource(R.string.localized_number_row), Modifier.weight(1f)) Switch( - checked = currentSubtype.getExtraValueOf(ExtraValue.LOCALIZED_NUMBER_ROW)?.toBoolean() - ?: prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, Defaults.PREF_LOCALIZED_NUMBER_ROW), + checked = checked ?: prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, Defaults.PREF_LOCALIZED_NUMBER_ROW), onCheckedChange = { currentSubtype = currentSubtype.with(ExtraValue.LOCALIZED_NUMBER_ROW, it.toString()) } ) - // todo: default button? + DefaultButton( + { currentSubtype = currentSubtype.without(ExtraValue.LOCALIZED_NUMBER_ROW) }, + checked == null + ) } + } + HorizontalDivider() + Text(stringResource(R.string.settings_screen_secondary_layouts), style = MaterialTheme.typography.titleMedium) LayoutType.entries.forEach { type -> if (type == LayoutType.MAIN) return@forEach - // todo: also some default button, to be shown when necessary, uses currentSubtype.withoutLayout(type) WithSmallTitle(stringResource(type.displayNameId)) { val explicitLayout = currentSubtype.layoutName(type) val layout = explicitLayout ?: Settings.readDefaultLayoutName(type, prefs) @@ -167,10 +189,12 @@ fun SubtypeDialog( selectedItem = layout, onSelected = { currentSubtype = currentSubtype.withLayout(type, it) - } + }, + onDefault = { currentSubtype = currentSubtype.withoutLayout(type) }, + isDefault = explicitLayout == null ) { val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it) - else it.getStringResourceOrName("layout_", ctx) + else it.getStringResourceOrName("layout_", ctx) Text(displayName) // content is name, and if it's user layout there is an edit button // also maybe there should be an "add" button similar to the old settings @@ -183,8 +207,8 @@ fun SubtypeDialog( if (showSecondaryLocaleDialog) MultiListPickerDialog( onDismissRequest = { showSecondaryLocaleDialog = false }, - onConfirmed = { - val newValue = it.joinToString(Separators.KV) { it.toLanguageTag() } + onConfirmed = { locales -> + val newValue = locales.joinToString(Separators.KV) { it.toLanguageTag() } currentSubtype = if (newValue.isEmpty()) currentSubtype.without(ExtraValue.SECONDARY_LOCALES) else currentSubtype.with(ExtraValue.SECONDARY_LOCALES, newValue) }, @@ -201,8 +225,8 @@ fun SubtypeDialog( title = stringResource(R.string.popup_order), showDefault = setting != null, onConfirmed = { - if (it == null) currentSubtype = currentSubtype.without(ExtraValue.POPUP_ORDER) - else currentSubtype = currentSubtype.with(ExtraValue.POPUP_ORDER, it) + currentSubtype = if (it == null) currentSubtype.without(ExtraValue.POPUP_ORDER) + else currentSubtype.with(ExtraValue.POPUP_ORDER, it) } ) } @@ -214,13 +238,12 @@ fun SubtypeDialog( title = stringResource(R.string.hint_source), showDefault = setting != null, onConfirmed = { - if (it == null) currentSubtype = currentSubtype.without(ExtraValue.HINT_ORDER) - else currentSubtype = currentSubtype.with(ExtraValue.HINT_ORDER, it) + currentSubtype = if (it == null) currentSubtype.without(ExtraValue.HINT_ORDER) + else currentSubtype.with(ExtraValue.HINT_ORDER, it) } ) } if (showMorePopupsDialog) { - // todo: default button in here? or next to the pref? val items = listOf(POPUP_KEYS_NORMAL, POPUP_KEYS_MAIN, POPUP_KEYS_MORE, POPUP_KEYS_ALL) val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS) val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS) @@ -262,7 +285,7 @@ private fun PopupOrderDialog( var checked by rememberSaveable { mutableStateOf(item.state) } Row(verticalAlignment = Alignment.CenterVertically) { KeyboardIconsSet.instance.GetIcon(item.name) - val text = item.name.lowercase().getStringResourceOrName("", ctx) + val text = item.name.lowercase().getStringResourceOrName("popup_keys_", ctx) Text(text, Modifier.weight(1f)) Switch( checked = checked, @@ -290,6 +313,8 @@ private fun DropDownField( items: List, selectedItem: T, onSelected: (T) -> Unit, + isDefault: Boolean? = null, + onDefault: () -> Unit = {}, itemContent: @Composable (T) -> Unit, ) { var expanded by remember { mutableStateOf(false) } @@ -299,7 +324,7 @@ private fun DropDownField( ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 4.dp) + modifier = Modifier.padding(start = 8.dp, bottom = 4.dp) ) { Box(Modifier.weight(1f)) { itemContent(selectedItem) @@ -310,10 +335,12 @@ private fun DropDownField( ) { Icon( painterResource(R.drawable.ic_arrow_left), - null, + "show dropdown", Modifier.rotate(-90f) ) } + if (isDefault != null) + DefaultButton(onDefault, isDefault) } } DropdownMenu( @@ -329,16 +356,19 @@ private fun DropDownField( } } -// get locales with same script as main locale, but different language -// todo: do we need any sort of force-ascii like in old variant? -// now we use hi-Latn and sr-Latn for the relevant subtypes, so it should be fine -// only potential issue is the Latn-default if we don't have the script for a locale, -// but in that case we should rather add the script to ScriptUtils -private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale): List { - val locales = getDictionaryLocales(context) - locales.removeAll { -// it.language == mainLocale.language || it.script() != mainLocale.script() - it == mainLocale || it.script() != mainLocale.script() // todo: check whether this is fine, otherwise go back to the variant above +@Composable +private fun DefaultButton( + onDefault: () -> Unit, + isDefault: Boolean +) { + IconButton( + onClick = onDefault, + enabled = !isDefault + ) { + Icon(painterResource(R.drawable.sym_keyboard_settings_holo), "default") // todo: more understandable icon! } - return locales.toList() + } + +private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale): List = + getDictionaryLocales(context).filter { it != mainLocale && it.script() == mainLocale.script() }