2025-02-16 22:58:19 +01:00
|
|
|
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.constructLocale
|
2025-02-23 13:41:30 +01:00
|
|
|
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
|
2025-02-16 22:58:19 +01:00
|
|
|
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
|
2025-02-19 23:06:52 +01:00
|
|
|
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
|
2025-02-16 22:58:19 +01:00
|
|
|
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?
|
2025-02-22 12:21:26 +01:00
|
|
|
val enabledSubtypes = SubtypeSettings.getEnabledSubtypes(prefs)
|
2025-02-16 22:58:19 +01:00
|
|
|
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 ->
|
|
|
|
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)
|
2025-02-23 13:41:30 +01:00
|
|
|
?.joinToString(", ") { it.constructLocale().localizedDisplayName(ctx) }
|
2025-02-19 23:00:58 +01:00
|
|
|
if (description != null) // todo: description should clarify when it's a default subtype that can't be changed / will be cloned
|
2025-02-16 22:58:19 +01:00
|
|
|
Text(
|
|
|
|
text = description,
|
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Switch(
|
2025-02-22 12:21:26 +01:00
|
|
|
checked = item in enabledSubtypes,
|
2025-02-16 22:58:19 +01:00
|
|
|
onCheckedChange = {
|
|
|
|
if (it) SubtypeSettings.addEnabledSubtype(prefs, item)
|
2025-02-19 23:00:58 +01:00
|
|
|
else SubtypeSettings.removeEnabledSubtype(ctx, item)
|
2025-02-16 22:58:19 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
if (selectedSubtype != null) {
|
|
|
|
val oldSubtype = selectedSubtype!!
|
|
|
|
SubtypeDialog(
|
2025-02-22 12:21:26 +01:00
|
|
|
onDismissRequest = {
|
|
|
|
selectedSubtype = null
|
2025-02-23 19:16:39 +01:00
|
|
|
sortedSubtypes = getSortedSubtypes(ctx)
|
2025-02-22 12:21:26 +01:00
|
|
|
},
|
2025-02-16 22:58:19 +01:00
|
|
|
onConfirmed = {
|
2025-02-19 23:00:58 +01:00
|
|
|
SubtypeUtilsAdditional.changeAdditionalSubtype(oldSubtype.toSettingsSubtype(), it, ctx)
|
2025-02-16 22:58:19 +01:00
|
|
|
},
|
|
|
|
subtype = oldSubtype
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-17 19:32:02 +01:00
|
|
|
// sorting by display name is still slow, even with the cache... but probably good enough
|
2025-02-16 22:58:19 +01:00
|
|
|
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")
|
2025-02-19 23:06:52 +01:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) it.languageTag == SubtypeLocaleUtils.NO_LANGUAGE
|
|
|
|
else it.locale == SubtypeLocaleUtils.NO_LANGUAGE
|
2025-02-16 22:58:19 +01:00
|
|
|
},
|
|
|
|
{ it.displayName(context) }
|
|
|
|
)
|
|
|
|
return SubtypeSettings.getAllAvailableSubtypes().sortedWith(subtypeSortComparator)
|
|
|
|
}
|