HeliBoard/app/src/main/java/helium314/keyboard/settings/screens/LanguageScreen.kt

153 lines
6.9 KiB
Kotlin
Raw Normal View History

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
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?
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) }
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(
checked = item in enabledSubtypes,
2025-02-16 22:58:19 +01:00
onCheckedChange = {
if (it) SubtypeSettings.addEnabledSubtype(prefs, item)
else SubtypeSettings.removeEnabledSubtype(ctx, item)
2025-02-16 22:58:19 +01:00
}
)
}
}
)
if (selectedSubtype != null) {
val oldSubtype = selectedSubtype!!
SubtypeDialog(
onDismissRequest = {
selectedSubtype = null
2025-02-23 19:16:39 +01:00
sortedSubtypes = getSortedSubtypes(ctx)
},
2025-02-16 22:58:19 +01:00
onConfirmed = {
SubtypeUtilsAdditional.changeAdditionalSubtype(oldSubtype.toSettingsSubtype(), it, ctx)
2025-02-16 22:58:19 +01:00
},
subtype = oldSubtype
)
}
}
// 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")
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)
}