mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-06-07 15:17:42 +00:00
add language screen (not finished)
This commit is contained in:
parent
12f1e20d9f
commit
85382de881
12 changed files with 709 additions and 20 deletions
|
@ -92,6 +92,9 @@ public final class Constants {
|
|||
/** Overrides the general "more popups" setting */
|
||||
public static final String MORE_POPUPS = "MorePopups";
|
||||
|
||||
/** Overrides the general "localized number row" setting */
|
||||
public static final String LOCALIZED_NUMBER_ROW = "LocalizedNumberRow";
|
||||
|
||||
private ExtraValue() {
|
||||
// This utility class is not publicly instantiable.
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package helium314.keyboard.latin.utils
|
||||
|
||||
import android.content.Context
|
||||
import helium314.keyboard.latin.R
|
||||
import helium314.keyboard.latin.settings.Defaults.default
|
||||
import helium314.keyboard.latin.utils.LayoutType.Companion.folder
|
||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||
|
@ -12,10 +13,11 @@ object LayoutUtils {
|
|||
if (layoutType != LayoutType.MAIN)
|
||||
return context.assets.list(layoutType.folder)?.map { it.substringBefore(".") }.orEmpty()
|
||||
if (locale == null)
|
||||
return SubtypeSettings.getAllAvailableSubtypes().mapTo(HashSet()) { it.mainLayoutName()?.substringBefore("+") ?: "qwerty" }
|
||||
if (locale.script() == ScriptUtils.SCRIPT_LATIN)
|
||||
return SubtypeSettings.getAllAvailableSubtypes().filter { it.isAsciiCapable && !LayoutUtilsCustom.isCustomLayout(it.mainLayoutName() ?: "qwerty") }
|
||||
return SubtypeSettings.getAllAvailableSubtypes()
|
||||
.mapTo(HashSet()) { it.mainLayoutName()?.substringBefore("+") ?: "qwerty" }
|
||||
.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() }
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAY
|
|||
import helium314.keyboard.latin.common.LocaleUtils
|
||||
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||
import helium314.keyboard.latin.define.DebugFlags
|
||||
import helium314.keyboard.latin.utils.LayoutType.Companion.toExtraValue
|
||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import java.util.Locale
|
||||
|
@ -64,22 +65,23 @@ fun getResourceSubtypes(resources: Resources): List<InputMethodSubtype> {
|
|||
|
||||
/** Workaround for SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale ignoring custom layout names */
|
||||
// todo (later): this should be done properly and in SubtypeLocaleUtils
|
||||
fun InputMethodSubtype.displayName(context: Context): CharSequence {
|
||||
fun InputMethodSubtype.displayName(context: Context): String {
|
||||
val layoutName = SubtypeLocaleUtils.getMainLayoutName(this)
|
||||
if (LayoutUtilsCustom.isCustomLayout(layoutName))
|
||||
return "${LocaleUtils.getLocaleDisplayNameInSystemLocale(locale(), context)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
|
||||
return SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(this)
|
||||
}
|
||||
|
||||
data class SettingsSubtype(val locale: Locale, val extraValue: String) {
|
||||
// some kind of intermediate between the string stored in preferences and an InputMethodSubtype
|
||||
data class SettingsSubtype(val locale: Locale, val extraValues: String) {
|
||||
|
||||
fun toPref() = locale.toLanguageTag() + Separators.SET + extraValue
|
||||
fun toPref() = locale.toLanguageTag() + Separators.SET + extraValues
|
||||
|
||||
/** Creates an additional subtype from the SettingsSubtype.
|
||||
* Resulting InputMethodSubtypes are equal if SettingsSubtypes are equal */
|
||||
fun toAdditionalSubtype(): InputMethodSubtype? {
|
||||
val asciiCapable = locale.script() == ScriptUtils.SCRIPT_LATIN
|
||||
val subtype = SubtypeUtilsAdditional.createAdditionalSubtype(locale, extraValue, asciiCapable, true)
|
||||
val subtype = SubtypeUtilsAdditional.createAdditionalSubtype(locale, extraValues, asciiCapable, true)
|
||||
if (subtype.nameResId == SubtypeLocaleUtils.UNKNOWN_KEYBOARD_LAYOUT && !LayoutUtilsCustom.isCustomLayout(mainLayoutName() ?: "qwerty")) {
|
||||
// Skip unknown keyboard layout subtype. This may happen when predefined keyboard
|
||||
// layout has been removed.
|
||||
|
@ -89,7 +91,40 @@ data class SettingsSubtype(val locale: Locale, val extraValue: String) {
|
|||
return subtype
|
||||
}
|
||||
|
||||
fun mainLayoutName() = LayoutType.getMainLayoutFromExtraValue(extraValue)
|
||||
fun mainLayoutName() = LayoutType.getMainLayoutFromExtraValue(extraValues)
|
||||
|
||||
fun layoutName(type: LayoutType) = LayoutType.getLayoutMap(getExtraValueOf(KEYBOARD_LAYOUT_SET) ?: "")[type]
|
||||
|
||||
fun with(extraValueKey: String, extraValue: String?): SettingsSubtype {
|
||||
val newList = extraValues.split(",")
|
||||
.filterNot { it.startsWith("$extraValueKey=") || it == extraValueKey }
|
||||
val newValue = if (extraValue == null) extraValueKey else "$extraValueKey=$extraValue"
|
||||
val newValues = (newList + newValue).joinToString(",")
|
||||
return copy(extraValues = newValues)
|
||||
}
|
||||
|
||||
fun without(extraValueKey: String): SettingsSubtype {
|
||||
val newValues = extraValues.split(",")
|
||||
.filterNot { it.startsWith("$extraValueKey=") || it == extraValueKey }
|
||||
.joinToString(",")
|
||||
return copy(extraValues = newValues)
|
||||
}
|
||||
|
||||
fun getExtraValueOf(extraValueKey: String): String? = extraValues.split(",")
|
||||
.firstOrNull { it.startsWith("$extraValueKey=") }?.substringAfter("$extraValueKey=")
|
||||
|
||||
fun withLayout(type: LayoutType, name: String): SettingsSubtype {
|
||||
val map = LayoutType.getLayoutMap(getExtraValueOf(KEYBOARD_LAYOUT_SET) ?: "")
|
||||
map[type] = name
|
||||
return with(KEYBOARD_LAYOUT_SET, map.toExtraValue())
|
||||
}
|
||||
|
||||
fun withoutLayout(type: LayoutType): SettingsSubtype {
|
||||
val map = LayoutType.getLayoutMap(getExtraValueOf(KEYBOARD_LAYOUT_SET) ?: "")
|
||||
map.remove(type)
|
||||
return if (map.isEmpty()) without(KEYBOARD_LAYOUT_SET)
|
||||
else with(KEYBOARD_LAYOUT_SET, map.toExtraValue())
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun String.toSettingsSubtype() =
|
||||
|
@ -109,6 +144,8 @@ data class SettingsSubtype(val locale: Locale, val extraValue: String) {
|
|||
// todo: this is in "old" additional subtypes, but where was it set?
|
||||
// must have been by app in 2.3, but not any more?
|
||||
// anyway, a. we can easily create it again, and b. it may contain "bad" characters messing up the extra value
|
||||
// removing UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME changes the name of some layouts,
|
||||
// e.g. from "English (United States)" to "English (US)"
|
||||
|| it.startsWith(ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)
|
||||
}.joinToString(",")
|
||||
require(!filteredExtraValue.contains(Separators.SETS) && !filteredExtraValue.contains(Separators.SET))
|
||||
|
|
|
@ -51,6 +51,7 @@ object SubtypeUtilsAdditional {
|
|||
fun createEmojiCapableAdditionalSubtype(locale: Locale, mainLayoutName: String, asciiCapable: Boolean) =
|
||||
createAdditionalSubtype(locale, "${ExtraValue.KEYBOARD_LAYOUT_SET}=MAIN${Separators.KV}$mainLayoutName", asciiCapable, true)
|
||||
|
||||
// todo: consider using SettingsSubtype
|
||||
fun addAdditionalSubtype(prefs: SharedPreferences, subtype: InputMethodSubtype) {
|
||||
val oldAdditionalSubtypesString = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!
|
||||
val additionalSubtypes = createAdditionalSubtypes(oldAdditionalSubtypesString).toMutableSet()
|
||||
|
@ -67,6 +68,27 @@ object SubtypeUtilsAdditional {
|
|||
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
|
||||
}
|
||||
|
||||
// updates additional subtypes, enabled subtypes, and selected subtype
|
||||
fun changeAdditionalSubtype(from: SettingsSubtype, to: SettingsSubtype, prefs: SharedPreferences) {
|
||||
val new = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!
|
||||
.split(Separators.SETS).mapTo(sortedSetOf()) {
|
||||
if (it == from.toPref()) to.toPref() else it
|
||||
}
|
||||
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, new.joinToString(Separators.SETS)).apply()
|
||||
|
||||
val fromSubtype = from.toAdditionalSubtype() // will be null if we edit a resource subtype
|
||||
val toSubtype = to.toAdditionalSubtype() // should never be null
|
||||
if (SubtypeSettings.getSelectedSubtype(prefs) == fromSubtype && toSubtype != null) {
|
||||
SubtypeSettings.setSelectedSubtype(prefs, toSubtype)
|
||||
}
|
||||
if (SubtypeSettings.getEnabledSubtypes(prefs, false).contains(fromSubtype)) {
|
||||
if (fromSubtype != null)
|
||||
SubtypeSettings.removeEnabledSubtype(prefs, fromSubtype)
|
||||
if (toSubtype != null)
|
||||
SubtypeSettings.addEnabledSubtype(prefs, toSubtype)
|
||||
}
|
||||
}
|
||||
|
||||
fun createAdditionalSubtypes(prefSubtypes: String): List<InputMethodSubtype> {
|
||||
if (prefSubtypes.isEmpty())
|
||||
return emptyList()
|
||||
|
|
|
@ -16,9 +16,10 @@ import helium314.keyboard.settings.screens.AppearanceScreen
|
|||
import helium314.keyboard.settings.screens.ColorsScreen
|
||||
import helium314.keyboard.settings.screens.DebugScreen
|
||||
import helium314.keyboard.settings.screens.GestureTypingScreen
|
||||
import helium314.keyboard.settings.screens.LayoutScreen
|
||||
import helium314.keyboard.settings.screens.LanguageScreen
|
||||
import helium314.keyboard.settings.screens.MainSettingsScreen
|
||||
import helium314.keyboard.settings.screens.PreferencesScreen
|
||||
import helium314.keyboard.settings.screens.SecondaryLayoutScreen
|
||||
import helium314.keyboard.settings.screens.TextCorrectionScreen
|
||||
import helium314.keyboard.settings.screens.ToolbarScreen
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -92,10 +93,10 @@ fun SettingsNavHost(
|
|||
// )
|
||||
}
|
||||
composable(SettingsDestination.Languages) {
|
||||
// LanguageScreen(onClickBack = ::goBack)
|
||||
LanguageScreen(onClickBack = ::goBack)
|
||||
}
|
||||
composable(SettingsDestination.Layouts) {
|
||||
LayoutScreen(onClickBack = ::goBack)
|
||||
SecondaryLayoutScreen(onClickBack = ::goBack)
|
||||
}
|
||||
composable(SettingsDestination.Colors) {
|
||||
ColorsScreen(isNight = false, onClickBack = ::goBack)
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
package helium314.keyboard.settings.dialogs
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
// modified version of ListPickerDialog for selecting multiple items
|
||||
@Composable
|
||||
fun <T: Any> MultiListPickerDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
items: List<T>,
|
||||
onConfirmed: (Collection<T>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
title: (@Composable () -> Unit)? = null,
|
||||
initialSelection: List<T> = emptyList(),
|
||||
getItemName: (@Composable (T) -> String) = { it.toString() },
|
||||
) {
|
||||
var selected by remember { mutableStateOf(initialSelection.toSet()) }
|
||||
val state = rememberLazyListState()
|
||||
|
||||
ThreeButtonAlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirmed = { onConfirmed(selected) },
|
||||
confirmButtonText = stringResource(android.R.string.ok),
|
||||
modifier = modifier,
|
||||
title = title,
|
||||
text = {
|
||||
CompositionLocalProvider(
|
||||
LocalTextStyle provides MaterialTheme.typography.bodyLarge
|
||||
) {
|
||||
LazyColumn(state = state) {
|
||||
items(items) { item ->
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
selected = if (item in selected) selected - item else selected + item
|
||||
}
|
||||
.padding(horizontal = 16.dp)
|
||||
.heightIn(min = 40.dp)
|
||||
) {
|
||||
Text(
|
||||
text = getItemName(item),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Switch(
|
||||
checked = item in selected,
|
||||
onCheckedChange = {
|
||||
selected = if (it) selected + item else selected - item
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
val items = remember { (0..<5).toList() }
|
||||
MultiListPickerDialog(
|
||||
onDismissRequest = {},
|
||||
items = items,
|
||||
onConfirmed = {},
|
||||
title = { Text("Select something") },
|
||||
initialSelection = listOf(2, 4),
|
||||
getItemName = { "Item $it" },
|
||||
)
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
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
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
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
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
|
||||
import helium314.keyboard.keyboard.internal.keyboard_parser.hasLocalizedNumberRow
|
||||
import helium314.keyboard.latin.R
|
||||
import helium314.keyboard.latin.common.Constants.Separators
|
||||
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
|
||||
import helium314.keyboard.latin.common.LocaleUtils
|
||||
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||
import helium314.keyboard.latin.settings.Defaults
|
||||
import helium314.keyboard.latin.settings.Settings
|
||||
import helium314.keyboard.latin.utils.LayoutType
|
||||
import helium314.keyboard.latin.utils.LayoutType.Companion.displayNameId
|
||||
import helium314.keyboard.latin.utils.LayoutUtils
|
||||
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
||||
import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_LATIN
|
||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||
import helium314.keyboard.latin.utils.SettingsSubtype
|
||||
import helium314.keyboard.latin.utils.SettingsSubtype.Companion.toSettingsSubtype
|
||||
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
|
||||
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.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
|
||||
@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,
|
||||
) {
|
||||
// todo: make sure the values are always correct (e.g. if using rememberSaveable and rotating)
|
||||
val ctx = LocalContext.current
|
||||
val prefs = ctx.prefs()
|
||||
var currentSubtype by remember { mutableStateOf(subtype.toSettingsSubtype()) }
|
||||
val availableLocalesForScript = getAvailableSecondaryLocales(ctx, currentSubtype.locale).sortedBy { it.toLanguageTag() }
|
||||
var showSecondaryLocaleDialog by remember { mutableStateOf(false) }
|
||||
var showKeyOrderDialog by remember { mutableStateOf(false) }
|
||||
var showHintOrderDialog by remember { mutableStateOf(false) }
|
||||
var showMorePopupsDialog by remember { mutableStateOf(false) }
|
||||
val scrollState = rememberScrollState()
|
||||
ThreeButtonAlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirmed = { onConfirmed(currentSubtype) },
|
||||
neutralButtonText = if (SubtypeSettings.isAdditionalSubtype(subtype)) null else stringResource(R.string.delete),
|
||||
onNeutral = {
|
||||
SubtypeUtilsAdditional.removeAdditionalSubtype(prefs, subtype)
|
||||
SubtypeSettings.removeEnabledSubtype(prefs, subtype)
|
||||
|
||||
}, // maybe confirm dialog?
|
||||
title = { Text(SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype)) },
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
WithDescription("main layout") {
|
||||
val appLayouts = LayoutUtils.getAvailableLayouts(LayoutType.MAIN, ctx, currentSubtype.locale)
|
||||
val customLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name }
|
||||
DropDownField(
|
||||
items = appLayouts + customLayouts,
|
||||
selectedItem = currentSubtype.mainLayoutName() ?: "qwerty", // todo: what about qwerty+ and similar?
|
||||
onSelected = {
|
||||
currentSubtype = currentSubtype.withLayout(LayoutType.MAIN, it)
|
||||
}
|
||||
) {
|
||||
// todo: displayName can be complicated and may require an inputmehtodsubtype...
|
||||
// maybe search for stuff in resource subtypes?
|
||||
Text(it)
|
||||
// todo: edit button? or only for selected layout? and delete button?
|
||||
}
|
||||
}
|
||||
WithDescription(stringResource(R.string.secondary_locale)) {
|
||||
TextButton(onClick = { showSecondaryLocaleDialog = true }, Modifier.fillMaxWidth()) {
|
||||
val text = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
|
||||
?.split(Separators.KV)?.joinToString(", ") {
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(it.constructLocale(), ctx)
|
||||
} ?: "none"
|
||||
Text(text, style = MaterialTheme.typography.bodyLarge)
|
||||
}
|
||||
}
|
||||
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
|
||||
val text = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
|
||||
?.split(Separators.KV)?.joinToString(", ") {
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(it.constructLocale(), ctx)
|
||||
} ?: ""
|
||||
Column(Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(R.string.secondary_locale))
|
||||
Text(text, style = MaterialTheme.typography.bodyLarge)
|
||||
}
|
||||
}
|
||||
WithDescription("dictionaries") {
|
||||
// todo: maybe remove here and use a separate screen for dictionary management
|
||||
// would be clearer, as dicts are per language (and no intention to change it)
|
||||
Text("not yet implemented")
|
||||
}
|
||||
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)
|
||||
WithDescription(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)
|
||||
val textResId = when (value) { // todo: this should not be duplicated... see below
|
||||
"normal" -> R.string.show_popup_keys_normal
|
||||
"more" -> R.string.show_popup_keys_more
|
||||
"all" -> R.string.show_popup_keys_all
|
||||
else -> R.string.show_popup_keys_main
|
||||
}
|
||||
TextButton(onClick = { showMorePopupsDialog = true }, Modifier.fillMaxWidth())
|
||||
{ Text(stringResource(textResId)) }
|
||||
}
|
||||
if (hasLocalizedNumberRow(currentSubtype.locale, ctx))
|
||||
Row {
|
||||
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),
|
||||
onCheckedChange = {
|
||||
currentSubtype = currentSubtype.with(ExtraValue.LOCALIZED_NUMBER_ROW, it.toString())
|
||||
}
|
||||
)
|
||||
// todo: default button?
|
||||
}
|
||||
LayoutType.entries.forEach { type ->
|
||||
if (type == LayoutType.MAIN) return@forEach
|
||||
// todo: also some default button, to be shown when necessary, uses currentSubtype.withoutLayout(type)
|
||||
WithDescription(stringResource(type.displayNameId)) {
|
||||
val explicitLayout = currentSubtype.layoutName(type)
|
||||
val layout = explicitLayout ?: Settings.readDefaultLayoutName(type, prefs)
|
||||
val defaultLayouts = LayoutUtils.getAvailableLayouts(type, ctx)
|
||||
val customLayouts = LayoutUtilsCustom.getLayoutFiles(type, ctx).map { it.name }
|
||||
DropDownField(
|
||||
items = defaultLayouts + customLayouts,
|
||||
selectedItem = layout,
|
||||
onSelected = {
|
||||
currentSubtype = currentSubtype.withLayout(type, it)
|
||||
}
|
||||
) {
|
||||
val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
if (showSecondaryLocaleDialog)
|
||||
MultiListPickerDialog(
|
||||
onDismissRequest = { showSecondaryLocaleDialog = false },
|
||||
onConfirmed = {
|
||||
val newValue = it.joinToString(Separators.KV) { it.toLanguageTag() }
|
||||
currentSubtype = if (newValue.isEmpty()) currentSubtype.without(ExtraValue.SECONDARY_LOCALES)
|
||||
else currentSubtype.with(ExtraValue.SECONDARY_LOCALES, newValue)
|
||||
},
|
||||
items = availableLocalesForScript,
|
||||
initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
|
||||
?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(),
|
||||
getItemName = { LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx) }
|
||||
)
|
||||
if (showKeyOrderDialog) {
|
||||
val setting = currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER)
|
||||
PopupOrderDialog(
|
||||
onDismissRequest = { showKeyOrderDialog = false },
|
||||
initialValue = setting ?: prefs.getString(Settings.PREF_POPUP_KEYS_ORDER, Defaults.PREF_POPUP_KEYS_ORDER)!!,
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (showHintOrderDialog) {
|
||||
val setting = currentSubtype.getExtraValueOf(ExtraValue.HINT_ORDER)
|
||||
PopupOrderDialog(
|
||||
onDismissRequest = { showHintOrderDialog = false },
|
||||
initialValue = setting ?: prefs.getString(Settings.PREF_POPUP_KEYS_LABELS_ORDER, Defaults.PREF_POPUP_KEYS_LABELS_ORDER)!!,
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (showMorePopupsDialog) {
|
||||
// todo: default button in here? or next to the pref?
|
||||
val items = listOf("normal", "main", "more", "all")
|
||||
val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS)
|
||||
val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)
|
||||
ListPickerDialog(
|
||||
onDismissRequest = { showMorePopupsDialog = false },
|
||||
items = items,
|
||||
getItemName = {
|
||||
val textResId = when (it) { // todo: this should not be duplicated... now we have it twice here, and in advanced settings
|
||||
"normal" -> R.string.show_popup_keys_normal
|
||||
"more" -> R.string.show_popup_keys_more
|
||||
"all" -> R.string.show_popup_keys_all
|
||||
else -> R.string.show_popup_keys_main
|
||||
}
|
||||
stringResource(textResId)
|
||||
},
|
||||
selectedItem = value,
|
||||
onItemSelected = { currentSubtype = currentSubtype.with(ExtraValue.MORE_POPUPS, it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// from ReorderSwitchPreference
|
||||
@Composable
|
||||
private fun PopupOrderDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
initialValue: String,
|
||||
onConfirmed: (String?) -> Unit,
|
||||
title: String,
|
||||
showDefault: Boolean
|
||||
) {
|
||||
class KeyAndState(var name: String, var state: Boolean)
|
||||
val items = initialValue.split(Separators.ENTRY).map {
|
||||
KeyAndState(it.substringBefore(Separators.KV), it.substringAfter(Separators.KV).toBoolean())
|
||||
}
|
||||
val ctx = LocalContext.current
|
||||
ReorderDialog(
|
||||
onConfirmed = { reorderedItems ->
|
||||
val value = reorderedItems.joinToString(Separators.ENTRY) { it.name + Separators.KV + it.state }
|
||||
onConfirmed(value)
|
||||
},
|
||||
onDismissRequest = onDismissRequest,
|
||||
onNeutral = { onDismissRequest(); onConfirmed(null) },
|
||||
neutralButtonText = if (showDefault) stringResource(R.string.button_default) else null,
|
||||
items = items,
|
||||
title = { Text(title) },
|
||||
displayItem = { item ->
|
||||
var checked by rememberSaveable { 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
|
||||
private fun WithDescription(
|
||||
description: String,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Column {
|
||||
Text(description, style = MaterialTheme.typography.bodySmall)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T>DropDownField(
|
||||
items: List<T>,
|
||||
selectedItem: T,
|
||||
onSelected: (T) -> Unit,
|
||||
itemContent: @Composable (T) -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
Box(
|
||||
Modifier.clickable { expanded = !expanded }
|
||||
//.border(2.dp, MaterialTheme.colorScheme.onSecondary)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 4.dp)
|
||||
) {
|
||||
Box(Modifier.weight(1f)) {
|
||||
itemContent(selectedItem)
|
||||
}
|
||||
IconButton(
|
||||
onClick = { expanded = !expanded },
|
||||
enabled = items.size > 1
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_arrow_left),
|
||||
null,
|
||||
Modifier.rotate(-90f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
items.forEach {
|
||||
DropdownMenuItem(
|
||||
text = { itemContent(it) },
|
||||
onClick = { expanded = false; onSelected(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Locale> {
|
||||
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
|
||||
}
|
||||
return locales.toList()
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package helium314.keyboard.settings.screens
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.inputmethod.InputMethodSubtype
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import helium314.keyboard.latin.R
|
||||
import helium314.keyboard.latin.common.Constants.Separators
|
||||
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
|
||||
import helium314.keyboard.latin.common.LocaleUtils
|
||||
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||
import helium314.keyboard.latin.common.splitOnWhitespace
|
||||
import helium314.keyboard.latin.settings.Defaults
|
||||
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
|
||||
import helium314.keyboard.latin.utils.DictionaryInfoUtils
|
||||
import helium314.keyboard.latin.utils.Log
|
||||
import helium314.keyboard.latin.utils.SettingsSubtype.Companion.toSettingsSubtype
|
||||
import helium314.keyboard.latin.utils.SubtypeSettings
|
||||
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
||||
import helium314.keyboard.latin.utils.displayName
|
||||
import helium314.keyboard.latin.utils.getActivity
|
||||
import helium314.keyboard.latin.utils.locale
|
||||
import helium314.keyboard.latin.utils.prefs
|
||||
import helium314.keyboard.settings.SearchScreen
|
||||
import helium314.keyboard.settings.SettingsActivity
|
||||
import helium314.keyboard.settings.dialogs.SubtypeDialog
|
||||
|
||||
@Composable
|
||||
fun LanguageScreen(
|
||||
onClickBack: () -> Unit,
|
||||
) {
|
||||
val ctx = LocalContext.current
|
||||
var sortedSubtypes by remember { mutableStateOf(getSortedSubtypes(ctx)) }
|
||||
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 selectedSubtype: InputMethodSubtype? by remember { mutableStateOf(null) } // todo: rememberSaveable? maybe with SettingsSubtype?
|
||||
SearchScreen(
|
||||
onClickBack = onClickBack,
|
||||
title = {
|
||||
Column {
|
||||
Text(stringResource(R.string.language_and_layouts_title))
|
||||
Text(stringResource(
|
||||
R.string.text_tap_languages),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
},
|
||||
filteredItems = { term ->
|
||||
// todo: maybe better performance with display name cache?
|
||||
sortedSubtypes.filter {
|
||||
it.displayName(ctx).replace("(", "")
|
||||
.splitOnWhitespace().any { it.startsWith(term, true) }
|
||||
}
|
||||
},
|
||||
itemContent = { item ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { selectedSubtype = item }
|
||||
.padding(vertical = 6.dp, horizontal = 16.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(item.displayName(ctx), style = MaterialTheme.typography.bodyLarge)
|
||||
val description = item.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)?.split(Separators.KV)
|
||||
?.joinToString(", ") { LocaleUtils.getLocaleDisplayNameInSystemLocale(it.constructLocale(), ctx) }
|
||||
if (description != null)
|
||||
Text(
|
||||
text = description,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = item in SubtypeSettings.getEnabledSubtypes(prefs),
|
||||
onCheckedChange = {
|
||||
if (it) SubtypeSettings.addEnabledSubtype(prefs, item)
|
||||
else SubtypeSettings.removeEnabledSubtype(prefs, item)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
if (selectedSubtype != null) {
|
||||
val oldSubtype = selectedSubtype!!
|
||||
SubtypeDialog(
|
||||
onDismissRequest = { selectedSubtype = null },
|
||||
onConfirmed = {
|
||||
// todo: this does not work when "modifying" a resource subtype
|
||||
SubtypeUtilsAdditional.changeAdditionalSubtype(oldSubtype.toSettingsSubtype(), it, prefs)
|
||||
sortedSubtypes = getSortedSubtypes(ctx)
|
||||
},
|
||||
subtype = oldSubtype
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// todo: sorting is slow, need to cache displayName (overall or just in getSortedSubtypes), and then it should be fine
|
||||
private fun getSortedSubtypes(context: Context): List<InputMethodSubtype> {
|
||||
val systemLocales = SubtypeSettings.getSystemLocales()
|
||||
val enabledSubtypes = SubtypeSettings.getEnabledSubtypes(context.prefs(), true)
|
||||
val localesWithDictionary = DictionaryInfoUtils.getCachedDirectoryList(context)?.mapNotNull { dir ->
|
||||
if (!dir.isDirectory)
|
||||
return@mapNotNull null
|
||||
if (dir.list()?.any { it.endsWith(USER_DICTIONARY_SUFFIX) } == true)
|
||||
dir.name.constructLocale()
|
||||
else null
|
||||
}.orEmpty()
|
||||
|
||||
val defaultAdditionalSubtypes = Defaults.PREF_ADDITIONAL_SUBTYPES.split(Separators.SETS).map {
|
||||
it.substringBefore(Separators.SET) to (it.substringAfter(Separators.SET) + ",AsciiCapable,EmojiCapable,isAdditionalSubtype")
|
||||
}
|
||||
fun isDefaultSubtype(subtype: InputMethodSubtype): Boolean =
|
||||
defaultAdditionalSubtypes.any { it.first == subtype.locale().language && it.second == subtype.extraValue }
|
||||
|
||||
val subtypeSortComparator = compareBy<InputMethodSubtype>(
|
||||
{ it !in enabledSubtypes },
|
||||
{ it.locale() !in localesWithDictionary },
|
||||
{ it.locale() !in systemLocales},
|
||||
{ !(SubtypeSettings.isAdditionalSubtype(it) && !isDefaultSubtype(it) ) },
|
||||
{
|
||||
@Suppress("DEPRECATION")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) it.languageTag == "zz"
|
||||
else it.locale == "zz"
|
||||
},
|
||||
{ it.displayName(context) }
|
||||
)
|
||||
return SubtypeSettings.getAllAvailableSubtypes().sortedWith(subtypeSortComparator)
|
||||
}
|
|
@ -23,7 +23,10 @@ import helium314.keyboard.latin.settings.LanguageSettingsFragment
|
|||
import helium314.keyboard.latin.settings.PreferencesSettingsFragment
|
||||
import helium314.keyboard.latin.settings.ToolbarSettingsFragment
|
||||
import helium314.keyboard.latin.utils.JniUtils
|
||||
import helium314.keyboard.latin.utils.SubtypeSettings
|
||||
import helium314.keyboard.latin.utils.displayName
|
||||
import helium314.keyboard.latin.utils.getActivity
|
||||
import helium314.keyboard.latin.utils.prefs
|
||||
import helium314.keyboard.latin.utils.switchTo
|
||||
import helium314.keyboard.settings.preferences.Preference
|
||||
import helium314.keyboard.settings.preferences.PreferenceCategory
|
||||
|
@ -49,9 +52,11 @@ fun MainSettingsScreen(
|
|||
title = stringResource(R.string.ime_settings),
|
||||
settings = emptyList(),
|
||||
) {
|
||||
val enabledSubtypes = SubtypeSettings.getEnabledSubtypes(ctx.prefs(), true)
|
||||
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||
Preference(
|
||||
name = stringResource(R.string.language_and_layouts_title),
|
||||
description = enabledSubtypes.joinToString(", ") { it.displayName(ctx) },
|
||||
onClick = onClickLanguage,
|
||||
icon = R.drawable.ic_settings_languages_foreground
|
||||
) {
|
||||
|
@ -118,7 +123,7 @@ fun MainSettingsScreen(
|
|||
)
|
||||
}
|
||||
Preference(
|
||||
name = stringResource(R.string.keyboard_layout_set),
|
||||
name = stringResource(R.string.settings_screen_secondary_layouts),
|
||||
onClick = onClickLayouts,
|
||||
icon = R.drawable.ic_ime_switcher
|
||||
) {
|
||||
|
|
|
@ -28,20 +28,16 @@ import helium314.keyboard.settings.preferences.Preference
|
|||
fun SecondaryLayoutScreen(
|
||||
onClickBack: () -> Unit,
|
||||
) {
|
||||
// todo: enable main layouts
|
||||
// which layouts to show? all is too much, maybe limit to latin and layouts for enabled locales (and system locales?)
|
||||
// no main layouts in here
|
||||
// could be added later, but need to decide how to do it (showing all main layouts is too much)
|
||||
SearchSettingsScreen(
|
||||
onClickBack = onClickBack,
|
||||
title = stringResource(R.string.keyboard_layout_set),
|
||||
title = stringResource(R.string.settings_screen_secondary_layouts),
|
||||
settings = LayoutType.entries.filter { it != LayoutType.MAIN }.map { Settings.PREF_LAYOUT_PREFIX + it.name }
|
||||
)
|
||||
}
|
||||
|
||||
fun createLayoutSettings(context: Context) = listOf(
|
||||
Setting(context, Settings.PREF_LAYOUT_PREFIX + LayoutType.MAIN, R.string.customize_functional_key_layouts) { // todo: title
|
||||
// todo: actual content
|
||||
},
|
||||
) + LayoutType.entries.filter { it != LayoutType.MAIN }.map { layoutType ->
|
||||
fun createLayoutSettings(context: Context) = LayoutType.entries.filter { it != LayoutType.MAIN }.map { layoutType ->
|
||||
Setting(context, Settings.PREF_LAYOUT_PREFIX + layoutType, layoutType.displayNameId) { setting ->
|
||||
val ctx = LocalContext.current
|
||||
val prefs = ctx.prefs()
|
||||
|
|
|
@ -539,8 +539,12 @@ disposition rather than other common dispositions for Latin languages. [CHAR LIM
|
|||
<string name="customize_symbols_number_layouts">Customize symbols and number layouts</string>
|
||||
<!-- Title for customizing functional key layouts -->
|
||||
<string name="customize_functional_key_layouts">Customize functional key layouts</string>
|
||||
<!-- Settings screen title for secondary layouts (functional keys, symbols, numpad, ...) -->
|
||||
<string name="settings_screen_secondary_layouts">Secondary layouts</string>
|
||||
<!-- Name for functional keys layout -->
|
||||
<string name="layout_functional_keys" tools:keep="@string/layout_functional_keys">Functional keys</string>
|
||||
<!-- Name for functional keys layout for tablets -->
|
||||
<string name="layout_functional_keys_tablet" tools:keep="@string/layout_functional_keys_tablet">Functional keys (large screen)</string>
|
||||
<!-- Name for functional keys layout when showing symbols layout -->
|
||||
<string name="layout_functional_keys_symbols" tools:keep="@string/layout_functional_keys_symbols">Functional keys (Symbols)</string>
|
||||
<!-- Name for functional keys layout when showing more symbols layout -->
|
||||
|
|
13
app/src/test/java/helium314/keyboard/LayoutTest.kt
Normal file
13
app/src/test/java/helium314/keyboard/LayoutTest.kt
Normal file
|
@ -0,0 +1,13 @@
|
|||
package helium314.keyboard
|
||||
|
||||
import helium314.keyboard.latin.utils.LayoutType
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class LayoutTest {
|
||||
// todo: add more
|
||||
@Test fun extraValueToMainLayout() {
|
||||
val extraValue = "KeyboardLayoutSet=MAIN:qwertz+,SupportTouchPositionCorrection"
|
||||
assertEquals("qwertz+", LayoutType.getMainLayoutFromExtraValue(extraValue))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue