solve a bunch of recent todos

This commit is contained in:
Helium314 2025-02-23 13:41:30 +01:00
parent 86f15e11d8
commit ff27d1f1c5
13 changed files with 95 additions and 70 deletions

View file

@ -369,7 +369,7 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
colorsString.split(";").forEach {
val ct = try {
ColorType.valueOf(it.substringBefore(",").uppercase())
} catch (_: Exception) { // todo: which one?
} catch (_: IllegalArgumentException) {
return@forEach
}
val i = it.substringAfter(",").toIntOrNull() ?: return@forEach

View file

@ -186,7 +186,6 @@ object LocaleUtils {
return getLocaleDisplayNameInLocale(locale, context.resources, context.resources.configuration.locale())
}
// todo: use this instead of getLocaleDisplayNameInSystemLocale in .kt files
fun Locale.localizedDisplayName(context: Context) =
getLocaleDisplayNameInLocale(this, context.resources, context.resources.configuration.locale())

View file

@ -25,7 +25,7 @@ enum class LayoutType {
val LayoutType.folder get() = "layouts${File.separator}${name.lowercase()}${File.separator}"
val LayoutType.displayNameId get() = when (this) {
MAIN -> TODO()
MAIN -> R.string.subtype_no_language
SYMBOLS -> R.string.layout_symbols
MORE_SYMBOLS -> R.string.layout_symbols_shifted
FUNCTIONAL -> R.string.layout_functional_keys

View file

@ -102,7 +102,6 @@ object SubtypeSettings {
prefs.edit { putString(Settings.PREF_SELECTED_SUBTYPE, subtypeString) }
}
// todo: use this or the version in SubtypeUtilsAdditional?
fun isAdditionalSubtype(subtype: InputMethodSubtype): Boolean = subtype in additionalSubtypes
fun getAdditionalSubtypes(): List<InputMethodSubtype> = additionalSubtypes.toList()

View file

@ -9,8 +9,8 @@ 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.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET
import helium314.keyboard.latin.common.LocaleUtils
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.define.DebugFlags
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
@ -72,7 +72,7 @@ fun getResourceSubtypes(resources: Resources): List<InputMethodSubtype> {
fun InputMethodSubtype.displayName(context: Context): String {
val layoutName = SubtypeLocaleUtils.getMainLayoutName(this)
if (LayoutUtilsCustom.isCustomLayout(layoutName))
return "${LocaleUtils.getLocaleDisplayNameInSystemLocale(locale(), context)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
return "${locale().localizedDisplayName(context)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
return SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(this)
}

View file

@ -7,12 +7,10 @@ import android.net.Uri
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import android.widget.RelativeLayout
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
@ -28,6 +26,7 @@ import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ExecutorUtils
import helium314.keyboard.latin.utils.cleanUnusedMainDicts
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.dialogs.ConfirmationDialog
import helium314.keyboard.settings.dialogs.NewDictionaryDialog
import kotlinx.coroutines.flow.MutableStateFlow
import java.io.BufferedOutputStream
@ -48,6 +47,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
val prefChanged = MutableStateFlow(0) // simple counter, as the only relevant information is that something changed
private val dictUriFlow = MutableStateFlow<Uri?>(null)
private val cachedDictionaryFile by lazy { File(this.cacheDir.path + File.separator + "temp_dict") }
private val crashReportFiles = MutableStateFlow<List<File>>(emptyList())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -57,7 +57,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
}
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { cleanUnusedMainDicts(this) }
if (BuildConfig.DEBUG || DebugFlags.DEBUG_ENABLED)
askAboutCrashReports()
crashReportFiles.value = findCrashReports()
// with this the layout edit dialog is not covered by the keyboard
// alternative of Modifier.imePadding() and properties = DialogProperties(decorFitsSystemWindows = false) has other weird side effects
@ -79,6 +79,8 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
Theme {
Surface {
val dictUri by dictUriFlow.collectAsState()
val crashReports by crashReportFiles.collectAsState()
val crashFilePicker = filePicker { saveCrashReports(it) }
if (spellchecker)
Column { // lazy way of implementing spell checker settings
settingsContainer[Settings.PREF_USE_CONTACTS]!!.Preference()
@ -100,6 +102,23 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
mainLocale = null
)
}
if (crashReports.isNotEmpty()) {
ConfirmationDialog(
cancelButtonText = "ignore",
onDismissRequest = { crashReportFiles.value = emptyList() },
neutralButtonText = "delete",
onNeutral = { crashReports.forEach { it.delete() }; crashReportFiles.value = emptyList() },
confirmButtonText = "get",
onConfirmed = {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.putExtra(Intent.EXTRA_TITLE, "crash_reports.zip")
intent.setType("application/zip")
crashFilePicker.launch(intent)
},
text = { Text("Crash report files found") },
)
}
}
}
}
@ -149,47 +168,21 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
forceOppositeTheme = opposite
}
// todo: crash report stuff just just taken from old SettingsFragment and kotlinized
// it should be updated to use compose, and maybe move to MainSettingsScreen
private val crashReportFiles = mutableListOf<File>()
private fun askAboutCrashReports() {
private fun findCrashReports(): List<File> {
// find crash report files
val dir: File = getExternalFilesDir(null) ?: return
val allFiles = dir.listFiles() ?: return
crashReportFiles.clear()
for (file in allFiles) {
if (file.name.startsWith("crash_report")) crashReportFiles.add(file)
}
if (crashReportFiles.isEmpty()) return
AlertDialog.Builder(this)
.setMessage("Crash report files found")
.setPositiveButton("get") { _, _ ->
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.putExtra(Intent.EXTRA_TITLE, "crash_reports.zip")
intent.setType("application/zip")
crashReportFilePicker.launch(intent)
}
.setNeutralButton("delete") { _, _ ->
for (file in crashReportFiles) {
file.delete() // don't care whether it fails, though user will complain
}
}
.setNegativeButton("ignore", null)
.show()
val dir: File = getExternalFilesDir(null) ?: return emptyList()
val allFiles = dir.listFiles() ?: return emptyList()
return allFiles.filter { it.name.startsWith("crash_report") }
}
private val crashReportFilePicker: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode != RESULT_OK || it.data == null) return@registerForActivityResult
val uri = it.data!!.data
if (uri != null) ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { saveCrashReport(uri) }
}
private fun saveCrashReport(uri: Uri?) {
if (uri == null || crashReportFiles.isEmpty()) return
private fun saveCrashReports(uri: Uri) {
val files = findCrashReports()
if (files.isEmpty()) return
try {
contentResolver.openOutputStream(uri)?.use {
val bos = BufferedOutputStream(it)
val z = ZipOutputStream(bos)
for (file in crashReportFiles) {
for (file in files) {
val f = FileInputStream(file)
z.putNextEntry(ZipEntry(file.name))
FileUtils.copyStreamToOtherStream(f, z)
@ -198,10 +191,9 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
}
z.close()
bos.close()
for (file in crashReportFiles) {
for (file in files) {
file.delete()
}
crashReportFiles.clear()
}
} catch (ignored: IOException) {
}

View file

@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
import helium314.keyboard.compat.locale
import helium314.keyboard.latin.Dictionary
import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.LocaleUtils
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.utils.DictionaryInfoUtils
import helium314.keyboard.settings.dictionaryFilePicker
import helium314.keyboard.settings.screens.getUserAndInternalDictionaries
@ -44,7 +44,7 @@ fun DictionaryDialog(
onConfirmed = {},
confirmButtonText = null,
cancelButtonText = stringResource(R.string.dialog_close),
title = { Text(LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, ctx)) },
title = { Text(locale.localizedDisplayName(ctx)) },
text = {
Column {
if (hasInternal) {

View file

@ -34,14 +34,17 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
import helium314.keyboard.latin.settings.Defaults.default
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.LayoutType
import helium314.keyboard.latin.utils.LayoutUtils
import helium314.keyboard.latin.utils.LayoutUtilsCustom
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.mainLayoutName
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.SettingsActivity
@ -190,16 +193,22 @@ private fun LayoutItemRow(
IconButton(
onClick = { showDeleteDialog = true }
) { Icon(painterResource(R.drawable.ic_bin), null) }
if (showDeleteDialog)
if (showDeleteDialog) {
val inUse = SubtypeSettings.getAdditionalSubtypes().any { st ->
val map = LayoutType.getLayoutMap(st.getExtraValueOf(ExtraValue.KEYBOARD_LAYOUT_SET))
map[layoutType] == layoutName
}
ConfirmationDialog(
onDismissRequest = { showDeleteDialog = false },
text = { Text(stringResource(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(layoutName))) },
title = { Text(stringResource(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(layoutName))) },
text = { if (inUse) Text(stringResource(R.string.layout_in_use)) },
confirmButtonText = stringResource(R.string.delete),
onConfirmed = {
showDeleteDialog = false
onDelete(layoutName)
}
)
}
}
IconButton(
onClick = { onClickEdit(layoutName to (if (isCustom) null else LayoutUtils.getContent(layoutType, layoutName, ctx))) }

View file

@ -2,6 +2,8 @@ package helium314.keyboard.settings.dialogs
import android.content.Intent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -9,20 +11,24 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.compat.locale
import helium314.keyboard.dictionarypack.DictionaryPackConstants
import helium314.keyboard.latin.Dictionary
import helium314.keyboard.latin.R
import helium314.keyboard.latin.ReadOnlyBinaryDictionary
import helium314.keyboard.latin.common.LocaleUtils
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.makedict.DictionaryHeader
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
import helium314.keyboard.latin.utils.DictionaryInfoUtils
import helium314.keyboard.latin.utils.ScriptUtils.script
import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.locale
import helium314.keyboard.latin.utils.prefs
import java.io.File
import java.util.Locale
@ -40,17 +46,20 @@ fun NewDictionaryDialog(
val ctx = LocalContext.current
val dictLocale = header.mLocaleString.constructLocale()
var locale by remember { mutableStateOf(mainLocale ?: dictLocale) }
val comparer = compareBy<Locale>({ it != mainLocale}, { it != dictLocale }, { it.script() != dictLocale.script() })
val enabledLanguages = SubtypeSettings.getEnabledSubtypes(ctx.prefs()).map { it.locale().language }
val comparer = compareBy<Locale>({ it != mainLocale }, { it != dictLocale }, { it.language !in enabledLanguages }, { it.script() != dictLocale.script() })
val locales = SubtypeSettings.getAvailableSubtypeLocales().sortedWith(comparer)
val cacheDir = DictionaryInfoUtils.getCacheDirectoryForLocale(locale, ctx)
val dictFile = File(cacheDir, header.mIdString.substringBefore(":") + "_" + USER_DICTIONARY_SUFFIX)
val type = header.mIdString.substringBefore(":")
val info = header.info(ctx.resources.configuration.locale())
ThreeButtonAlertDialog(
onDismissRequest = { onDismissRequest(); cachedFile.delete() },
onConfirmed = {
dictFile.parentFile?.mkdirs()
dictFile.delete()
cachedFile.renameTo(dictFile)
if (header.mIdString.substringBefore(":") == Dictionary.TYPE_MAIN) {
if (type == Dictionary.TYPE_MAIN) {
// replaced main dict, remove the one created from internal data
val internalMainDictFile = File(cacheDir, DictionaryInfoUtils.getExtractedMainDictFilename())
internalMainDictFile.delete()
@ -60,7 +69,7 @@ fun NewDictionaryDialog(
},
text = {
Column {
Text(header.info(LocalContext.current.resources.configuration.locale()))
Text(info)
// todo: dropdown takes very long to load, should be lazy!
// but can't be lazy because of measurements (has width of widest element)
// -> what do?
@ -68,11 +77,25 @@ fun NewDictionaryDialog(
selectedItem = locale,
onSelected = { locale = it },
items = locales
) { Text(LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx)) }
if (locale.script() != dictLocale.script())
Text("wrong script", color = MaterialTheme.colorScheme.error) // todo: string resource
if (dictFile.exists())
Text("will overwrite existing dictionary", color = MaterialTheme.colorScheme.error) // todo: string resource
) { Text(it.localizedDisplayName(ctx)) }
if (locale.script() != dictLocale.script()) {
// whatever, still allow it if the user wants
HorizontalDivider()
Text(
stringResource(R.string.dictionary_file_wrong_script),
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(bottom = 8.dp, top = 4.dp)
)
}
if (dictFile.exists()) {
val oldInfo = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(dictFile, 0, dictFile.length())?.info(ctx.resources.configuration.locale())
HorizontalDivider()
Text(
stringResource(R.string.replace_dictionary_message, type, oldInfo ?: "(no info)", info),
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
)

View file

@ -43,8 +43,8 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.morePopupKeysResId
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.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.LayoutType
@ -134,11 +134,12 @@ fun SubtypeDialog(
}
}
if (showLayoutDeleteDialog) {
// todo: if layout used by other subtypes: either disable button, or explicitly mention in text
val others = SubtypeSettings.getAdditionalSubtypes().filter { st -> st.mainLayoutName() == it }.any { it != subtype }
ConfirmationDialog(
onDismissRequest = { showLayoutDeleteDialog = false },
confirmButtonText = stringResource(R.string.delete),
title = { Text(stringResource(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(it))) },
text = { if (others) Text(stringResource(R.string.layout_in_use)) },
onConfirmed = {
if (it == currentSubtype.mainLayoutName())
currentSubtype = currentSubtype.withoutLayout(LayoutType.MAIN)
@ -193,7 +194,7 @@ fun SubtypeDialog(
WithSmallTitle(stringResource(R.string.secondary_locale)) {
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") {
LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx)
it.localizedDisplayName(ctx)
}.ifEmpty { stringResource(R.string.action_none) }
Text(text, Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge)
}
@ -299,7 +300,7 @@ fun SubtypeDialog(
items = availableLocalesForScript,
initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(),
getItemName = { LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx) }
getItemName = { it.localizedDisplayName(ctx) }
)
if (showKeyOrderDialog) {
val setting = currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER)

View file

@ -21,6 +21,7 @@ import helium314.keyboard.latin.Dictionary
import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.LocaleUtils
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.common.splitOnWhitespace
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
import helium314.keyboard.latin.utils.DICTIONARY_URL
@ -56,7 +57,7 @@ fun DictionaryScreen(
if (term.isBlank()) dictionaryLocales
else dictionaryLocales.filter {
it.language != SubtypeLocaleUtils.NO_LANGUAGE &&
LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx).replace("(", "")
it.localizedDisplayName(ctx).replace("(", "")
.splitOnWhitespace().any { it.startsWith(term, true) }
}
},
@ -73,7 +74,7 @@ fun DictionaryScreen(
val types = dicts.mapTo(mutableListOf()) { it.name.substringBefore("_${USER_DICTIONARY_SUFFIX}") }
if (hasInternal && !types.contains(Dictionary.TYPE_MAIN))
types.add(0, stringResource(R.string.internal_dictionary_summary))
Text(LocaleUtils.getLocaleDisplayNameInSystemLocale(it, ctx))
Text(it.localizedDisplayName(ctx))
Text(
types.joinToString(", "),
style = MaterialTheme.typography.bodyMedium,

View file

@ -25,8 +25,8 @@ 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.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.common.splitOnWhitespace
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
@ -39,7 +39,6 @@ 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.mainLayoutName
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity
@ -86,7 +85,7 @@ fun LanguageScreen(
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) }
?.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
Text(
text = description,

View file

@ -529,8 +529,10 @@ disposition rather than other common dispositions for Latin languages. [CHAR LIM
<string name="button_copy_existing_layout">Copy existing layout</string>
<!-- Title text for choosing a layout name -->
<string name="title_layout_name_select">Set layout name</string>
<!-- Message when deleting a layouts -->
<!-- Message when deleting a layout -->
<string name="delete_layout">Really delete custom layout %s?</string>
<!-- Message when layout to be deleted is in use -->
<string name="layout_in_use">Warning: layout is in currently use</string>
<!-- Message on layout error -->
<string name="layout_error">Layout error: %s</string>
<!-- Text hint for editing layout -->