mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-18 16:03:12 +00:00
register app for opening .dict files (content uri only)
This commit is contained in:
parent
e623d14829
commit
e3240965a8
6 changed files with 183 additions and 80 deletions
|
@ -15,12 +15,9 @@ import androidx.core.view.isVisible
|
|||
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants
|
||||
import org.dslul.openboard.inputmethod.latin.BinaryDictionaryGetter
|
||||
import org.dslul.openboard.inputmethod.latin.R
|
||||
import org.dslul.openboard.inputmethod.latin.common.FileUtils
|
||||
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
|
||||
import org.dslul.openboard.inputmethod.latin.makedict.DictionaryHeader
|
||||
import org.dslul.openboard.inputmethod.latin.utils.*
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
|
@ -37,7 +34,6 @@ class LanguageSettingsDialog(
|
|||
private val view = LayoutInflater.from(context).inflate(R.layout.locale_settings_dialog, null)
|
||||
private val mainLocaleString = subtypes.first().subtype.locale
|
||||
private val mainLocale = mainLocaleString.toLocale()
|
||||
private val cachedDictionaryFile by lazy { File(context.cacheDir.path + File.separator + "temp_dict") }
|
||||
|
||||
init {
|
||||
setTitle(subtypes.first().displayName)
|
||||
|
@ -207,82 +203,10 @@ class LanguageSettingsDialog(
|
|||
}
|
||||
|
||||
override fun onNewDictionary(uri: Uri?) {
|
||||
if (uri == null)
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
|
||||
cachedDictionaryFile.delete()
|
||||
try {
|
||||
FileUtils.copyStreamToNewFile(
|
||||
context.contentResolver.openInputStream(uri),
|
||||
cachedDictionaryFile
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
}
|
||||
val newHeader = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(cachedDictionaryFile, 0, cachedDictionaryFile.length())
|
||||
?: return onDictionaryLoadingError(R.string.dictionary_file_error)
|
||||
|
||||
val locale = newHeader.mLocaleString.toLocale()
|
||||
// ScriptUtils.getScriptFromSpellCheckerLocale may return latin when it should not,
|
||||
// e.g. for Persian or Chinese. But at least fail when dictionary certainly is incompatible
|
||||
if (ScriptUtils.getScriptFromSpellCheckerLocale(locale) != ScriptUtils.getScriptFromSpellCheckerLocale(mainLocale))
|
||||
return onDictionaryLoadingError(R.string.dictionary_file_wrong_script)
|
||||
|
||||
if (locale != mainLocale) {
|
||||
val message = context.resources.getString(
|
||||
R.string.dictionary_file_wrong_locale,
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context),
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(mainLocale, context)
|
||||
)
|
||||
Builder(context)
|
||||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() }
|
||||
.setPositiveButton(R.string.dictionary_file_wrong_locale_ok) { _, _ ->
|
||||
addDictAndAskToReplace(newHeader)
|
||||
}
|
||||
.show()
|
||||
return
|
||||
}
|
||||
addDictAndAskToReplace(newHeader)
|
||||
}
|
||||
|
||||
private fun addDictAndAskToReplace(header: DictionaryHeader) {
|
||||
val dictionaryType = header.mIdString.substringBefore(":")
|
||||
val dictFilename = DictionaryInfoUtils.getCacheDirectoryForLocale(mainLocaleString, context) +
|
||||
File.separator + dictionaryType + "_" + USER_DICTIONARY_SUFFIX
|
||||
val dictFile = File(dictFilename)
|
||||
|
||||
fun moveDict(replaced: Boolean) {
|
||||
if (!cachedDictionaryFile.renameTo(dictFile)) {
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
}
|
||||
if (dictionaryType == DictionaryInfoUtils.DEFAULT_MAIN_DICT) {
|
||||
// replaced main dict, remove the one created from internal data
|
||||
// todo: currently not, see also BinaryDictionaryGetter.getDictionaryFiles
|
||||
// val internalMainDictFilename = DictionaryInfoUtils.getCacheDirectoryForLocale(mainLocaleString, context) +
|
||||
// File.separator + DictionaryInfoUtils.getMainDictFilename(mainLocaleString)
|
||||
// File(internalMainDictFilename).delete()
|
||||
}
|
||||
val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)
|
||||
fragment?.activity?.sendBroadcast(newDictBroadcast)
|
||||
NewDictionaryAdder(context) { replaced, dictFile ->
|
||||
if (!replaced)
|
||||
addDictionaryToView(dictFile, view.findViewById(R.id.dictionaries))
|
||||
}
|
||||
|
||||
if (!dictFile.exists()) {
|
||||
return moveDict(false)
|
||||
}
|
||||
confirmDialog(context, context.getString(R.string.replace_dictionary_message, dictionaryType), context.getString(
|
||||
R.string.replace_dictionary)) {
|
||||
moveDict(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDictionaryLoadingError(messageId: Int) = onDictionaryLoadingError(context.getString(messageId))
|
||||
|
||||
private fun onDictionaryLoadingError(message: String) {
|
||||
cachedDictionaryFile.delete()
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
|
||||
}.addDictionary(uri, mainLocale)
|
||||
}
|
||||
|
||||
private fun addDictionaryToView(dictFile: File, dictionariesView: LinearLayout) {
|
||||
|
@ -395,5 +319,4 @@ private fun getAvailableDictionaryLocales(context: Context, mainLocaleString: St
|
|||
return locales
|
||||
}
|
||||
|
||||
private fun String.toLocale() = LocaleUtils.constructLocaleFromString(this)
|
||||
private const val DICTIONARY_URL = "https://codeberg.org/Helium314/aosp-dictionaries"
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.preference.PreferenceActivity;
|
|||
|
||||
import org.dslul.openboard.inputmethod.latin.permissions.PermissionsManager;
|
||||
import org.dslul.openboard.inputmethod.latin.utils.FragmentUtils;
|
||||
import org.dslul.openboard.inputmethod.latin.utils.NewDictionaryAdder;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
|
@ -46,6 +47,10 @@ public final class SettingsActivity extends PreferenceActivity
|
|||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setHomeButtonEnabled(true);
|
||||
}
|
||||
final Intent i = getIntent();
|
||||
if (Intent.ACTION_VIEW.equals(i.getAction()) && i.getData() != null) {
|
||||
new NewDictionaryAdder(this, null).addDictionary(i.getData(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -133,6 +133,16 @@ fun getSystemLocales(): List<Locale> {
|
|||
return systemLocales
|
||||
}
|
||||
|
||||
fun hasMatchingSubtypeForLocaleString(localeString: String): Boolean {
|
||||
require(initialized)
|
||||
return !resourceSubtypesByLocale[localeString].isNullOrEmpty()
|
||||
}
|
||||
|
||||
fun getAvailableSubtypeLocaleStrings(): Collection<String> {
|
||||
require(initialized)
|
||||
return resourceSubtypesByLocale.keys
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
if (initialized) return
|
||||
SubtypeLocaleUtils.init(context) // necessary to get the correct getKeyboardLayoutSetName
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
package org.dslul.openboard.inputmethod.latin.utils
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants
|
||||
import org.dslul.openboard.inputmethod.latin.R
|
||||
import org.dslul.openboard.inputmethod.latin.common.FileUtils
|
||||
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
|
||||
import org.dslul.openboard.inputmethod.latin.makedict.DictionaryHeader
|
||||
import org.dslul.openboard.inputmethod.latin.settings.*
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class NewDictionaryAdder(private val context: Context, private val onAdded: ((Boolean, File) -> Unit)?) {
|
||||
private val cachedDictionaryFile = File(context.cacheDir.path + File.separator + "temp_dict")
|
||||
|
||||
fun addDictionary(uri: Uri?, mainLocale: Locale?) {
|
||||
if (uri == null)
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
|
||||
cachedDictionaryFile.delete()
|
||||
try {
|
||||
val i = context.contentResolver.openInputStream(uri)
|
||||
FileUtils.copyStreamToNewFile(
|
||||
i,
|
||||
cachedDictionaryFile
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
}
|
||||
|
||||
val newHeader = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(cachedDictionaryFile, 0, cachedDictionaryFile.length())
|
||||
?: return onDictionaryLoadingError(R.string.dictionary_file_error)
|
||||
val locale = newHeader.mLocaleString.toLocale()
|
||||
|
||||
if (mainLocale == null) {
|
||||
val localeName = LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context)
|
||||
val message = context.getString(R.string.add_new_dictionary_ask_locale,
|
||||
newHeader.mIdString.substringBefore(":"),
|
||||
localeName
|
||||
)
|
||||
val b = AlertDialog.Builder(context)
|
||||
.setTitle(R.string.add_new_dictionary_title)
|
||||
.setMessage(message)
|
||||
.setNeutralButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() }
|
||||
.setNegativeButton(R.string.button_select_language) { _, _ -> selectLocaleForDictionary(newHeader, locale) }
|
||||
if (hasMatchingSubtypeForLocaleString(locale.toString())) {
|
||||
val buttonText = context.getString(R.string.button_add_to_language, localeName)
|
||||
b.setPositiveButton(buttonText) { _, _ ->
|
||||
addDictAndAskToReplace(newHeader, locale)
|
||||
}
|
||||
}
|
||||
b.show()
|
||||
return
|
||||
}
|
||||
|
||||
// ScriptUtils.getScriptFromSpellCheckerLocale may return latin when it should not,
|
||||
// e.g. for Persian or Chinese. But at least fail when dictionary certainly is incompatible
|
||||
if (ScriptUtils.getScriptFromSpellCheckerLocale(locale) != ScriptUtils.getScriptFromSpellCheckerLocale(mainLocale))
|
||||
return onDictionaryLoadingError(R.string.dictionary_file_wrong_script)
|
||||
|
||||
if (locale != mainLocale) {
|
||||
val message = context.resources.getString(
|
||||
R.string.dictionary_file_wrong_locale,
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context),
|
||||
LocaleUtils.getLocaleDisplayNameInSystemLocale(mainLocale, context)
|
||||
)
|
||||
AlertDialog.Builder(context)
|
||||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() }
|
||||
.setPositiveButton(R.string.dictionary_file_wrong_locale_ok) { _, _ ->
|
||||
addDictAndAskToReplace(newHeader, mainLocale)
|
||||
}
|
||||
.show()
|
||||
return
|
||||
}
|
||||
addDictAndAskToReplace(newHeader, mainLocale)
|
||||
}
|
||||
|
||||
private fun selectLocaleForDictionary(newHeader: DictionaryHeader, dictLocale: Locale) {
|
||||
val localeStrings = getAvailableSubtypeLocaleStrings()
|
||||
val locales = linkedSetOf<Locale>()
|
||||
localeStrings.forEach {
|
||||
if (it.substringBefore("_") == dictLocale.language)
|
||||
locales.add(it.toLocale())
|
||||
}
|
||||
localeStrings.forEach { locales.add(it.toLocale()) }
|
||||
val displayNamesArray = locales.map { LocaleUtils.getLocaleDisplayNameInSystemLocale(it, context) }.toTypedArray()
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(R.string.button_select_language)
|
||||
.setItems(displayNamesArray) { di, i ->
|
||||
di.dismiss()
|
||||
locales.forEachIndexed { index, locale ->
|
||||
if (index == i)
|
||||
addDictAndAskToReplace(newHeader, locale)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() }
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun addDictAndAskToReplace(header: DictionaryHeader, mainLocale: Locale) {
|
||||
val dictionaryType = header.mIdString.substringBefore(":")
|
||||
val dictFilename = DictionaryInfoUtils.getCacheDirectoryForLocale(mainLocale.toString(), context) +
|
||||
File.separator + dictionaryType + "_" + USER_DICTIONARY_SUFFIX
|
||||
val dictFile = File(dictFilename)
|
||||
|
||||
fun moveDict(replaced: Boolean) {
|
||||
if (!cachedDictionaryFile.renameTo(dictFile)) {
|
||||
return onDictionaryLoadingError(R.string.dictionary_load_error)
|
||||
}
|
||||
if (dictionaryType == DictionaryInfoUtils.DEFAULT_MAIN_DICT) {
|
||||
// replaced main dict, remove the one created from internal data
|
||||
// todo: currently not, see also BinaryDictionaryGetter.getDictionaryFiles
|
||||
// val internalMainDictFilename = DictionaryInfoUtils.getCacheDirectoryForLocale(mainLocaleString, context) +
|
||||
// File.separator + DictionaryInfoUtils.getMainDictFilename(mainLocaleString)
|
||||
// File(internalMainDictFilename).delete()
|
||||
}
|
||||
val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)
|
||||
context.sendBroadcast(newDictBroadcast)
|
||||
onAdded?.let { it(replaced, dictFile) }
|
||||
}
|
||||
|
||||
if (!dictFile.exists()) {
|
||||
return moveDict(false)
|
||||
}
|
||||
confirmDialog(context, context.getString(R.string.replace_dictionary_message, dictionaryType), context.getString(
|
||||
R.string.replace_dictionary)) {
|
||||
moveDict(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDictionaryLoadingError(messageId: Int) {
|
||||
cachedDictionaryFile.delete()
|
||||
Toast.makeText(context, messageId, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun String.toLocale() = LocaleUtils.constructLocaleFromString(this)
|
Loading…
Add table
Add a link
Reference in a new issue