mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-20 03:52:18 +02:00
Add user dictionary manager UI for system and internal
This commit is contained in:
parent
df6b08024f
commit
084c2abfc2
@ -40,8 +40,9 @@ import java.util.*
|
||||
|
||||
private const val WORDS_TABLE = "words"
|
||||
|
||||
private const val FREQUENCY_MIN = 1
|
||||
private const val FREQENCY_MAX = 255
|
||||
const val FREQUENCY_MIN = 1
|
||||
const val FREQUENCY_MAX = 255
|
||||
const val FREQUENCY_DEFAULT = 128
|
||||
|
||||
private const val SORT_BY_WORD_ASC = "${UserDictionary.Words.WORD} ASC"
|
||||
private const val SORT_BY_WORD_DESC = "${UserDictionary.Words.WORD} DESC"
|
||||
@ -56,6 +57,10 @@ private val PROJECTIONS: Array<String> = arrayOf(
|
||||
UserDictionary.Words.SHORTCUT,
|
||||
)
|
||||
|
||||
private val PROJECTIONS_LANGUAGE: Array<String> = arrayOf(
|
||||
UserDictionary.Words.LOCALE,
|
||||
)
|
||||
|
||||
@Entity(tableName = WORDS_TABLE)
|
||||
data class UserDictionaryEntry(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ -89,12 +94,18 @@ interface UserDictionaryDao {
|
||||
@Query(SELECT_ALL_FROM_WORDS)
|
||||
fun queryAll(): List<UserDictionaryEntry>
|
||||
|
||||
@Query("$SELECT_ALL_FROM_WORDS WHERE (${UserDictionary.Words.LOCALE} = :locale AND :locale IS NOT NULL) OR (${UserDictionary.Words.LOCALE} IS NULL AND :locale IS NULL)")
|
||||
fun queryAll(locale: Locale?): List<UserDictionaryEntry>
|
||||
|
||||
@Query("$SELECT_ALL_FROM_WORDS WHERE ${UserDictionary.Words.WORD} = :word")
|
||||
fun queryExact(word: String): List<UserDictionaryEntry>
|
||||
|
||||
@Query("$SELECT_ALL_FROM_WORDS WHERE ${UserDictionary.Words.WORD} = :word AND $LOCALE_MATCHES")
|
||||
@Query("$SELECT_ALL_FROM_WORDS WHERE ${UserDictionary.Words.WORD} = :word AND (${UserDictionary.Words.LOCALE} = :locale OR (${UserDictionary.Words.LOCALE} IS NULL AND :locale IS NULL))")
|
||||
fun queryExact(word: String, locale: Locale?): List<UserDictionaryEntry>
|
||||
|
||||
@Query("SELECT DISTINCT ${UserDictionary.Words.LOCALE} FROM $WORDS_TABLE")
|
||||
fun queryLanguageList(): List<Locale?>
|
||||
|
||||
@Insert
|
||||
fun insert(entry: UserDictionaryEntry)
|
||||
|
||||
@ -130,7 +141,7 @@ interface UserDictionaryDatabase {
|
||||
when (key) {
|
||||
"w", "word" -> word = value.ifBlank { null }
|
||||
"f", "freq" -> runCatching { value.toInt(10) }.onSuccess {
|
||||
freq = it.coerceIn(FREQUENCY_MIN, FREQENCY_MAX)
|
||||
freq = it.coerceIn(FREQUENCY_MIN, FREQUENCY_MAX)
|
||||
}
|
||||
"l", "locale" -> locale = when (value) {
|
||||
"all", "null", "" -> null
|
||||
@ -203,15 +214,18 @@ abstract class FlorisUserDictionaryDatabase : RoomDatabase(), UserDictionaryData
|
||||
|
||||
class Converters {
|
||||
@TypeConverter
|
||||
fun localeToString(locale: Locale?): String {
|
||||
return locale.toString()
|
||||
fun localeToString(locale: Locale?): String? {
|
||||
return when (locale) {
|
||||
null -> null
|
||||
else -> locale.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun stringToLocale(string: String): Locale? {
|
||||
fun stringToLocale(string: String?): Locale? {
|
||||
return when (string) {
|
||||
"all", "null", "" -> null
|
||||
else ->LocaleUtils.stringToLocale(string)
|
||||
null, "all", "null", "" -> null
|
||||
else -> LocaleUtils.stringToLocale(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,7 +242,7 @@ class SystemUserDictionaryDatabase(context: Context) : UserDictionaryDatabase {
|
||||
override fun query(word: String, locale: Locale?): List<UserDictionaryEntry> {
|
||||
return queryResolver(
|
||||
selection = "${UserDictionary.Words.WORD} LIKE ? AND (${UserDictionary.Words.LOCALE} = ? OR ${UserDictionary.Words.LOCALE} = ? OR ${UserDictionary.Words.LOCALE} IS NULL)",
|
||||
selectionArgs = arrayOf("%$word%", locale.toString(), locale?.language.toString()),
|
||||
selectionArgs = arrayOf("%$word%", locale?.toString() ?: "", locale?.language?.toString() ?: ""),
|
||||
sortOrder = SORT_BY_FREQ_DESC,
|
||||
)
|
||||
}
|
||||
@ -241,6 +255,22 @@ class SystemUserDictionaryDatabase(context: Context) : UserDictionaryDatabase {
|
||||
)
|
||||
}
|
||||
|
||||
override fun queryAll(locale: Locale?): List<UserDictionaryEntry> {
|
||||
return if (locale == null) {
|
||||
queryResolver(
|
||||
selection = "${UserDictionary.Words.LOCALE} IS NULL",
|
||||
selectionArgs = null,
|
||||
sortOrder = SORT_BY_FREQ_DESC,
|
||||
)
|
||||
} else {
|
||||
queryResolver(
|
||||
selection = "${UserDictionary.Words.LOCALE} = ?",
|
||||
selectionArgs = arrayOf(locale.toString()),
|
||||
sortOrder = SORT_BY_FREQ_DESC,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun queryExact(word: String): List<UserDictionaryEntry> {
|
||||
return queryResolver(
|
||||
selection = "${UserDictionary.Words.WORD} = ?",
|
||||
@ -252,11 +282,37 @@ class SystemUserDictionaryDatabase(context: Context) : UserDictionaryDatabase {
|
||||
override fun queryExact(word: String, locale: Locale?): List<UserDictionaryEntry> {
|
||||
return queryResolver(
|
||||
selection = "${UserDictionary.Words.WORD} = ? AND (${UserDictionary.Words.LOCALE} = ? OR ${UserDictionary.Words.LOCALE} = ? OR ${UserDictionary.Words.LOCALE} IS NULL)",
|
||||
selectionArgs = arrayOf(word, locale.toString(), locale?.language.toString()),
|
||||
selectionArgs = arrayOf(word, locale?.toString() ?: "", locale?.language?.toString() ?: ""),
|
||||
sortOrder = null,
|
||||
)
|
||||
}
|
||||
|
||||
override fun queryLanguageList(): List<Locale?> {
|
||||
val resolver = applicationContext.get()?.contentResolver ?: return listOf()
|
||||
val cursor = resolver.query(
|
||||
UserDictionary.Words.CONTENT_URI,
|
||||
PROJECTIONS_LANGUAGE,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
) ?: return listOf()
|
||||
if (cursor.count <= 0) {
|
||||
return listOf()
|
||||
}
|
||||
val localeIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE)
|
||||
val retList = mutableSetOf<Locale?>()
|
||||
while (cursor.moveToNext()) {
|
||||
val localeStr = cursor.getString(localeIndex)
|
||||
if (localeStr == null) {
|
||||
retList.add(null)
|
||||
} else {
|
||||
retList.add(LocaleUtils.stringToLocale(localeStr))
|
||||
}
|
||||
}
|
||||
cursor.close()
|
||||
return retList.toList()
|
||||
}
|
||||
|
||||
private fun queryResolver(selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): List<UserDictionaryEntry> {
|
||||
val resolver = applicationContext.get()?.contentResolver ?: return listOf()
|
||||
val cursor = resolver.query(
|
||||
|
@ -16,28 +16,146 @@
|
||||
|
||||
package dev.patrickgold.florisboard.settings
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.UdmActivityBinding
|
||||
import dev.patrickgold.florisboard.databinding.UdmEntryDialogBinding
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisActivity
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FREQUENCY_DEFAULT
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FREQUENCY_MAX
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FREQUENCY_MIN
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryDao
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryDatabase
|
||||
import dev.patrickgold.florisboard.ime.extension.AssetManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryEntry
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.*
|
||||
import java.util.*
|
||||
|
||||
interface OnListItemCLickListener {
|
||||
fun onListItemClick(pos: Int)
|
||||
}
|
||||
|
||||
class LanguageEntryAdapter(
|
||||
private val data: List<String>,
|
||||
private val onListItemCLickListener: OnListItemCLickListener
|
||||
) : RecyclerView.Adapter<LanguageEntryAdapter.ViewHolder>() {
|
||||
|
||||
class ViewHolder(view: View, private val onListItemCLickListener: OnListItemCLickListener) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
val titleView: TextView = view.findViewById(android.R.id.title)
|
||||
val summaryView: TextView = view.findViewById(android.R.id.summary)
|
||||
|
||||
init {
|
||||
view.setOnClickListener {
|
||||
onListItemCLickListener.onListItemClick(adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val listItemView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.list_item, parent, false)
|
||||
|
||||
return ViewHolder(listItemView, onListItemCLickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.titleView.text = data[position]
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
}
|
||||
|
||||
class UserDictionaryEntryAdapter(
|
||||
private val data: List<UserDictionaryEntry>,
|
||||
private val onListItemCLickListener: OnListItemCLickListener
|
||||
) : RecyclerView.Adapter<UserDictionaryEntryAdapter.ViewHolder>() {
|
||||
|
||||
class ViewHolder(view: View, private val onListItemCLickListener: OnListItemCLickListener) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
val titleView: TextView = view.findViewById(android.R.id.title)
|
||||
val summaryView: TextView = view.findViewById(android.R.id.summary)
|
||||
|
||||
init {
|
||||
view.setOnClickListener {
|
||||
onListItemCLickListener.onListItemClick(adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val listItemView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.list_item, parent, false)
|
||||
|
||||
return ViewHolder(listItemView, onListItemCLickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.titleView.text = data[position].word
|
||||
val shortcut = data[position].shortcut
|
||||
holder.summaryView.text = if (shortcut == null) {
|
||||
String.format(
|
||||
holder.summaryView.context.resources.getString(R.string.settings__udm__word_summary_freq),
|
||||
data[position].freq
|
||||
)
|
||||
} else {
|
||||
String.format(
|
||||
holder.summaryView.context.resources.getString(R.string.settings__udm__word_summary_freq_shortcut),
|
||||
data[position].freq,
|
||||
shortcut
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
}
|
||||
|
||||
class UdmActivity : FlorisActivity<UdmActivityBinding>() {
|
||||
private val dictionaryManager: DictionaryManager get() = DictionaryManager.default()
|
||||
private val assetManager: AssetManager get() = AssetManager.default()
|
||||
|
||||
private var userDictionaryType: Int = -1
|
||||
private var currentLevel: Int = LEVEL_LANGUAGES
|
||||
private var locale: Locale? = null
|
||||
private var currentLocale: Locale? = null
|
||||
private var activeDialogWindow: AlertDialog? = null
|
||||
|
||||
private var languageList: List<Locale?> = listOf()
|
||||
private var wordList: List<UserDictionaryEntry> = listOf()
|
||||
|
||||
private val languageListItemClickListener = object : OnListItemCLickListener {
|
||||
override fun onListItemClick(pos: Int) {
|
||||
if (currentLevel == LEVEL_LANGUAGES) {
|
||||
currentLocale = languageList[pos]
|
||||
currentLevel = LEVEL_WORDS
|
||||
buildUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val wordListItemClickListener = object : OnListItemCLickListener {
|
||||
override fun onListItemClick(pos: Int) {
|
||||
if (currentLevel == LEVEL_WORDS) {
|
||||
val entry = wordList[pos]
|
||||
showEditWordDialog(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val importUserDictionary = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
|
||||
// If uri is null it indicates that the selection activity was cancelled (mostly by pressing the back button),
|
||||
@ -100,7 +218,7 @@ class UdmActivity : FlorisActivity<UdmActivityBinding>() {
|
||||
|
||||
private const val LEVEL_LANGUAGES: Int = 1
|
||||
private const val LEVEL_WORDS: Int = 2
|
||||
private const val USER_DICTIONARY_SETTINGS_INTENT_ACTION: String =
|
||||
private const val SYSTEM_USER_DICTIONARY_SETTINGS_INTENT_ACTION: String =
|
||||
"android.settings.USER_DICTIONARY_SETTINGS"
|
||||
}
|
||||
|
||||
@ -123,7 +241,10 @@ class UdmActivity : FlorisActivity<UdmActivityBinding>() {
|
||||
|
||||
dictionaryManager.loadUserDictionariesIfNecessary()
|
||||
|
||||
binding.fabAddWord.setOnClickListener { }
|
||||
binding.fabAddWord.setOnClickListener { showAddWordDialog() }
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
|
||||
|
||||
buildUi()
|
||||
}
|
||||
|
||||
override fun onCreateBinding(): UdmActivityBinding {
|
||||
@ -132,9 +253,24 @@ class UdmActivity : FlorisActivity<UdmActivityBinding>() {
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.udm_extra_menu, menu)
|
||||
if (userDictionaryType == USER_DICTIONARY_TYPE_FLORIS) {
|
||||
menu?.findItem(R.id.udm__open_system_manager_ui)?.isVisible = false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
activeDialogWindow?.dismiss()
|
||||
activeDialogWindow = null
|
||||
currentLocale = null
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
buildUi()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
@ -149,11 +285,134 @@ class UdmActivity : FlorisActivity<UdmActivityBinding>() {
|
||||
exportUserDictionary.launch("my-personal-dictionary.clb")
|
||||
true
|
||||
}
|
||||
R.id.udm__open_system_manager_ui -> {
|
||||
startActivity(Intent(SYSTEM_USER_DICTIONARY_SETTINGS_INTENT_ACTION))
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildUi() {
|
||||
override fun onBackPressed() {
|
||||
if (currentLevel == LEVEL_WORDS) {
|
||||
currentLevel = LEVEL_LANGUAGES
|
||||
currentLocale = null
|
||||
buildUi()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun userDictionaryDao(): UserDictionaryDao? {
|
||||
return when (userDictionaryType) {
|
||||
USER_DICTIONARY_TYPE_FLORIS -> dictionaryManager.florisUserDictionaryDao()
|
||||
USER_DICTIONARY_TYPE_SYSTEM -> dictionaryManager.systemUserDictionaryDao()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildUi() {
|
||||
when (currentLevel) {
|
||||
LEVEL_LANGUAGES -> {
|
||||
languageList = userDictionaryDao()?.queryLanguageList()?.sortedBy { it?.displayLanguage } ?: listOf()
|
||||
binding.recyclerView.adapter = LanguageEntryAdapter(
|
||||
languageList.map { it?.displayName ?: resources.getString(R.string.settings__udm__all_languages) },
|
||||
languageListItemClickListener
|
||||
)
|
||||
}
|
||||
LEVEL_WORDS -> {
|
||||
wordList = userDictionaryDao()?.queryAll(currentLocale) ?: listOf()
|
||||
binding.recyclerView.adapter = UserDictionaryEntryAdapter(
|
||||
wordList,
|
||||
wordListItemClickListener
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAddWordDialog() {
|
||||
val dialogBinding = UdmEntryDialogBinding.inflate(layoutInflater)
|
||||
dialogBinding.freq.setText(FREQUENCY_DEFAULT.toString())
|
||||
dialogBinding.freqLabel.hint = String.format(
|
||||
resources.getString(R.string.settings__udm__dialog__freq_label),
|
||||
FREQUENCY_MIN,
|
||||
FREQUENCY_MAX
|
||||
)
|
||||
if (currentLevel == LEVEL_WORDS) {
|
||||
currentLocale?.let {
|
||||
dialogBinding.locale.setText(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.settings__udm__dialog__title_add)
|
||||
setCancelable(true)
|
||||
setView(dialogBinding.root)
|
||||
setPositiveButton(R.string.assets__action__add, null)
|
||||
setNegativeButton(R.string.assets__action__cancel, null)
|
||||
setOnDismissListener { activeDialogWindow = null }
|
||||
create()
|
||||
activeDialogWindow = show()
|
||||
activeDialogWindow?.getButton(AlertDialog.BUTTON_POSITIVE)?.setOnClickListener {
|
||||
val word = dialogBinding.word.text.toString()
|
||||
val freq = dialogBinding.freq.text.toString()
|
||||
val shortcut = dialogBinding.shortcut.text?.toString()?.ifBlank { null }
|
||||
val locale = dialogBinding.locale.text?.toString()?.ifBlank { null }
|
||||
if (word.isBlank() || freq.isBlank()) {
|
||||
// ERROR
|
||||
} else {
|
||||
userDictionaryDao()?.insert(
|
||||
UserDictionaryEntry(0, word, freq.toInt(), locale, shortcut)
|
||||
)
|
||||
activeDialogWindow?.dismiss()
|
||||
activeDialogWindow = null
|
||||
buildUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEditWordDialog(entry: UserDictionaryEntry) {
|
||||
val dialogBinding = UdmEntryDialogBinding.inflate(layoutInflater)
|
||||
dialogBinding.word.setText(entry.word)
|
||||
dialogBinding.freq.setText(entry.freq.toString())
|
||||
dialogBinding.freqLabel.hint = String.format(
|
||||
resources.getString(R.string.settings__udm__dialog__freq_label),
|
||||
FREQUENCY_MIN,
|
||||
FREQUENCY_MAX
|
||||
)
|
||||
dialogBinding.shortcut.setText(entry.shortcut ?: "")
|
||||
dialogBinding.locale.setText(entry.locale ?: "")
|
||||
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.settings__udm__dialog__title_edit)
|
||||
setCancelable(true)
|
||||
setView(dialogBinding.root)
|
||||
setPositiveButton(R.string.assets__action__apply, null)
|
||||
setNegativeButton(R.string.assets__action__cancel, null)
|
||||
setNeutralButton(R.string.assets__action__delete) { _, _ ->
|
||||
userDictionaryDao()?.delete(entry)
|
||||
buildUi()
|
||||
}
|
||||
setOnDismissListener { activeDialogWindow = null }
|
||||
create()
|
||||
activeDialogWindow = show()
|
||||
activeDialogWindow?.getButton(AlertDialog.BUTTON_POSITIVE)?.setOnClickListener {
|
||||
val word = dialogBinding.word.text.toString()
|
||||
val freq = dialogBinding.freq.text.toString()
|
||||
val shortcut = dialogBinding.shortcut.text?.toString()?.ifBlank { null }
|
||||
val locale = dialogBinding.locale.text?.toString()?.ifBlank { null }
|
||||
if (word.isBlank() || freq.isBlank()) {
|
||||
// ERROR
|
||||
} else {
|
||||
userDictionaryDao()?.update(
|
||||
UserDictionaryEntry(entry.id, word, freq.toInt(), locale, shortcut)
|
||||
)
|
||||
activeDialogWindow?.dismiss()
|
||||
activeDialogWindow = null
|
||||
buildUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
94
app/src/main/res/layout/udm_entry_dialog.xml
Normal file
94
app/src/main/res/layout/udm_entry_dialog.xml
Normal file
@ -0,0 +1,94 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingTop="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/word_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/settings__udm__dialog__word_label"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxBackgroundColor="?android:windowBackground"
|
||||
app:boxStrokeColor="?colorAccent"
|
||||
app:boxStrokeErrorColor="?colorError"
|
||||
app:boxStrokeWidth="1dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/word"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textFilter"
|
||||
android:imeOptions="flagNoExtractUi"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/freq_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/settings__udm__dialog__freq_label"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxBackgroundColor="?android:windowBackground"
|
||||
app:boxStrokeColor="?colorAccent"
|
||||
app:boxStrokeErrorColor="?colorError"
|
||||
app:boxStrokeWidth="1dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/freq"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textFilter"
|
||||
android:imeOptions="flagNoExtractUi"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/shortcut_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/settings__udm__dialog__shortcut_label"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxBackgroundColor="?android:windowBackground"
|
||||
app:boxStrokeColor="?colorAccent"
|
||||
app:boxStrokeErrorColor="?colorError"
|
||||
app:boxStrokeWidth="1dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/shortcut"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textFilter"
|
||||
android:imeOptions="flagNoExtractUi"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/locale_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/settings__udm__dialog__locale_label"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxBackgroundColor="?android:windowBackground"
|
||||
app:boxStrokeColor="?colorAccent"
|
||||
app:boxStrokeErrorColor="?colorError"
|
||||
app:boxStrokeWidth="1dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/locale"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textFilter"
|
||||
android:imeOptions="flagNoExtractUi"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
@ -17,6 +17,11 @@
|
||||
android:id="@+id/udm__export"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/assets__action__export"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/udm__open_system_manager_ui"
|
||||
android:orderInCategory="3"
|
||||
android:title="@string/settings__udm__open_system_manager_ui"/>
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
@ -259,9 +259,18 @@
|
||||
|
||||
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">Internal User Dictionary</string>
|
||||
<string name="settings__udm__title_system" comment="Title of the User Dictionary Manager activity for system">System User Dictionary</string>
|
||||
<string name="settings__udm__word_summary_freq" comment="Summary label for a word entry. The decimal placeholder inserts the frequency for the word it summarizes.">Frequency: %d</string>
|
||||
<string name="settings__udm__word_summary_freq_shortcut" comment="Summary label for a word entry. The first placeholder inserts the frequency for the word it summarizes, the second placeholder the shortcut defined.">Frequency: %d | Shortcut: %s</string>
|
||||
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">For all languages</string>
|
||||
<string name="settings__udm__open_system_manager_ui" comment="Label of the Open system manager UI menu option">Open system manager UI</string>
|
||||
<string name="settings__udm__dictionary_import_success" comment="Message for dictionary import success">User dictionary imported successfully!</string>
|
||||
<string name="settings__udm__dictionary_export_success" comment="Message for dictionary export success">User dictionary exported successfully!</string>
|
||||
<string name="settings__udm__dialog__title_add" comment="Label for the title (when in adding mode) in the user dictionary add/edit dialog">Add word entry</string>
|
||||
<string name="settings__udm__dialog__title_edit" comment="Label for the title (when in editing mode) in the user dictionary add/edit dialog">Edit word entry</string>
|
||||
<string name="settings__udm__dialog__word_label" comment="Label for the word in the user dictionary add/edit dialog">Word</string>
|
||||
<string name="settings__udm__dialog__freq_label" comment="Label for the frequency in the user dictionary add/edit dialog. The two decimal placeholders are the minimum and maximum frequency, both inclusive.">Frequency (between %d and %d)</string>
|
||||
<string name="settings__udm__dialog__shortcut_label" comment="Label for the shortcut in the user dictionary add/edit dialog">Shortcut (optional)</string>
|
||||
<string name="settings__udm__dialog__locale_label" comment="Label for the language code in the user dictionary add/edit dialog">Language code (optional)</string>
|
||||
|
||||
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gestures & Glide typing</string>
|
||||
<string name="pref__glide__title" comment="Preference group title">Glide typing</string>
|
||||
@ -347,6 +356,7 @@
|
||||
<string name="assets__file__name">Name</string>
|
||||
<string name="assets__file__source">Source</string>
|
||||
<string name="assets__action__add">Add</string>
|
||||
<string name="assets__action__apply">Apply</string>
|
||||
<string name="assets__action__cancel">Cancel</string>
|
||||
<string name="assets__action__cancel_confirm_title">Confirm cancel</string>
|
||||
<string name="assets__action__cancel_confirm_message">Are you sure you want to discard any unsaved changes? This action can not be undone once executed.</string>
|
||||
|
Loading…
Reference in New Issue
Block a user