Move layout-language mapping to mapping.yaml, update AddLanguage screen

This commit is contained in:
Aleksandras Kostarevas 2024-09-19 12:21:09 +03:00
parent c1d0787395
commit 6bcc162f1e
10 changed files with 725 additions and 183 deletions

View File

@ -1,5 +1,5 @@
name: Serbian QWERTZ
languages: sr-ZZ
languages: sr-Latn
rows:
- letters: q w e r t z u i o p š
- letters: a s d f g h j k l č ć

View File

@ -1,4 +1,4 @@
name: Русский
name: East Slavic
languages: ru be bg bn kk ky uk
rows:
- letters: й ц у к е н г ш щ з х

View File

@ -0,0 +1,521 @@
languages:
af:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ar:
- arabic
- lulua
az_AZ:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
be_BY:
- east_slavic
- russian_student
- russian_yavert
- russian_yazhert
bg:
- bulgarian
- bulgarian_bds
bn_BD:
- bengali_akkhor
bn_IN:
- bengali
ca:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ckb:
- kurdish
cs:
- qwertz
- qwerty
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
da:
- nordic
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
de:
- german
- qwertz
- swiss
- qwerty
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
de_CH:
- swiss
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
el:
- greek
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
en_GB:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
en_IN:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
en_US:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
eo:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
es:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
es_419:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
es_US:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
et_EE:
- nordic
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
eu_ES:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
fa:
- farsi
fi:
- nordic
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
fr:
- azerty
- swiss
- qwerty
- qwertz
- dvorak
- colemak
- bepo
- pcqwerty
- nordic
fr_CA:
- qwerty
- swiss
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
fr_CH:
- swiss
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
gl_ES:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
hi:
- hindi
- hindi_compact
hi_Latn:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
hr:
- qwertz
- qwerty
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
hu:
- qwertz
- qwerty
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
hy_AM:
- armenian_phonetic
in:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
is:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
it:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
it_CH:
- swiss
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
iw:
- hebrew
ka_GE:
- georgian
kk:
- east_slavic
- russian_student
- russian_yavert
- russian_yazhert
km_KH:
- khmer
kn_IN:
- kannada
ky:
- east_slavic
- russian_student
- russian_yavert
- russian_yazhert
lo_LA:
- lao
lt:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
lv:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
mk:
- south_slavic
ml_IN:
- malayalam
mn_MN:
- mongolian
mr_IN:
- marathi
ms_MY:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
nb:
- nordic
ne_NP:
- nepali_romanized
- nepali_traditional
nl:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
nl_BE:
- azerty
- qwerty
- qwertz
- dvorak
- colemak
- bepo
- pcqwerty
- nordic
pl:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
pt_BR:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
pt_PT:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ro:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ru:
- east_slavic
- russian_student
- russian_yavert
- russian_yazhert
si_LK:
- sinhala
sk:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
sl:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
sr:
- south_slavic
sr_Latn:
- serbian_qwertz
sv:
- nordic
sw:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ta_IN:
- tamil
ta_LK:
- tamil
ta_SG:
- tamil
te_IN:
- telugu
th:
- thai
tl:
- spanish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
tr:
- turkish
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
uk:
- east_slavic
- russian_student
- russian_yavert
- russian_yazhert
uz_UZ:
- uzbek
vi:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
zu:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
zz:
- qwerty
- qwertz
- dvorak
- azerty
- colemak
- bepo
- pcqwerty
- nordic
ipa:
- ipa

View File

@ -43,10 +43,10 @@ import org.futo.inputmethod.latin.uix.setSettingBlocking
import org.futo.inputmethod.latin.uix.settings.NavigationItem
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
import org.futo.inputmethod.latin.uix.settings.SettingsActivity
import org.futo.inputmethod.latin.uix.settings.pages.LocaleLayoutMap
import org.futo.inputmethod.latin.uix.settings.useDataStoreValue
import org.futo.inputmethod.latin.uix.theme.Typography
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
import org.futo.inputmethod.v2keyboard.LayoutManager
import java.util.Locale
import kotlin.math.sign
@ -110,7 +110,7 @@ object Subtypes {
var numAdded = 0
for(i in 0 until locales.size()) {
val locale = locales.get(i).stripExtensionsIfNeeded()
val layout = findClosestLocaleLayouts(locale).firstOrNull() ?: continue
val layout = findClosestLocaleLayouts(context, locale).firstOrNull() ?: continue
addLanguage(context, locale, layout)
numAdded += 1
@ -124,10 +124,8 @@ object Subtypes {
context.setSettingBlocking(ActiveSubtype.key, context.getSettingBlocking(SubtypesSetting).firstOrNull() ?: return)
}
fun findClosestLocaleLayouts(locale: Locale): List<String> {
val supportedLocales = LocaleLayoutMap.toList().associate {
getLocale(it.first) to it.second
}
fun findClosestLocaleLayouts(context: Context, locale: Locale): List<String> {
val supportedLocales = LayoutManager.getLayoutMapping(context)
val perfectMatch = supportedLocales.keys.find { it.language == locale.language && it.country == locale.country }
val languageMatch = supportedLocales.keys.find { it.language == locale.language }
@ -242,7 +240,7 @@ object Subtypes {
for(i in 0 until locales.size()) {
val locale = locales.get(i).stripExtensionsIfNeeded()
val layout = findClosestLocaleLayouts(locale).firstOrNull() ?: continue
val layout = findClosestLocaleLayouts(context, locale).firstOrNull() ?: continue
val value = subtypeToString(
InputMethodSubtypeBuilder()

View File

@ -67,22 +67,17 @@ fun KeyboardViewCompose(keyboard: Keyboard?, width: Dp) {
}
@Composable
fun KeyboardLayoutPreview(id: String, width: Dp = 172.dp) {
fun KeyboardLayoutPreview(id: String, width: Dp = 172.dp, locale: Locale? = null) {
val context = LocalContext.current
val locale = remember(id) {
LayoutManager.getLayout(context, id).languages.firstOrNull()?.let {
val l = Locale.forLanguageTag(it)
println("SET LOCALE: $it to $l, ${l.language}, ${l.country}")
l
val loc = remember(id) {
locale ?: LayoutManager.getLayout(context, id).languages.firstOrNull()?.let {
Locale.forLanguageTag(it)
}
}
val configuration = LocalConfiguration.current
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val isLandscape = false//configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val widthPx: Int
val heightPx: Int
@ -116,7 +111,7 @@ fun KeyboardLayoutPreview(id: String, width: Dp = 172.dp) {
height = heightPx,
gap = 4.0f,
keyboardLayoutSet = id,
locale = locale ?: Locale.ENGLISH,
locale = loc ?: Locale.ENGLISH,
editorInfo = editorInfo,
numberRow = numberRow,
useSplitLayout = isLandscape,

View File

@ -130,19 +130,15 @@ private fun levenshteinDistance(lhs: CharSequence, rhs: CharSequence): Int {
return cost[lhsLen]
}
private fun <T> List<T>.search(searchTarget: String, keyFunction: (T) -> String): List<T> {
val maxDistance = searchTarget.length * 2 / 3
fun <T> List<T>.searchMultiple(searchTarget: String, maxDistance: Int = searchTarget.length * 2 / 3, limitLength: Boolean = false, keyFunction: (T) -> List<String>): List<T> {
return this.mapNotNull { item ->
val key = keyFunction(item)
val distance = levenshteinDistance(searchTarget, key)
if (distance <= maxDistance) Pair(item, distance) else null
}.sortedBy { it.second }.map { it.first }
}
private fun <T> List<T>.searchMultiple(searchTarget: String, keyFunction: (T) -> List<String>): List<T> {
val maxDistance = searchTarget.length * 2 / 3
return this.mapNotNull { item ->
val keys = keyFunction(item)
val keys = keyFunction(item).let {
if(limitLength) {
it.map { it.substring(0 until searchTarget.length.coerceAtMost(it.length)) }
} else {
it
}
}
val minDistanceKey = keys.minByOrNull { levenshteinDistance(searchTarget, it) }
val minDistance = minDistanceKey?.let { levenshteinDistance(searchTarget, it) }
if (minDistance != null && minDistance <= maxDistance) Pair(item, minDistance) else null

View File

@ -12,7 +12,6 @@ import androidx.navigation.compose.rememberNavController
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.uix.ErrorDialog
import org.futo.inputmethod.latin.uix.InfoDialog
import org.futo.inputmethod.latin.uix.settings.pages.AddLanguageScreen
import org.futo.inputmethod.latin.uix.settings.pages.AdvancedParametersScreen
import org.futo.inputmethod.latin.uix.settings.pages.BlacklistScreen
import org.futo.inputmethod.latin.uix.settings.pages.CreditsScreen
@ -25,6 +24,8 @@ import org.futo.inputmethod.latin.uix.settings.pages.LanguagesScreen
import org.futo.inputmethod.latin.uix.settings.pages.PaymentScreen
import org.futo.inputmethod.latin.uix.settings.pages.PaymentThankYouScreen
import org.futo.inputmethod.latin.uix.settings.pages.PredictiveTextScreen
import org.futo.inputmethod.latin.uix.settings.pages.SelectLanguageScreen
import org.futo.inputmethod.latin.uix.settings.pages.SelectLayoutsScreen
import org.futo.inputmethod.latin.uix.settings.pages.ThemeScreen
import org.futo.inputmethod.latin.uix.settings.pages.VoiceInputScreen
import org.futo.inputmethod.latin.uix.settings.pages.addModelManagerNavigation
@ -53,8 +54,8 @@ fun SettingsNavigator(
) {
composable("home") { HomeScreen(navController) }
composable("languages") { LanguagesScreen(navController) }
composable("addLanguage") { AddLanguageScreen(navController) }
composable("addLayout/{lang}") { AddLanguageScreen(navController, it.arguments?.getString("lang")?.urlDecode()) }
composable("addLanguage") { SelectLanguageScreen(navController) }
composable("addLayout/{lang}") { SelectLayoutsScreen(navController, it.arguments?.getString("lang")?.urlDecode() ?: "") }
composable("predictiveText") { PredictiveTextScreen(navController) }
composable("advancedparams") { AdvancedParametersScreen(navController) }
addTypingNavigation(navController)
@ -87,8 +88,4 @@ fun SettingsNavigator(
}
addModelManagerNavigation(navController)
}
LaunchedEffect(Unit) {
navController.navigate("devlayouts")
}
}

View File

@ -1,173 +1,184 @@
package org.futo.inputmethod.latin.uix.settings.pages
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.PlatformImeOptions
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import org.futo.inputmethod.latin.Subtypes
import org.futo.inputmethod.latin.stripExtensionsIfNeeded
import org.futo.inputmethod.latin.uix.settings.DropDownPicker
import org.futo.inputmethod.latin.uix.KeyboardLayoutPreview
import org.futo.inputmethod.latin.uix.actions.searchMultiple
import org.futo.inputmethod.latin.uix.settings.NavigationItem
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
import org.futo.inputmethod.latin.uix.settings.ScrollableList
import org.futo.inputmethod.latin.uix.settings.SettingItem
import org.futo.inputmethod.latin.uix.urlEncode
import org.futo.inputmethod.v2keyboard.LayoutManager
import java.text.Normalizer
import java.util.Locale
val QwertyVariants = listOf("qwerty", "qwertz", "dvorak", "azerty", "colemak", "bepo", "pcqwerty", "nordic")
fun makeQwertyWithPrimary(primary: String): List<String> {
return listOf(primary) + QwertyVariants.filter { it != primary }
private val alphaRegex = Regex("[^a-zA-Z\\s]")
fun normalize(str: String): String {
return Normalizer.normalize(str, Normalizer.Form.NFD)
.replace(alphaRegex, "")
}
fun makeQwertyWithPrimary(primary: String, secondary: String): List<String> {
return listOf(primary, secondary) + QwertyVariants.filter { it != primary && it != secondary }
}
val LocaleLayoutMap = mapOf(
"af" to QwertyVariants,
"ar" to listOf("arabic"),
"az_AZ" to QwertyVariants,
"be_BY" to listOf("east_slavic", "east_slavic_phonetic"),
"bg" to listOf("bulgarian", "bulgarian_bds"),
"bn_BD" to listOf("bengali_akkhor"),
"bn_IN" to listOf("bengali"),
"ca" to makeQwertyWithPrimary("spanish"),
"cs" to makeQwertyWithPrimary("qwertz"),
"da" to makeQwertyWithPrimary("nordic"),
"de" to makeQwertyWithPrimary("qwertz"),
"de_CH" to makeQwertyWithPrimary("swiss"),
"el" to makeQwertyWithPrimary("greek"),
"en_IN" to QwertyVariants,
"en_US" to QwertyVariants,
"en_GB" to QwertyVariants,
"eo" to makeQwertyWithPrimary("spanish"),
"es" to makeQwertyWithPrimary("spanish"),
"es_US" to makeQwertyWithPrimary("spanish"),
"es_419" to makeQwertyWithPrimary("spanish"),
"et_EE" to makeQwertyWithPrimary("nordic"),
"eu_ES" to makeQwertyWithPrimary("spanish"),
"fa" to listOf("farsi"),
"ckb" to listOf("kurdish"),
"fi" to makeQwertyWithPrimary("nordic"),
"fr" to makeQwertyWithPrimary("azerty", "swiss"),
"fr_CA" to makeQwertyWithPrimary("qwerty", "swiss"),
"fr_CH" to makeQwertyWithPrimary("swiss"),
"gl_ES" to makeQwertyWithPrimary("spanish"),
"hi" to listOf("hindi", "hindi_compact"),
//"hi_ZZ" to QwertyVariants,
"hr" to makeQwertyWithPrimary("qwertz"),
"hu" to makeQwertyWithPrimary("qwertz"),
"hy_AM" to listOf("armenian_phonetic"),
"in" to QwertyVariants,
"is" to QwertyVariants,
"it" to QwertyVariants,
"it_CH" to makeQwertyWithPrimary("swiss"),
"iw" to listOf("hebrew"),
"ka_GE" to listOf("georgian"),
"kk" to listOf("east_slavic", "east_slavic_phonetic"),
"km_KH" to listOf("khmer"),
"kn_IN" to listOf("kannada"),
"ky" to listOf("east_slavic", "east_slavic_phonetic"),
"lo_LA" to listOf("lao"),
"lt" to QwertyVariants,
"lv" to QwertyVariants,
"mk" to listOf("south_slavic"),
"ml_IN" to listOf("malayalam"),
"mn_MN" to listOf("mongolian"),
"mr_IN" to listOf("marathi"),
"ms_MY" to QwertyVariants,
"nb" to listOf("nordic"),
"ne_NP" to listOf("nepali_romanized", "nepali_traditional"),
"nl" to QwertyVariants,
"nl_BE" to makeQwertyWithPrimary("azerty"),
"pl" to QwertyVariants,
"pt_BR" to QwertyVariants,
"pt_PT" to QwertyVariants,
"ro" to QwertyVariants,
"ru" to listOf("east_slavic", "east_slavic_phonetic"),
"si_LK" to listOf("sinhala"),
"sk" to QwertyVariants,
"sl" to QwertyVariants,
"sr" to listOf("south_slavic"),
"sr_ZZ" to listOf("serbian_qwertz"),
"sv" to listOf("nordic"),
"sw" to QwertyVariants,
"ta_IN" to listOf("tamil"),
"ta_LK" to listOf("tamil"),
"ta_SG" to listOf("tamil"),
"te_IN" to listOf("telugu"),
"th" to listOf("thai"),
"tl" to makeQwertyWithPrimary("spanish"),
"tr" to makeQwertyWithPrimary("turkish"),
"uk" to listOf("east_slavic", "east_slavic_phonetic"),
"uz_UZ" to listOf("uzbek"),
"vi" to QwertyVariants,
"zu" to QwertyVariants,
"zz" to QwertyVariants,
)
@Preview
@Composable
fun AddLanguageScreen(navController: NavHostController = rememberNavController(), defaultLocale: String? = null) {
fun SelectLanguageScreen(navController: NavHostController = rememberNavController()) {
val context = LocalContext.current
val defaultLocaleVal = defaultLocale ?: context.resources.configuration.locale.stripExtensionsIfNeeded().toString()
val defaultLayout = Subtypes.findClosestLocaleLayouts(Subtypes.getLocale(defaultLocaleVal)).firstOrNull() ?: "qwerty"
val layoutMapping = remember { LayoutManager.getLayoutMapping(context) }
val selectedLocale: MutableState<String> = remember { mutableStateOf(defaultLocale ?: context.resources.configuration.locale.stripExtensionsIfNeeded().toString()) }
val selectedLayout: MutableState<String> = remember { mutableStateOf(defaultLayout) }
val systemLocale = remember { context.resources.configuration.locales[0] }
val textFieldValue = remember { mutableStateOf(TextFieldValue("")) }
val locales = remember {
layoutMapping.keys.toList().sortedBy {
it.getDisplayName(systemLocale)
}
}
val searchKeys = if(textFieldValue.value.text.isEmpty()) {
locales
} else {
locales.searchMultiple(textFieldValue.value.text.lowercase(), limitLength = true, maxDistance = Int.MAX_VALUE) {
listOf(
it.language, it.getDisplayName(systemLocale), it.getDisplayName(it)
).map { normalize(it.lowercase()) }.flatMap { it.split(" ") }.filter { it.isNotBlank() }
}
}
LazyColumn {
item {
ScreenTitle("Select language to add", showBack = true, navController)
}
item {
Surface(color = MaterialTheme.colorScheme.surfaceContainerHighest, shape = RoundedCornerShape(8.dp), modifier = Modifier.padding(8.dp).height(48.dp).fillMaxWidth()) {
Row(modifier = Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Search, contentDescription = "Search")
Spacer(modifier = Modifier.width(8.dp))
BasicTextField(
value = textFieldValue.value,
onValueChange = { textFieldValue.value = it },
keyboardOptions = KeyboardOptions.Default.copy(
platformImeOptions = PlatformImeOptions(
privateImeOptions = "org.futo.inputmethod.latin.NoSuggestions=1,org.futo.inputmethod.latin.ForceLayout=qwerty,org.futo.inputmethod.latin.ForceLocale=zz"
)
),
modifier = Modifier.weight(1.0f),
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
textStyle = TextStyle.Default.copy(color = MaterialTheme.colorScheme.onSurface)
)
}
}
}
items(searchKeys) {
NavigationItem(
title = it.getDisplayName(systemLocale),
subtitle = it.getDisplayName(it),
style = NavigationItemStyle.MiscNoArrow,
navigate = {
navController.navigate("addLayout/" + it.toLanguageTag().urlEncode())
}
)
}
}
}
@Composable
fun LayoutPreview(name: String, locale: Locale, onClick: () -> Unit) {
val context = LocalContext.current
val layoutName = remember { LayoutManager.getLayout(context, name).name }
Box(
Modifier.padding(4.dp).fillMaxWidth().border(
1.dp,
MaterialTheme.colorScheme.outlineVariant,
RoundedCornerShape(8.dp)
).clickable { onClick() }) {
Column(
modifier = Modifier.fillMaxWidth().padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
KeyboardLayoutPreview(id = name, width = 172.dp, locale = locale)
Text(
layoutName,
style = TextSmallStyle,
modifier = Modifier.padding(4.dp),
textAlign = TextAlign.Center
)
}
}
}
@Preview
@Composable
fun SelectLayoutsScreen(navController: NavHostController = rememberNavController(), language: String = "en_US") {
val context = LocalContext.current
val locale = remember { Locale.forLanguageTag(language.replace("_", "-")) }
val layoutMapping = remember { LayoutManager.getLayoutMapping(context) }
val systemLocale = remember { context.resources.configuration.locales[0] }
val relevantLayouts = remember {
layoutMapping.entries.filter {
it.key.language == locale.language
}.flatMap { it.value }.toSet()
}
val keys = remember { LocaleLayoutMap.keys.toList() }
ScrollableList {
ScreenTitle("Add Language", showBack = true, navController)
ScreenTitle(locale.getDisplayName(locale), showBack = true, navController)
SettingItem(title = "Language") {
DropDownPicker(
"",
keys,
selectedLocale.value,
{
selectedLocale.value = it
selectedLayout.value = LocaleLayoutMap[it]!!.first()
},
{
Subtypes.getNameForLocale(it)
},
modifier = Modifier.width(180.dp)
)
}
ScreenTitle("Select a layout to add")
SettingItem(title = "Layout") {
DropDownPicker(
"",
LocaleLayoutMap[selectedLocale.value] ?: listOf(),
selectedLayout.value,
{ selectedLayout.value = it },
{ Subtypes.getLayoutName(context, it) },
modifier = Modifier.width(180.dp)
)
}
relevantLayouts.forEach {
LayoutPreview(it, locale) {
Subtypes.addLanguage(context, locale, it)
Button(onClick = {
Subtypes.addLanguage(
context,
Subtypes.getLocale(selectedLocale.value),
selectedLayout.value
)
navController.navigateUp()
}, modifier = Modifier.fillMaxWidth().padding(16.dp)) {
Text("Add")
// Go back to languages
for(x in 0 until 3) navController.navigateUp()
navController.navigate("languages")
}
}
}
}

View File

@ -6,13 +6,20 @@ import android.util.Log
import com.charleskorn.kaml.PolymorphismStyle
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.EmptySerializersModule
import org.futo.inputmethod.latin.uix.actions.BugInfo
import org.futo.inputmethod.latin.uix.actions.BugViewerState
import java.util.Locale
@Serializable
data class Mappings(
val languages: Map<String, List<String>>
)
object LayoutManager {
private var layoutsById: Map<String, Keyboard>? = null
private var localeToLayoutsMappings: Map<Locale, List<String>>? = null
private var initialized = false
private fun listFilesRecursively(assetManager: AssetManager, path: String): List<String> {
@ -26,7 +33,7 @@ object LayoutManager {
private fun getAllLayoutPaths(assetManager: AssetManager): List<String> {
return listFilesRecursively(assetManager, "layouts").filter {
it.endsWith(".yml") || it.endsWith(".yaml")
(it.endsWith(".yml") || it.endsWith(".yaml")) && it != "mapping.yaml"
}
}
@ -35,6 +42,10 @@ object LayoutManager {
initialized = true
localeToLayoutsMappings = parseMappings(context, "layouts/mapping.yaml").languages.mapKeys {
Locale.forLanguageTag(it.key.replace("_", "-"))
}
val assetManager = context.assets
val layoutPaths = getAllLayoutPaths(assetManager)
@ -65,10 +76,10 @@ object LayoutManager {
return layoutsById?.get(name) ?: throw IllegalArgumentException("Failed to find keyboard layout $name. Available layouts: ${layoutsById?.keys}")
}
fun queryLayoutsForLocale(locale: Locale): List<Keyboard> {
val language = locale.language
//val script = locale.getKeyboardScript()
return layoutsById!!.values.filter { it.languages.contains(language) }
fun getLayoutMapping(context: Context): Map<Locale, List<String>> {
init(context)
return localeToLayoutsMappings!!
}
fun getAllLayoutNames(context: Context): List<String> {
@ -80,6 +91,20 @@ object LayoutManager {
}
}
private fun parseMappings(context: Context, mappingsPath: String): Mappings {
val yaml = Yaml(
EmptySerializersModule(),
YamlConfiguration(
polymorphismStyle = PolymorphismStyle.Property,
allowAnchorsAndAliases = true
)
)
return context.assets.open(mappingsPath).use { inputStream ->
val yamlString = inputStream.bufferedReader().use { it.readText() }
yaml.decodeFromString(Mappings.serializer(), yamlString)
}
}
private fun parseKeyboardYaml(context: Context, layoutPath: String): Keyboard {
val yaml = Yaml(

View File

@ -1,6 +1,5 @@
package org.futo.inputmethod.v2keyboard
import org.futo.inputmethod.keyboard.internal.KeyboardLayoutKind
import org.futo.inputmethod.latin.common.Constants
fun getDefaultMoreKeysForKey(code: Int, relevantSpecShortcut: List<String>?): String {