mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-20 03:52:18 +02:00
Add internal subtype management with language/layout selection
- The subtype management is done only internally because the default Android subtypes don't really allow for dynamically added Subtypes. Additionally the official Android docs recommend against using the default Subtypes when providing a way to customize the locale/layout association. - Subtypes are always a triple: id/locale/layout, where the user can configure both the locale and the layout in the Settings. - Fallback subtype if none is specified is English/QWERTY. - Language switch now shows accordingly to the number of subtypes defined. - Current language name is shown on SpaceBar. - PrefHelper.Keyboard now provides methods to easily manipulate the subtype list and to get the current active subtype. - Other fixes in KeyView and Looknfeel which get fixed with this commit: - Key preview may flicker if the pointer is between the screen edge and the first KeyView of the row, due to a indefinite circle between loose in interest and giving the interest to the view. - Cleanup in LooknfeelFragment.kt
This commit is contained in:
parent
adaa3f0a9c
commit
05ccaeea66
@ -7,6 +7,7 @@
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:extractNativeLibs="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
|
@ -27,10 +27,8 @@ import dev.patrickgold.florisboard.ime.text.TextInputManager
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.settings.SettingsMainActivity
|
||||
import dev.patrickgold.florisboard.util.ViewLayoutUtils
|
||||
import dev.patrickgold.florisboard.util.getBooleanFromAttr
|
||||
import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
import dev.patrickgold.florisboard.util.refreshLayoutOf
|
||||
import dev.patrickgold.florisboard.util.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Variable which holds the current [FlorisBoard] instance. To get this instance from another
|
||||
@ -44,6 +42,7 @@ private var florisboardInstance: FlorisBoard? = null
|
||||
*/
|
||||
class FlorisBoard : InputMethodService() {
|
||||
|
||||
lateinit var activeSubtype: Subtype
|
||||
private var audioManager: AudioManager? = null
|
||||
val context: Context
|
||||
get() = inputView?.context ?: this
|
||||
@ -78,6 +77,8 @@ class FlorisBoard : InputMethodService() {
|
||||
prefs.initDefaultPreferences()
|
||||
prefs.sync()
|
||||
|
||||
activeSubtype = prefs.keyboard.fetchActiveSubtype() ?: Subtype(-1, Locale.ENGLISH, "qwerty")
|
||||
|
||||
currentThemeResId = prefs.theme.getSelectedThemeResId()
|
||||
setTheme(currentThemeResId)
|
||||
|
||||
@ -145,6 +146,8 @@ class FlorisBoard : InputMethodService() {
|
||||
prefs.sync()
|
||||
updateThemeIfNecessary()
|
||||
updateOneHandedPanelVisibility()
|
||||
activeSubtype = prefs.keyboard.fetchActiveSubtype() ?: Subtype(-1, Locale.ENGLISH, "qwerty")
|
||||
onSubtypeChanged(activeSubtype)
|
||||
setActiveInput(R.id.text_input)
|
||||
|
||||
super.onWindowShown()
|
||||
@ -332,11 +335,20 @@ class FlorisBoard : InputMethodService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: evaluate the boolean based on the language prefs
|
||||
* @return If the language switch should be shown
|
||||
*/
|
||||
fun shouldShowLanguageSwitch(): Boolean {
|
||||
return false
|
||||
return prefs.keyboard.subtypes.size > 1
|
||||
}
|
||||
|
||||
fun switchToNextSubtype() {
|
||||
activeSubtype = prefs.keyboard.switchToNextSubtype() ?: Subtype(-1, Locale.ENGLISH, "qwerty")
|
||||
onSubtypeChanged(activeSubtype)
|
||||
}
|
||||
|
||||
private fun onSubtypeChanged(newSubtype: Subtype) {
|
||||
textInputManager.onSubtypeChanged(newSubtype)
|
||||
mediaInputManager.onSubtypeChanged(newSubtype)
|
||||
}
|
||||
|
||||
fun setActiveInput(type: Int) {
|
||||
@ -405,6 +417,28 @@ class FlorisBoard : InputMethodService() {
|
||||
}, 0)
|
||||
}
|
||||
|
||||
data class Subtype(
|
||||
var id: Int,
|
||||
var locale: Locale,
|
||||
var layoutName: String
|
||||
) {
|
||||
companion object {
|
||||
fun fromString(string: String): Subtype {
|
||||
val data = string.split("/")
|
||||
if (data.size != 3) {
|
||||
throw Exception("Given string is malformed...")
|
||||
} else {
|
||||
val locale = LocaleUtils.stringToLocale(data[1])
|
||||
return Subtype(data[0].toInt(), locale, data[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$id/$locale/$layoutName"
|
||||
}
|
||||
}
|
||||
|
||||
interface EventListener {
|
||||
fun onCreate() {}
|
||||
fun onCreateInputView() {}
|
||||
@ -428,5 +462,7 @@ class FlorisBoard : InputMethodService() {
|
||||
candidatesStart: Int,
|
||||
candidatesEnd: Int
|
||||
) {}
|
||||
|
||||
fun onSubtypeChanged(newSubtype: Subtype) {}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ import android.content.SharedPreferences
|
||||
import android.provider.Settings
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.util.LocaleUtils
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* Helper class for an organized access to the shared preferences.
|
||||
@ -34,6 +37,7 @@ class PrefHelper(
|
||||
private val cacheString: HashMap<String, String> = hashMapOf()
|
||||
|
||||
val advanced = Advanced(this)
|
||||
val keyboard = Keyboard(this)
|
||||
val looknfeel = Looknfeel(this)
|
||||
val theme = Theme(this)
|
||||
|
||||
@ -110,9 +114,11 @@ class PrefHelper(
|
||||
*/
|
||||
fun initDefaultPreferences() {
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_advanced, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_correction, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_keyboard, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_looknfeel, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_theme, true)
|
||||
//setPref(Keyboard.SUBTYPES, "")
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,6 +155,111 @@ class PrefHelper(
|
||||
private set
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for keyboard preferences.
|
||||
*/
|
||||
class Keyboard(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val ACTIVE_SUBTYPE_ID = "keyboard__active_subtype_id"
|
||||
const val SUBTYPES = "keyboard__subtypes"
|
||||
}
|
||||
|
||||
private var activeSubtypeId: Int
|
||||
get() = prefHelper.getPref(ACTIVE_SUBTYPE_ID, -1)
|
||||
private set(v) = prefHelper.setPref(ACTIVE_SUBTYPE_ID, v)
|
||||
var subtypes: List<FlorisBoard.Subtype>
|
||||
get() {
|
||||
val listRaw = prefHelper.getPref(SUBTYPES, "")
|
||||
return if (listRaw == "") {
|
||||
listOf()
|
||||
} else {
|
||||
listRaw.split(";").map {
|
||||
FlorisBoard.Subtype.fromString(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
set(value) = prefHelper.setPref(SUBTYPES, value.joinToString(";"))
|
||||
|
||||
private fun addSubtype(subtype: FlorisBoard.Subtype) {
|
||||
val oldListRaw = prefHelper.getPref(SUBTYPES, "")
|
||||
if (oldListRaw.isBlank()) {
|
||||
prefHelper.setPref(SUBTYPES, "$subtype")
|
||||
} else {
|
||||
prefHelper.setPref(SUBTYPES, "$oldListRaw;$subtype")
|
||||
}
|
||||
}
|
||||
fun addSubtype(locale: Locale, layoutName: String) {
|
||||
addSubtype(FlorisBoard.Subtype(
|
||||
locale.hashCode() + layoutName.hashCode(),
|
||||
locale,
|
||||
layoutName
|
||||
))
|
||||
}
|
||||
fun fetchActiveSubtype(): FlorisBoard.Subtype? {
|
||||
for (s in subtypes) {
|
||||
if (s.id == activeSubtypeId) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
val subtypes = this.subtypes
|
||||
return if (subtypes.isNotEmpty()) {
|
||||
activeSubtypeId = subtypes[0].id
|
||||
subtypes[0]
|
||||
} else {
|
||||
activeSubtypeId = -1
|
||||
null
|
||||
}
|
||||
}
|
||||
fun getSubtypeById(id: Int): FlorisBoard.Subtype? {
|
||||
for (s in subtypes) {
|
||||
if (s.id == id) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
fun removeSubtype(subtype: FlorisBoard.Subtype) {
|
||||
val oldListRaw = prefHelper.getPref(SUBTYPES, "")
|
||||
var newListRaw = ""
|
||||
for (s in oldListRaw.split(";")) {
|
||||
if (s != subtype.toString()) {
|
||||
newListRaw += "$s;"
|
||||
}
|
||||
}
|
||||
if (newListRaw.isNotEmpty()) {
|
||||
newListRaw = newListRaw.substring(0, newListRaw.length - 1)
|
||||
}
|
||||
prefHelper.setPref(SUBTYPES, newListRaw)
|
||||
if (subtype.id == activeSubtypeId) {
|
||||
fetchActiveSubtype()
|
||||
}
|
||||
}
|
||||
fun switchToNextSubtype(): FlorisBoard.Subtype? {
|
||||
val subtypes = this.subtypes
|
||||
val activeSubtype = fetchActiveSubtype() ?: return null
|
||||
var triggerNextSubtype = false
|
||||
var newActiveSubtype: FlorisBoard.Subtype? = null
|
||||
for (s in subtypes) {
|
||||
if (triggerNextSubtype) {
|
||||
triggerNextSubtype = false
|
||||
newActiveSubtype = s
|
||||
} else if (s == activeSubtype) {
|
||||
triggerNextSubtype = true
|
||||
}
|
||||
}
|
||||
if (triggerNextSubtype) {
|
||||
newActiveSubtype = subtypes[0]
|
||||
}
|
||||
return if (newActiveSubtype == null) {
|
||||
activeSubtypeId = -1
|
||||
null
|
||||
} else {
|
||||
activeSubtypeId = newActiveSubtype.id
|
||||
newActiveSubtype
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for looknfeel preferences.
|
||||
*/
|
||||
|
@ -26,7 +26,6 @@ import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.ExtractedTextRequest
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import android.widget.ViewFlipper
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
@ -104,7 +103,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
override fun onCreate() {
|
||||
if (BuildConfig.DEBUG) Log.i(this::class.simpleName, "onCreate()")
|
||||
|
||||
layoutManager.autoFetchAssociationsFromPrefs()
|
||||
layoutManager.autoFetchAssociationsFromPrefs(florisboard.prefs)
|
||||
smartbarManager = SmartbarManager.getInstance()
|
||||
}
|
||||
|
||||
@ -208,6 +207,10 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
smartbarManager.onFinishInputView()
|
||||
}
|
||||
|
||||
override fun onWindowShown() {
|
||||
keyboardViews[KeyboardMode.CHARACTERS]?.updateVisibility()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets [activeKeyboardMode].
|
||||
*
|
||||
@ -230,6 +233,13 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
smartbarManager.activeContainerId = smartbarManager.getPreferredContainerId()
|
||||
}
|
||||
|
||||
override fun onSubtypeChanged(newSubtype: FlorisBoard.Subtype) {
|
||||
layoutManager.autoFetchAssociationsFromPrefs(florisboard.prefs)
|
||||
val keyboardView = keyboardViews[KeyboardMode.CHARACTERS]
|
||||
keyboardView?.setKeyboardMode(KeyboardMode.CHARACTERS)
|
||||
keyboardView?.updateVisibility()
|
||||
}
|
||||
|
||||
/**
|
||||
* Main logic point for processing cursor updates as well as parsing the current composing word
|
||||
* and passing this info on to the [SmartbarManager] to turn it into candidate suggestions.
|
||||
@ -451,10 +461,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
when (keyData.code) {
|
||||
KeyCode.DELETE -> handleDelete()
|
||||
KeyCode.ENTER -> handleEnter()
|
||||
KeyCode.LANGUAGE_SWITCH -> {
|
||||
Toast.makeText(florisboard, "[NYI]: Language switch",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
KeyCode.LANGUAGE_SWITCH -> florisboard.switchToNextSubtype()
|
||||
KeyCode.SHIFT -> handleShift()
|
||||
KeyCode.SHOW_INPUT_METHOD_PICKER -> {
|
||||
val im =
|
||||
|
@ -217,8 +217,11 @@ class KeyView(
|
||||
keyboardView.dismissActiveKeyViewReference()
|
||||
}
|
||||
} else {
|
||||
if (event.x < -0.1f * measuredWidth || event.x > 1.1f * measuredWidth
|
||||
|| event.y < -0.35f * measuredHeight || event.y > 1.35f * measuredHeight
|
||||
val parent = parent as ViewGroup
|
||||
if ((event.x < -0.1f * measuredWidth && parent.children.first() != this)
|
||||
|| (event.x > 1.1f * measuredWidth && parent.children.last() != this)
|
||||
|| event.y < -0.35f * measuredHeight
|
||||
|| event.y > 1.35f * measuredHeight
|
||||
) {
|
||||
if (!shouldBlockNextKeyCode) {
|
||||
keyboardView.dismissActiveKeyViewReference()
|
||||
@ -480,6 +483,9 @@ class KeyView(
|
||||
drawable = getDrawable(context, R.drawable.ic_space_bar)
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
}
|
||||
KeyboardMode.CHARACTERS -> {
|
||||
label = florisboard?.activeSubtype?.locale?.displayName
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -535,12 +541,15 @@ class KeyView(
|
||||
// Draw label
|
||||
val label = label
|
||||
if (label != null) {
|
||||
if (data.code == KeyCode.VIEW_NUMERIC || data.code == KeyCode.VIEW_NUMERIC_ADVANCED) {
|
||||
if (data.code == KeyCode.VIEW_NUMERIC || data.code == KeyCode.VIEW_NUMERIC_ADVANCED
|
||||
|| data.code == KeyCode.SPACE) {
|
||||
labelPaint.textSize = resources.getDimension(R.dimen.key_numeric_textSize)
|
||||
} else {
|
||||
labelPaint.textSize = resources.getDimension(R.dimen.key_textSize)
|
||||
}
|
||||
labelPaint.color = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
labelPaint.alpha = if (keyboardView.computedLayout?.mode == KeyboardMode.CHARACTERS &&
|
||||
data.code == KeyCode.SPACE) { 120 } else { 255 }
|
||||
val isPortrait =
|
||||
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
if (keyboardView.prefs.looknfeel.oneHandedMode != "off" && isPortrait) {
|
||||
|
@ -3,6 +3,8 @@ package dev.patrickgold.florisboard.ime.text.layout
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyTypeAdapter
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyVariationAdapter
|
||||
@ -25,9 +27,10 @@ class LayoutManager(private val context: Context) {
|
||||
* This method automatically fetches the current user selected keyboard layout prefs from
|
||||
* the shared preferences and sets the associations for each layout type.
|
||||
*/
|
||||
fun autoFetchAssociationsFromPrefs() {
|
||||
fun autoFetchAssociationsFromPrefs(prefs: PrefHelper) {
|
||||
// TODO: Fetch current layout preferences instead of using dev constants
|
||||
associate(LayoutType.CHARACTERS, "qwerty")
|
||||
val activeSubtype = prefs.keyboard.fetchActiveSubtype()
|
||||
associate(LayoutType.CHARACTERS, activeSubtype?.layoutName ?: "qwerty")
|
||||
associate(LayoutType.CHARACTERS_MOD, "default")
|
||||
associate(LayoutType.EXTENSION, "number_row")
|
||||
associate(LayoutType.NUMERIC, "default")
|
||||
|
@ -1,15 +1,32 @@
|
||||
package dev.patrickgold.florisboard.settings
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.*
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatSpinner
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.LocaleUtils
|
||||
import java.util.*
|
||||
|
||||
class KeyboardFragment : Fragment() {
|
||||
private lateinit var prefs: PrefHelper
|
||||
private lateinit var rootView: LinearLayout
|
||||
private lateinit var subtypeListView: LinearLayout
|
||||
private lateinit var subtypeAddButton: AppCompatButton
|
||||
private lateinit var subtypeNotConfiguredView: AppCompatTextView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
prefs = (activity as SettingsMainActivity).prefs
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
@ -17,14 +34,102 @@ class KeyboardFragment : Fragment() {
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
rootView = inflater.inflate(R.layout.settings_fragment_keyboard, container, false) as LinearLayout
|
||||
subtypeListView = rootView.findViewById(R.id.settings__keyboard__subtype_list)
|
||||
subtypeNotConfiguredView = rootView.findViewById(R.id.settings__keyboard__subtype_not_conf_warning)
|
||||
subtypeAddButton = rootView.findViewById(R.id.subtype_add_btn)
|
||||
subtypeAddButton.setOnClickListener { showAddSubtypeDialog() }
|
||||
|
||||
updateSubtypeListView()
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
transaction.replace(
|
||||
R.id.settings__keyboard__frame_container,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_keyboard)
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_correction)
|
||||
)
|
||||
transaction.commit()
|
||||
|
||||
return rootView
|
||||
}
|
||||
|
||||
private fun showAddSubtypeDialog() {
|
||||
val dialogView =
|
||||
View.inflate(context, R.layout.settings_fragment_keyboard_subtype_dialog, null)
|
||||
val languageSpinner = dialogView.findViewById<AppCompatSpinner>(R.id.language_dropdown)
|
||||
val layoutSpinner = dialogView.findViewById<AppCompatSpinner>(R.id.layout_dropdown)
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.settings__keyboard__subtype_add_title)
|
||||
setCancelable(true)
|
||||
setView(dialogView)
|
||||
setPositiveButton(R.string.settings__keyboard__subtype_add) { _, _ ->
|
||||
val languageCode = languageSpinner.selectedItem.toString()
|
||||
val layoutName = layoutSpinner.selectedItem.toString()
|
||||
prefs.keyboard.addSubtype(LocaleUtils.stringToLocale(languageCode), layoutName)
|
||||
updateSubtypeListView()
|
||||
}
|
||||
setNegativeButton(R.string.settings__keyboard__subtype_cancel) { _, _ -> }
|
||||
create()
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun showEditSubtypeDialog(id: Int) {
|
||||
var subtypeIndex = -1
|
||||
val subtypes = prefs.keyboard.subtypes
|
||||
for ((i, subtype) in subtypes.withIndex()) {
|
||||
if (subtype.id == id) {
|
||||
subtypeIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (subtypeIndex < 0) {
|
||||
return
|
||||
}
|
||||
val dialogView =
|
||||
View.inflate(context, R.layout.settings_fragment_keyboard_subtype_dialog, null)
|
||||
val languageSpinner = dialogView.findViewById<AppCompatSpinner>(R.id.language_dropdown)
|
||||
languageSpinner.setSelection((languageSpinner.adapter as ArrayAdapter<String>).getPosition(subtypes[subtypeIndex].locale.toString()))
|
||||
val layoutSpinner = dialogView.findViewById<AppCompatSpinner>(R.id.layout_dropdown)
|
||||
layoutSpinner.setSelection((layoutSpinner.adapter as ArrayAdapter<String>).getPosition(subtypes[subtypeIndex].layoutName))
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.settings__keyboard__subtype_edit_title)
|
||||
setCancelable(true)
|
||||
setView(dialogView)
|
||||
setPositiveButton(R.string.settings__keyboard__subtype_apply) { _, _ ->
|
||||
val languageCode = languageSpinner.selectedItem.toString()
|
||||
val layoutName = layoutSpinner.selectedItem.toString()
|
||||
subtypes[subtypeIndex].locale = LocaleUtils.stringToLocale(languageCode)
|
||||
subtypes[subtypeIndex].layoutName = layoutName
|
||||
prefs.keyboard.subtypes = subtypes
|
||||
updateSubtypeListView()
|
||||
}
|
||||
setNeutralButton(R.string.settings__keyboard__subtype_delete) { _, _ ->
|
||||
prefs.keyboard.removeSubtype(subtypes[subtypeIndex])
|
||||
updateSubtypeListView()
|
||||
}
|
||||
setNegativeButton(R.string.settings__keyboard__subtype_cancel) { _, _ -> }
|
||||
create()
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSubtypeListView() {
|
||||
val subtypes = prefs.keyboard.subtypes
|
||||
subtypeListView.removeAllViews()
|
||||
if (subtypes.isEmpty()) {
|
||||
subtypeNotConfiguredView.visibility = View.VISIBLE
|
||||
} else {
|
||||
subtypeNotConfiguredView.visibility = View.GONE
|
||||
for (subtype in subtypes) {
|
||||
val itemView =
|
||||
View.inflate(context, R.layout.settings_fragment_keyboard_subtype_list_item, null)
|
||||
itemView.findViewById<TextView>(R.id.titleText)?.text =
|
||||
subtype.locale.displayName
|
||||
itemView.findViewById<TextView>(R.id.captionText)?.text =
|
||||
subtype.layoutName.toUpperCase(Locale.getDefault())
|
||||
itemView.setOnClickListener { showEditSubtypeDialog(subtype.id) }
|
||||
subtypeListView.addView(itemView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
|
||||
@ -17,7 +16,7 @@ import kotlinx.coroutines.*
|
||||
|
||||
class LooknfeelFragment : Fragment(), CoroutineScope by MainScope() {
|
||||
|
||||
lateinit var keyboardView: KeyboardView
|
||||
private lateinit var keyboardView: KeyboardView
|
||||
lateinit var prefs: PrefHelper
|
||||
private lateinit var rootView: LinearLayout
|
||||
|
||||
@ -37,7 +36,7 @@ class LooknfeelFragment : Fragment(), CoroutineScope by MainScope() {
|
||||
launch(Dispatchers.Default) {
|
||||
val themeContext = ContextThemeWrapper(context, prefs.theme.getSelectedThemeResId())
|
||||
val layoutManager = LayoutManager(themeContext)
|
||||
layoutManager.autoFetchAssociationsFromPrefs()
|
||||
layoutManager.autoFetchAssociationsFromPrefs(prefs)
|
||||
keyboardView = KeyboardView(themeContext)
|
||||
keyboardView.prefs = prefs
|
||||
keyboardView.isPreviewMode = true
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
object LocaleUtils {
|
||||
fun stringToLocale(string: String): Locale {
|
||||
return when {
|
||||
string.contains("_") -> {
|
||||
val lc = string.split("_")
|
||||
Locale(lc[0], lc[1])
|
||||
}
|
||||
else -> {
|
||||
Locale(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
app/src/main/res/drawable/ic_add.xml
Normal file
5
app/src/main/res/drawable/ic_add.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
@ -9,10 +9,43 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="0dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TODO: implement language and layout selection" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settings__keyboard__subtype_not_conf_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:padding="8dp"
|
||||
android:background="@drawable/shape_rect_rounded"
|
||||
android:backgroundTint="#F8F808"
|
||||
android:text="@string/settings__keyboard__subtype_no_subtypes_configured_warning"
|
||||
android:textColor="#000000"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/settings__keyboard__subtype_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/subtype_add_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:textAllCaps="false"
|
||||
android:text="@string/settings__keyboard__subtype_add_title"
|
||||
android:drawableStart="@drawable/ic_add"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableTint="?colorAccent"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@ -20,6 +53,6 @@
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings__keyboard__frame_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -0,0 +1,60 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- TODO: improve the design and UX of this layout -->
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings__keyboard__subtype_locale"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
android:id="@+id/language_dropdown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/supported_languages"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings__keyboard__subtype_layout"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
android:id="@+id/layout_dropdown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/valid_layout_names"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,28 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/captionText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="normal"
|
||||
tools:text="Caption"/>
|
||||
|
||||
</LinearLayout>
|
19
app/src/main/res/values/layout_language_config.xml
Normal file
19
app/src/main/res/values/layout_language_config.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<!-- TODO: properly configure this temporary file -->
|
||||
<!-- NOTE: The specified layouts and languages currently do not represent what the keyboard
|
||||
really supports!! -->
|
||||
<resources>
|
||||
<string-array name="valid_layout_names">
|
||||
<item>qwerty</item>
|
||||
<item>qwertz</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="supported_languages">
|
||||
<item>en_US</item>
|
||||
<item>en_UK</item>
|
||||
<item>en_CA</item>
|
||||
<item>en_AU</item>
|
||||
<item>de_DE</item>
|
||||
<item>de_AT</item>
|
||||
<item>de_CH</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -53,8 +53,18 @@
|
||||
|
||||
<string name="settings__home__title">Welcome to %s</string>
|
||||
|
||||
<string name="settings__keyboard__title">Keyboard & Input</string>
|
||||
<string name="pref__keyboard__group_text_correction__label">Text correction</string>
|
||||
<string name="settings__keyboard__title">Keyboard & Text Correction</string>
|
||||
<string name="settings__keyboard__subtype_no_subtypes_configured_warning">It seems that you haven\'t configured any subtypes. As a fallback the subtype English/QWERTY will be used!</string>
|
||||
<string name="settings__keyboard__subtype_add">Add</string>
|
||||
<string name="settings__keyboard__subtype_add_title">Add subtype</string>
|
||||
<string name="settings__keyboard__subtype_apply">Apply</string>
|
||||
<string name="settings__keyboard__subtype_cancel">Cancel</string>
|
||||
<string name="settings__keyboard__subtype_delete">Delete</string>
|
||||
<string name="settings__keyboard__subtype_edit_title">Edit subtype</string>
|
||||
<string name="settings__keyboard__subtype_locale">Locale</string>
|
||||
<string name="settings__keyboard__subtype_layout">Keyboard layout</string>
|
||||
<string name="pref__correction__group_suggestions__label">Suggestions</string>
|
||||
<string name="pref__correction__group_corrections__label">Corrections</string>
|
||||
|
||||
<string name="settings__looknfeel__title">Look & feel</string>
|
||||
<string name="pref__looknfeel__group_layout__label">Layout</string>
|
||||
|
@ -1,9 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<input-method xmlns:android="https://schemas.android.com/apk/res/android"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:settingsActivity="dev.patrickgold.florisboard.settings.SettingsMainActivity">
|
||||
<subtype
|
||||
android:label="@string/subtype_en_US"
|
||||
android:imeSubtypeLocale="en_US"
|
||||
android:imeSubtypeMode="keyboard" />
|
||||
</input-method>
|
||||
android:isDefault="false"
|
||||
android:settingsActivity="dev.patrickgold.florisboard.settings.SettingsMainActivity" />
|
||||
|
21
app/src/main/res/xml/prefs_correction.xml
Normal file
21
app/src/main/res/xml/prefs_correction.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__group_suggestions__label">
|
||||
|
||||
<!-- TODO: implement text correction prefs -->
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__group_corrections__label">
|
||||
|
||||
<!-- TODO: implement text correction prefs -->
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
@ -2,12 +2,6 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__keyboard__group_text_correction__label">
|
||||
|
||||
<!-- TODO: implement text correction prefs -->
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
Loading…
Reference in New Issue
Block a user