Slowly getting stable

This commit is contained in:
Nehemiah of Zebulun 2023-12-03 19:58:54 -05:00
parent 6c59ee4d82
commit 92a4ac541c
13 changed files with 278 additions and 144 deletions

View File

@ -15,7 +15,7 @@ interface IME {
current: Int? = 0 current: Int? = 0
) )
fun onWords(words: List<Word>) fun onWords(words: List<Word>, capMode: Int?)
fun onNextWord() fun onNextWord()
@ -23,6 +23,8 @@ interface IME {
fun onWordSelected(word: Word) fun onWordSelected(word: Word)
fun onDeleteWord(word: Word)
fun onCommit(text: CharSequence = "", beforeCursor: Int = 0, afterCursor: Int = 0) fun onCommit(text: CharSequence = "", beforeCursor: Int = 0, afterCursor: Int = 0)
fun onCompose(text: CharSequence) fun onCompose(text: CharSequence)

View File

@ -2,8 +2,10 @@ package net.mezimmah.wkt9
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.inputmethodservice.InputMethodService import android.inputmethodservice.InputMethodService
import android.provider.Settings import android.provider.Settings
import android.text.InputType
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
@ -12,14 +14,15 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.view.inputmethod.InputMethodSubtype import android.view.inputmethod.InputMethodSubtype
import androidx.preference.PreferenceManager
import net.mezimmah.wkt9.entity.Word import net.mezimmah.wkt9.entity.Word
import net.mezimmah.wkt9.inputhandler.IdleInputHandler import net.mezimmah.wkt9.inputhandler.IdleInputHandler
import net.mezimmah.wkt9.inputhandler.InputHandler import net.mezimmah.wkt9.inputhandler.InputHandler
import net.mezimmah.wkt9.inputhandler.LetterInputHandler import net.mezimmah.wkt9.inputhandler.LetterInputHandler
import net.mezimmah.wkt9.inputhandler.NumberInputHandler import net.mezimmah.wkt9.inputhandler.NumberInputHandler
import net.mezimmah.wkt9.inputhandler.WordInputHandler import net.mezimmah.wkt9.inputhandler.WordInputHandler
import net.mezimmah.wkt9.inputmode.InputModeManager
import net.mezimmah.wkt9.inputmode.InputMode import net.mezimmah.wkt9.inputmode.InputMode
import net.mezimmah.wkt9.inputmode.InputModeManager
import net.mezimmah.wkt9.keypad.Event import net.mezimmah.wkt9.keypad.Event
import net.mezimmah.wkt9.keypad.Key import net.mezimmah.wkt9.keypad.Key
import net.mezimmah.wkt9.keypad.KeyEventStat import net.mezimmah.wkt9.keypad.KeyEventStat
@ -45,6 +48,8 @@ class WKT9IME: IME, InputMethodService() {
private var selectionStart: Int = 0 private var selectionStart: Int = 0
private var selectionEnd: Int = 0 private var selectionEnd: Int = 0
private var capMode: Int? = null
override fun onCandidates(candidates: ArrayList<CharSequence>, current: Int?) { override fun onCandidates(candidates: ArrayList<CharSequence>, current: Int?) {
// this.candidates?.load(candidates, current) // this.candidates?.load(candidates, current)
} }
@ -103,6 +108,10 @@ class WKT9IME: IME, InputMethodService() {
deleteText(beforeCursor, afterCursor) deleteText(beforeCursor, afterCursor)
} }
override fun onDeleteWord(word: Word) {
inputHandler?.onDeleteWord(word)
}
override fun onGetTextBeforeCursor(n: Int): CharSequence? { override fun onGetTextBeforeCursor(n: Int): CharSequence? {
return this.currentInputConnection?.getTextBeforeCursor(n, 0) return this.currentInputConnection?.getTextBeforeCursor(n, 0)
} }
@ -264,12 +273,21 @@ class WKT9IME: IME, InputMethodService() {
else showStatusIcon(icon) else showStatusIcon(icon)
} }
override fun onWords(words: List<Word>) { override fun onWords(words: List<Word>, capMode: Int?) {
this.capMode = capMode
wordsView?.words = words wordsView?.words = words
} }
override fun onWordSelected(word: Word) { override fun onWordSelected(word: Word) {
this.onCompose(word.word) val compose = when (capMode) {
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS -> word.word.uppercase()
InputType.TYPE_TEXT_FLAG_CAP_WORDS,
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> word.word.replaceFirstChar { it.uppercase() }
else -> word.word
}
this.onCompose(compose)
this.inputHandler?.onWordSelected(word) this.inputHandler?.onWordSelected(word)
} }
@ -301,7 +319,15 @@ class WKT9IME: IME, InputMethodService() {
private fun switchInputMode(mode: InputMode) { private fun switchInputMode(mode: InputMode) {
inputHandler = when(mode) { inputHandler = when(mode) {
InputMode.Word -> WordInputHandler(this, this, locale) InputMode.Word -> WordInputHandler(this, this, locale)
InputMode.Letter -> LetterInputHandler(this, this, locale)
InputMode.Letter -> {
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val timeout = prefs.getString(getString(R.string.compose_timeout), "700")
val composeTimeout = timeout?.toLong() ?: 700L
timeout?.let { LetterInputHandler(this, this, locale, composeTimeout) }
}
InputMode.Number -> NumberInputHandler(this, this) InputMode.Number -> NumberInputHandler(this, this)
else -> IdleInputHandler(this, this) else -> IdleInputHandler(this, this)
} }

View File

@ -11,8 +11,8 @@ interface WordDao {
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(vararg words: Word) suspend fun insert(vararg words: Word)
@Query("DELETE FROM word WHERE word = :word AND locale = :locale") @Query("DELETE FROM word WHERE id = :id")
fun delete(word: String, locale: String) fun delete(id: Int)
@Query("SELECT * FROM word WHERE code LIKE :code || '%' AND locale = :locale " + @Query("SELECT * FROM word WHERE code LIKE :code || '%' AND locale = :locale " +
"ORDER BY length, weight DESC LIMIT :limit") "ORDER BY length, weight DESC LIMIT :limit")
@ -20,4 +20,7 @@ interface WordDao {
@Query("UPDATE word SET weight = weight + 1 WHERE id=:id") @Query("UPDATE word SET weight = weight + 1 WHERE id=:id")
suspend fun increaseWeight(id: Int) suspend fun increaseWeight(id: Int)
@Query("SELECT * FROM word WHERE word = :word AND locale = :locale COLLATE NOCASE")
suspend fun selectWord(word: String, locale: String): Word?
} }

View File

@ -3,79 +3,73 @@ package net.mezimmah.wkt9.inputhandler
import android.text.InputType import android.text.InputType
import android.view.KeyEvent import android.view.KeyEvent
import net.mezimmah.wkt9.WKT9IME import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.IME
import net.mezimmah.wkt9.inputmode.InputMode
import net.mezimmah.wkt9.inputmode.TextPositionInfo
import net.mezimmah.wkt9.keypad.Command
import net.mezimmah.wkt9.keypad.Key import net.mezimmah.wkt9.keypad.Key
import net.mezimmah.wkt9.keypad.KeyEventStat
import net.mezimmah.wkt9.keypad.KeyLayout
import net.mezimmah.wkt9.keypad.Keypad import net.mezimmah.wkt9.keypad.Keypad
import java.util.Locale
open class DefaultInputHandler( open class DefaultInputHandler(
private val wkt9: IME, private val wkt9: WKT9IME
private val context: WKT9IME
) { ) {
private val capModes = listOf(
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES,
InputType.TYPE_TEXT_FLAG_CAP_WORDS,
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
null
)
private var currentCapMode: Int? = null
protected val punctuationMarks = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ")
protected val tag = "WKT9" protected val tag = "WKT9"
protected val keypad: Keypad = Keypad()
protected var keypad: Keypad = Keypad() protected var wordStart: Boolean = true
protected var capMode: Int = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES protected var sentenceStart: Boolean = true
protected open fun capMode(key: Key): Int? { init {
val modes = listOf( wkt9.currentInputEditorInfo?.let {
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, val inputType = it.inputType
InputType.TYPE_TEXT_FLAG_CAP_WORDS, val typeFlags = inputType.and(InputType.TYPE_MASK_FLAGS)
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
null if (typeFlags.and(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) == InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) {
) currentCapMode = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
var index = modes.indexOf(capMode) } else if (typeFlags.and(InputType.TYPE_TEXT_FLAG_CAP_WORDS) == InputType.TYPE_TEXT_FLAG_CAP_WORDS) {
currentCapMode = InputType.TYPE_TEXT_FLAG_CAP_WORDS
} else if (typeFlags.and(InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) == InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) {
currentCapMode = InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
}
}
}
protected fun effectiveCapMode(): Int? {
return when (currentCapMode) {
InputType.TYPE_TEXT_FLAG_CAP_WORDS -> {
if (wordStart) InputType.TYPE_TEXT_FLAG_CAP_WORDS
else null
}
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> {
if (sentenceStart) InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
else null
}
else -> currentCapMode
}
}
protected open fun toggleCapMode(key: Key) {
var index = capModes.indexOf(currentCapMode)
when (key) { when (key) {
Key.B2 -> { Key.B2 -> {
if (index == 0) index = modes.count() if (index == 0) index = capModes.count()
index-- index--
} }
else -> index++ else -> index++
} }
return modes[index % modes.count()] currentCapMode = capModes[index % capModes.count()]
}
protected open fun finalizeWordOrSentence(stats: KeyEventStat) {
val candidates = ArrayList<CharSequence>()
wkt9.onCandidates(
candidates = candidates,
current = stats.repeats % candidates.count()
)
}
protected open fun getTextPositionInfo(text: CharSequence): TextPositionInfo {
val trimmed = text.trimEnd()
val regex = "[.!?]$".toRegex()
val startSentence = text.isEmpty() || regex.containsMatchIn(trimmed)
val startWord = text.isEmpty() || (startSentence || trimmed.length < text.length)
return TextPositionInfo(
startSentence = startSentence,
startWord = startWord
)
}
protected fun getDefaultCapMode(typeFlags: Int): Int? {
val modes = listOf(
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES,
InputType.TYPE_TEXT_FLAG_CAP_WORDS,
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
)
modes.forEach {
if (typeFlags.and(it) == it) return it
}
return null
} }
protected fun triggerKeyEvent(keyCode: Int) { protected fun triggerKeyEvent(keyCode: Int) {

View File

@ -6,6 +6,7 @@ import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import net.mezimmah.wkt9.WKT9IME import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.IME import net.mezimmah.wkt9.IME
import net.mezimmah.wkt9.R
import net.mezimmah.wkt9.entity.Word import net.mezimmah.wkt9.entity.Word
import net.mezimmah.wkt9.keypad.Command import net.mezimmah.wkt9.keypad.Command
import net.mezimmah.wkt9.keypad.Key import net.mezimmah.wkt9.keypad.Key
@ -15,12 +16,14 @@ import java.util.Locale
class IdleInputHandler( class IdleInputHandler(
val ime: IME, val ime: IME,
val wkt9: WKT9IME, val wkt9: WKT9IME,
) : DefaultInputHandler(ime, wkt9), InputHandler { ) : DefaultInputHandler(wkt9), InputHandler {
init {
wkt9.showStatusIcon(R.drawable.idle_input)
}
override fun onFinishComposing() {} override fun onFinishComposing() {}
override fun onLongClickCandidate(text: String) { override fun onDeleteWord(word: Word) {}
TODO("Not yet implemented")
}
override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) { override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) {
when (command) { when (command) {

View File

@ -8,9 +8,9 @@ import net.mezimmah.wkt9.keypad.KeyEventStat
import java.util.Locale import java.util.Locale
interface InputHandler { interface InputHandler {
fun onFinishComposing() fun onDeleteWord(word: Word)
fun onLongClickCandidate(text: String) fun onFinishComposing()
fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat)

View File

@ -30,23 +30,22 @@ class LetterInputHandler(
val ime: IME, val ime: IME,
private var wkt9: WKT9IME, private var wkt9: WKT9IME,
private var locale: Locale, private var locale: Locale,
): SpellCheckerSession.SpellCheckerSessionListener, DefaultInputHandler(ime, wkt9), InputHandler { private var composeTimeout: Long
): SpellCheckerSession.SpellCheckerSessionListener, DefaultInputHandler(wkt9), InputHandler {
private val db = AppDatabase.getInstance(wkt9) private val db = AppDatabase.getInstance(wkt9)
private val wordDao = db.getWordDao() private val wordDao = db.getWordDao()
private val word = StringBuilder()
private var lastKey: Key? = null private var lastKey: Key? = null
private var repeats: Int = 0 private var repeats: Int = 0
private var lastComposeChar: Char? = null
private var lastIcon: Int? = null
private var spellCheckerSession: SpellCheckerSession? = null private var spellCheckerSession: SpellCheckerSession? = null
private var sentenceStart: Boolean = false
private var wordStart: Boolean = false
private val timeoutScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
private var timeoutJob: Job? = null private var timeoutJob: Job? = null
private val content = StringBuilder()
init { init {
val textServiceManager = wkt9.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE) as TextServicesManager val textServiceManager = wkt9.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE) as TextServicesManager
@ -56,44 +55,67 @@ class LetterInputHandler(
this, this,
false false
) )
updateIcon()
} }
override fun finalizeWordOrSentence(stats: KeyEventStat) { private fun finalizeWordOrSentence(stats: KeyEventStat) {
if (word.isNotEmpty()) storeWord()
timeoutJob?.cancel() timeoutJob?.cancel()
val ends = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ") val index = stats.repeats % punctuationMarks.count()
val index = stats.repeats % ends.count() val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % punctuationMarks.count() else null
val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % ends.count() else null
var beforeCursor = 0 var beforeCursor = 0
if (lastIndex != null) beforeCursor += ends[lastIndex].length if (lastIndex != null) beforeCursor += punctuationMarks[lastIndex].length
wkt9.onCommit(ends[index], beforeCursor) wordStart = true
sentenceStart = index in 1..3
wkt9.onCommit(punctuationMarks[index], beforeCursor)
updateIcon()
}
private fun storeWord() {
val str = word.toString()
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
word.clear()
scope.launch {
val word = Word(
word = str,
code = keypad.getCodeForWord(str),
weight = 0,
length = str.length,
locale = locale.language
)
val result = wordDao.selectWord(str, locale.language)
if (result == null) wordDao.insert(word)
}
} }
override fun onSwitchLocale(locale: Locale) { override fun onSwitchLocale(locale: Locale) {
this.locale = locale this.locale = locale
} }
override fun onGetSuggestions(results: Array<out SuggestionsInfo>?) { override fun onDeleteWord(word: Word) {}
TODO("Not yet implemented") override fun onGetSuggestions(results: Array<out SuggestionsInfo>?) {}
} override fun onGetSentenceSuggestions(results: Array<out SentenceSuggestionsInfo>?) {}
override fun onFinishComposing() {}
override fun onGetSentenceSuggestions(results: Array<out SentenceSuggestionsInfo>?) { override fun toggleCapMode(key: Key) {
TODO("Not yet implemented") super.toggleCapMode(key)
}
override fun onFinishComposing() { updateIcon()
}
override fun onLongClickCandidate(text: String) {
TODO("Not yet implemented")
} }
override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) { override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) {
when (command) { when (command) {
Command.CAP_MODE -> capMode(key) Command.CAP_MODE -> toggleCapMode(key)
Command.CHARACTER -> composeCharacter(key, stats) Command.CHARACTER -> composeCharacter(key)
Command.DELETE -> delete() Command.DELETE -> delete()
Command.INPUT_MODE -> inputMode(key) Command.INPUT_MODE -> inputMode(key)
Command.NUMBER -> triggerOriginalKeyEvent(key) Command.NUMBER -> triggerOriginalKeyEvent(key)
@ -106,35 +128,75 @@ class LetterInputHandler(
override fun onWordSelected(word: Word) {} override fun onWordSelected(word: Word) {}
private fun composeCharacter(key: Key, stats: KeyEventStat) { private fun composeCharacter(key: Key) {
if (lastKey == key) repeats++ val composing = timeoutJob?.isActive ?: false
else {
wkt9.onCommit()
lastKey = key timeoutJob?.cancel()
repeats = 0
if (lastKey == key) {
repeats++
word.deleteAt(word.length - 1)
} else {
resetKey(key)
if (composing) finishComposingChar()
} }
val layout = KeyLayout.chars[key] ?: return val layout = KeyLayout.chars[key] ?: return
val index = repeats % layout.count() val index = repeats % layout.count()
val char = when(effectiveCapMode()) {
null -> layout[index].toString()
else -> layout[index].uppercase()
}
wkt9.onCompose(layout[index].toString()) lastComposeChar = layout[index]
word.append(char)
wkt9.onCompose(char)
setComposeTimeout() setComposeTimeout()
} }
private fun resetKey(key: Key? = null) {
lastKey = key
repeats = 0
}
private fun finishComposingChar() {
val wordDelimiters = listOf(' ', ',', ':', ';')
val sentenceDelimiters = listOf('.', '?', '!')
wkt9.onCommit()
if (sentenceDelimiters.contains(lastComposeChar)) {
sentenceStart = true
wordStart = true
} else if (wordDelimiters.contains(lastComposeChar)) {
sentenceStart = false
wordStart = true
} else {
wordStart = false
sentenceStart = false
}
updateIcon()
}
private fun setComposeTimeout() { private fun setComposeTimeout() {
timeoutJob?.cancel() val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
timeoutJob = timeoutScope.launch { timeoutJob = scope.launch {
delay(400L) delay(composeTimeout)
wkt9.onCommit("") resetKey()
finishComposingChar()
lastKey = null
repeats = 0
} }
} }
private fun delete() { private fun delete() {
if (word.isNotEmpty()) word.deleteAt(word.length - 1)
resetKey()
if (timeoutJob?.isActive == true) { if (timeoutJob?.isActive == true) {
timeoutJob?.cancel() timeoutJob?.cancel()
wkt9.onCompose("") wkt9.onCompose("")
@ -149,14 +211,18 @@ class LetterInputHandler(
} }
private fun updateIcon() { private fun updateIcon() {
val icon = when (capMode) { val icon = when (effectiveCapMode()) {
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS -> R.drawable.letter_upper InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS -> R.drawable.letter_upper
InputType.TYPE_TEXT_FLAG_CAP_WORDS, InputType.TYPE_TEXT_FLAG_CAP_WORDS,
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> if (wordStart) R.drawable.letter_cap else R.drawable.letter_lower InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> R.drawable.letter_cap
else -> R.drawable.letter_lower else -> R.drawable.letter_lower
} }
// wkt9.onUpdateStatusIcon(icon) if (icon == lastIcon) return
wkt9.onUpdateStatusIcon(icon)
lastIcon = icon
} }
} }
// //

View File

@ -4,6 +4,7 @@ import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import net.mezimmah.wkt9.WKT9IME import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.IME import net.mezimmah.wkt9.IME
import net.mezimmah.wkt9.R
import net.mezimmah.wkt9.entity.Word import net.mezimmah.wkt9.entity.Word
import net.mezimmah.wkt9.inputmode.InputMode import net.mezimmah.wkt9.inputmode.InputMode
import net.mezimmah.wkt9.keypad.Command import net.mezimmah.wkt9.keypad.Command
@ -17,9 +18,13 @@ class NumberInputHandler(
) : InputHandler { ) : InputHandler {
private val tag = "WKT9" private val tag = "WKT9"
init {
wkt9.showStatusIcon(R.drawable.number_input)
}
// We don't need to implement methods below // We don't need to implement methods below
override fun onFinishComposing() {} override fun onFinishComposing() {}
override fun onLongClickCandidate(text: String) {} override fun onDeleteWord(word: Word) {}
override fun onSwitchLocale(locale: Locale) {} override fun onSwitchLocale(locale: Locale) {}
override fun onWordSelected(word: Word) {} override fun onWordSelected(word: Word) {}

View File

@ -1,6 +1,7 @@
package net.mezimmah.wkt9.inputhandler package net.mezimmah.wkt9.inputhandler
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.text.InputType
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -23,7 +24,7 @@ class WordInputHandler(
val ime: IME, val ime: IME,
private var wkt9: WKT9IME, private var wkt9: WKT9IME,
private var locale: Locale, private var locale: Locale,
) : DefaultInputHandler(ime, wkt9), InputHandler { ) : DefaultInputHandler(wkt9), InputHandler {
private val codeword = StringBuilder() private val codeword = StringBuilder()
private var staleCodeword = false private var staleCodeword = false
private var lastSelectedWord: Word? = null private var lastSelectedWord: Word? = null
@ -35,11 +36,17 @@ class WordInputHandler(
private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var queryJob: Job? = null private var queryJob: Job? = null
override fun capMode(key: Key): Int? { init {
return super.capMode(key) updateIcon()
} }
override fun finalizeWordOrSentence(stats: KeyEventStat) { override fun toggleCapMode(key: Key) {
super.toggleCapMode(key)
updateIcon()
}
private fun finalizeWordOrSentence(stats: KeyEventStat) {
val ends = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ") val ends = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ")
val index = stats.repeats % ends.count() val index = stats.repeats % ends.count()
val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % ends.count() else null val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % ends.count() else null
@ -48,10 +55,24 @@ class WordInputHandler(
if (lastIndex != null) beforeCursor += ends[lastIndex].length if (lastIndex != null) beforeCursor += ends[lastIndex].length
wkt9.onCommit(ends[index], beforeCursor) wkt9.onCommit(ends[index], beforeCursor)
sentenceStart = index in 1..3
updateIcon()
}
override fun onDeleteWord(word: Word) {
ioScope.launch {
wordDao.delete(word.id)
handleCodewordChange(codeword)
}
} }
override fun onSwitchLocale(locale: Locale) { override fun onSwitchLocale(locale: Locale) {
this.locale = locale this.locale = locale
updateIcon()
} }
override fun onFinishComposing() { override fun onFinishComposing() {
@ -63,17 +84,9 @@ class WordInputHandler(
lastSelectedWord = null lastSelectedWord = null
} }
override fun onLongClickCandidate(text: String) {
ioScope.launch {
wordDao.delete(text, locale.language)
handleCodewordChange(codeword)
}
}
override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) { override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) {
when (command) { when (command) {
// Command.CAP_MODE -> capMode(key) Command.CAP_MODE -> toggleCapMode(key)
Command.CHARACTER -> buildCodeword(key) Command.CHARACTER -> buildCodeword(key)
Command.DELETE -> delete() Command.DELETE -> delete()
Command.ENTER -> enter(key) Command.ENTER -> enter(key)
@ -109,7 +122,8 @@ class WordInputHandler(
handleCodewordChange(codeword) handleCodewordChange(codeword)
} else if (codeword.isNotEmpty()) { } else if (codeword.isNotEmpty()) {
codeword.clear() codeword.clear()
wkt9.onCompose("") wkt9.onCommit()
wkt9.onDeleteText(1)
} else { } else {
wkt9.onDeleteText(1) wkt9.onDeleteText(1)
} }
@ -129,7 +143,7 @@ class WordInputHandler(
// The codeword is stale when it does not yield any candidates in the DB // The codeword is stale when it does not yield any candidates in the DB
staleCodeword = words.isEmpty() staleCodeword = words.isEmpty()
if (words.isNotEmpty()) wkt9.onWords(words) if (words.isNotEmpty()) wkt9.onWords(words, effectiveCapMode())
} }
} }
@ -154,15 +168,16 @@ class WordInputHandler(
@SuppressLint("DiscouragedApi") @SuppressLint("DiscouragedApi")
private fun updateIcon() { private fun updateIcon() {
// val mode = when (capMode) { val mode = when (effectiveCapMode()) {
// InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS -> "upper" InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS -> "upper"
// InputType.TYPE_TEXT_FLAG_CAP_WORDS, InputType.TYPE_TEXT_FLAG_CAP_WORDS,
// InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> if (wordStart) "cap" else "lower" InputType.TYPE_TEXT_FLAG_CAP_SENTENCES -> "cap"
// else -> "lower" else -> "lower"
// } }
// val name = "word_${locale}_${mode}".replace('-', '_').lowercase()
// val icon = context.resources.getIdentifier(name, "drawable", context.packageName)
// wkt9.onUpdateStatusIcon(icon) val name = "word_${locale}_${mode}".replace('-', '_').lowercase()
val icon = wkt9.resources.getIdentifier(name, "drawable", wkt9.packageName)
wkt9.onUpdateStatusIcon(icon)
} }
} }

View File

@ -133,8 +133,7 @@ enum class Key(
), ),
CommandMapping( CommandMapping(
events = listOf(Event.keyDown), inputModes = listOf(InputMode.Number, InputMode.Idle),
inputModes = listOf(InputMode.Number),
overrideConsume = true, overrideConsume = true,
consume = null consume = null
) )

View File

@ -1,10 +1,8 @@
package net.mezimmah.wkt9.layout package net.mezimmah.wkt9.layout
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.PendingIntent.getActivity
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import android.view.View import android.view.View
import android.widget.HorizontalScrollView import android.widget.HorizontalScrollView
@ -16,7 +14,6 @@ import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.entity.Word import net.mezimmah.wkt9.entity.Word
class Words(context: Context, attributeSet: AttributeSet): HorizontalScrollView(context, attributeSet), View.OnClickListener, View.OnLongClickListener { class Words(context: Context, attributeSet: AttributeSet): HorizontalScrollView(context, attributeSet), View.OnClickListener, View.OnLongClickListener {
private val tag = "WKT9"
private var wkt9: WKT9IME private var wkt9: WKT9IME
private var wordCount: Int = 0 private var wordCount: Int = 0
private var current: Int = 0 private var current: Int = 0
@ -94,7 +91,19 @@ class Words(context: Context, attributeSet: AttributeSet): HorizontalScrollView(
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
Log.d(tag, "We need to delete this word from the db") val words = this.words ?: return true
val wordContainer = findViewById<LinearLayout>(R.id.words)
for (i in 0 until wordCount) {
val child: View = wordContainer.getChildAt(i)
if (v != child) continue
wordContainer.removeView(child)
wkt9.onDeleteWord(words[i])
break
}
return true return true
} }

View File

@ -29,6 +29,6 @@
<item>400</item> <item>400</item>
<item>600</item> <item>600</item>
<item>800</item> <item>800</item>
<item>900</item> <item>1000</item>
</string-array> </string-array>
</resources> </resources>

View File

@ -20,6 +20,12 @@
android:languageTag="es-ES" android:languageTag="es-ES"
android:imeSubtypeMode="keyboard" /> android:imeSubtypeMode="keyboard" />
<subtype
android:label="Spanish AR"
android:imeSubtypeLocale="es_AR"
android:languageTag="es-AR"
android:imeSubtypeMode="keyboard" />
<subtype <subtype
android:label="German DE" android:label="German DE"
android:imeSubtypeLocale="de_DE" android:imeSubtypeLocale="de_DE"
@ -32,4 +38,10 @@
android:languageTag="pt-PT" android:languageTag="pt-PT"
android:imeSubtypeMode="keyboard" /> android:imeSubtypeMode="keyboard" />
<subtype
android:label="Portuguese BR"
android:imeSubtypeLocale="pt_BR"
android:languageTag="pt-BR"
android:imeSubtypeMode="keyboard" />
</input-method> </input-method>