diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/candidate/CandidateTypes.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/candidate/CandidateTypes.kt new file mode 100644 index 00000000..6375214f --- /dev/null +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/candidate/CandidateTypes.kt @@ -0,0 +1,3 @@ +package com.kazumaproject.markdownhelperkeyboard.converter.candidate + +const val QWERTY_GLIDE_CANDIDATE_TYPE: Byte = 45 diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/glide/QwertyGlideDecoder.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/glide/QwertyGlideDecoder.kt index a60fe9b2..8f2cc977 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/glide/QwertyGlideDecoder.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/glide/QwertyGlideDecoder.kt @@ -1,6 +1,7 @@ package com.kazumaproject.markdownhelperkeyboard.converter.glide import com.kazumaproject.markdownhelperkeyboard.converter.candidate.Candidate +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.QWERTY_GLIDE_CANDIDATE_TYPE import com.kazumaproject.qwerty_keyboard.glide.QwertyInputPointers import com.kazumaproject.qwerty_keyboard.glide.QwertyKeyboardProximityInfo import kotlin.math.ceil @@ -113,7 +114,7 @@ class QwertyGlideDecoder( .map { scoredWord -> Candidate( string = scoredWord.entry.word, - type = 36.toByte(), + type = QWERTY_GLIDE_CANDIDATE_TYPE, length = scoredWord.entry.word.length.toUByte(), score = (scoredWord.totalCost * 1000f).toInt().coerceAtLeast(1) ) diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt index 7f5a63df..a8887312 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt @@ -154,6 +154,7 @@ import com.kazumaproject.markdownhelperkeyboard.clipboard_history.database.Clipb import com.kazumaproject.markdownhelperkeyboard.clipboard_history.database.ItemType import com.kazumaproject.markdownhelperkeyboard.converter.candidate.BunsetsuCandidateResult import com.kazumaproject.markdownhelperkeyboard.converter.candidate.Candidate +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.QWERTY_GLIDE_CANDIDATE_TYPE import com.kazumaproject.markdownhelperkeyboard.converter.candidate.ZenzCandidate import com.kazumaproject.markdownhelperkeyboard.converter.engine.EnglishEngine import com.kazumaproject.markdownhelperkeyboard.converter.engine.KanaKanjiEngine @@ -211,9 +212,6 @@ import com.kazumaproject.markdownhelperkeyboard.setting_activity.circular_slot.C import com.kazumaproject.markdownhelperkeyboard.short_cut.ShortcutType import com.kazumaproject.markdownhelperkeyboard.variant.AppVariantConfig import com.kazumaproject.qwerty_keyboard.ui.QWERTYKeyboardView -import com.kazumaproject.qwerty_keyboard.glide.QwertyGlideInputListener -import com.kazumaproject.qwerty_keyboard.glide.QwertyInputPointers -import com.kazumaproject.qwerty_keyboard.glide.QwertyKeyboardProximityInfo import com.kazumaproject.symbol_keyboard.CustomSymbolKeyboardView import com.kazumaproject.tenkey.TenKey import com.kazumaproject.tenkey.extensions.getDakutenFlickLeft @@ -597,6 +595,8 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, private var qwertyRomajiHankakuSymbolPreference: Boolean? = false private var qwertyShowPopupWindowPreference: Boolean? = true private var qwertyGlideInputPreference: Boolean = false + private var qwertyGlideCommitPreviousCandidateOnNewGlidePreference: Boolean = false + private var qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference: Boolean = false private var qwertyShowCursorButtonsPreference: Boolean? = false private var qwertyShowNumberButtonsPreference: Boolean? = false private var qwertyShowSwitchRomajiEnglishPreference: Boolean? = false @@ -739,6 +739,7 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, private var qwertySwitchNumberKeyWithoutNumberPreference: Boolean? = false private var qwertyGlideInputCoordinator: QwertyGlideInputCoordinator? = null private var suppressNextQwertyGlideSuggestionRefresh: Boolean = false + private var currentQwertyGlideCompositionText: String? = null private var customRomajiZenkakuConversionEnablePreference: Boolean? = true @@ -1292,9 +1293,14 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, qwertyShowSwitchRomajiEnglishPreference = preferences.qwertyShowSwitchRomajiEnglishPreference qwertyGlideInputPreference = preferences.qwertyGlideInputPreference + qwertyGlideCommitPreviousCandidateOnNewGlidePreference = + preferences.qwertyGlideCommitPreviousCandidateOnNewGlidePreference + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference = + preferences.qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference if (qwertyGlidePreferenceChanged) { qwertyGlideInputCoordinator?.cancelPending() englishEngine.invalidateQwertyGlideCache() + currentQwertyGlideCompositionText = null } if (preferences.qwertyGlideInputPreference) { englishEngine.warmUpQwertyGlideDecoderAsync() @@ -13286,6 +13292,9 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, onFinalCandidates = { candidates -> showQwertyGlideCandidates(candidates, applyFirstCandidate = true) }, + onGlideStarted = { + commitPreviousQwertyGlideCandidateOnNewGlideIfNeeded() + }, onCancel = {}, onProcessingChanged = { isProcessing -> setSuggestionProgressVisible( @@ -13857,6 +13866,13 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, clearDeletedBuffer() refreshEditHistoryUi() val first = candidates.first() + currentQwertyGlideCompositionText = if ( + first.type == QWERTY_GLIDE_CANDIDATE_TYPE + ) { + first.string + } else { + null + } suppressNextQwertyGlideSuggestionRefresh = true _inputString.update { first.string } val spannable = createSpannableWithTail(first.string) @@ -13878,6 +13894,35 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, } } + private fun commitPreviousQwertyGlideCandidateOnNewGlideIfNeeded() { + val firstCandidate = suggestionAdapter?.suggestions?.firstOrNull() + val decision = QwertyGlideCommitPolicy.resolvePreviousGlideCommitDecision( + qwertyGlideInputPreference = qwertyGlideInputPreference, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference = + qwertyGlideCommitPreviousCandidateOnNewGlidePreference, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference = + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference, + inputString = inputString.value, + stringInTail = stringInTail.get(), + currentQwertyRomajiModeForSession = currentQwertyRomajiModeForSession, + firstCandidate = firstCandidate, + currentQwertyGlideCompositionText = currentQwertyGlideCompositionText + ) + if (decision !is QwertyGlidePreviousCandidateCommitDecision.Commit) return + + beginBatchEdit() + try { + setComposingText("", 0) + finishComposingText() + commitText(decision.commitText, 1) + } finally { + endBatchEdit() + } + stringInTail.set("") + currentQwertyGlideCompositionText = null + resetFlagsSuggestionClick() + } + private suspend fun setSymbols(mainView: MainLayoutBinding) { coroutineScope { if (cachedEmoji == null || cachedEmoticons == null || cachedSymbols == null) { @@ -13992,6 +14037,14 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, if (insertString.isNotEmpty()) { isHenkan.set(false) henkanPressedWithBunsetsuDetect = false + val qwertyGlideDecision = QwertyGlideCommitPolicy.resolveTapCommitDecision( + candidate = candidate, + insertString = insertString + ) + if (qwertyGlideDecision is QwertyGlideTapCommitDecision.CommitQwertyGlideCandidate) { + commitQwertyGlideCandidate(candidate) + return + } processCandidate( candidate = candidate, insertString = insertString, @@ -14682,10 +14735,32 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, commitAndClearInput(candidateString) } + private fun commitQwertyGlideCandidate(candidate: Candidate) { + beginBatchEdit() + try { + setComposingText("", 0) + finishComposingText() + commitText(candidate.string, 1) + } finally { + endBatchEdit() + } + stringInTail.set("") + currentQwertyGlideCompositionText = null + resetFlagsSuggestionClick() + } + private fun processCandidate( candidate: Candidate, insertString: String, currentInputMode: InputMode, position: Int ) { Timber.d("processCandidate ${candidate.type.toInt()} ${insertString.length == candidate.length.toInt()}") + val qwertyGlideDecision = QwertyGlideCommitPolicy.resolveTapCommitDecision( + candidate = candidate, + insertString = insertString + ) + if (qwertyGlideDecision is QwertyGlideTapCommitDecision.CommitQwertyGlideCandidate) { + commitQwertyGlideCandidate(candidate) + return + } when (candidate.type.toInt()) { 15 -> { val readingCorrection = candidate.string.correctReading() diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/ImePreferencesSnapshot.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/ImePreferencesSnapshot.kt index ee22ba9f..493f9947 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/ImePreferencesSnapshot.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/ImePreferencesSnapshot.kt @@ -33,6 +33,8 @@ data class ImePreferencesSnapshot( val qwertyShowNumberButtonsPreference: Boolean, val qwertyShowSwitchRomajiEnglishPreference: Boolean, val qwertyGlideInputPreference: Boolean, + val qwertyGlideCommitPreviousCandidateOnNewGlidePreference: Boolean, + val qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference: Boolean, val qwertyShowPopupWindowPreference: Boolean, val qwertyEnableFlickUpPreference: Boolean, val qwertyEnableFlickDownPreference: Boolean, @@ -203,6 +205,10 @@ data class ImePreferencesSnapshot( qwertyShowSwitchRomajiEnglishPreference = appPreference.qwerty_show_switch_romaji_english_button ?: true, qwertyGlideInputPreference = appPreference.qwerty_glide_input_preference, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference = + appPreference.qwerty_glide_commit_previous_candidate_on_new_glide_preference, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference = + appPreference.qwerty_glide_insert_space_after_committing_previous_candidate_preference, qwertyShowPopupWindowPreference = appPreference.qwerty_show_popup_window ?: true, qwertyEnableFlickUpPreference = appPreference.qwerty_enable_flick_up_preference ?: false, diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicy.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicy.kt new file mode 100644 index 00000000..cf754b95 --- /dev/null +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicy.kt @@ -0,0 +1,100 @@ +package com.kazumaproject.markdownhelperkeyboard.ime_service + +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.Candidate +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.QWERTY_GLIDE_CANDIDATE_TYPE + +sealed class QwertyGlideTapCommitDecision { + data class CommitQwertyGlideCandidate(val commitText: String) : QwertyGlideTapCommitDecision() + data class UseStandardCandidateFlow(val tailForPartialOrExcess: String?) : + QwertyGlideTapCommitDecision() +} + +sealed class QwertyGlidePreviousCandidateCommitDecision { + data class Commit(val commitText: String) : QwertyGlidePreviousCandidateCommitDecision() + data object Skip : QwertyGlidePreviousCandidateCommitDecision() +} + +object QwertyGlideCommitPolicy { + fun isQwertyGlideCandidate(candidate: Candidate): Boolean { + return candidate.type == QWERTY_GLIDE_CANDIDATE_TYPE + } + + fun resolveTapCommitDecision( + candidate: Candidate, + insertString: String + ): QwertyGlideTapCommitDecision { + if (isQwertyGlideCandidate(candidate)) { + return QwertyGlideTapCommitDecision.CommitQwertyGlideCandidate(candidate.string) + } + val tail = if (insertString.length > candidate.length.toInt()) { + insertString.substring(candidate.length.toInt()) + } else { + null + } + return QwertyGlideTapCommitDecision.UseStandardCandidateFlow(tail) + } + + fun shouldCommitPreviousGlideCandidateOnNewGlide( + qwertyGlideInputPreference: Boolean, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference: Boolean, + inputString: String, + stringInTail: String, + currentQwertyRomajiModeForSession: Boolean, + firstCandidate: Candidate?, + currentQwertyGlideCompositionText: String? + ): Boolean { + if (!qwertyGlideInputPreference) return false + if (!qwertyGlideCommitPreviousCandidateOnNewGlidePreference) return false + if (inputString.isEmpty()) return false + if (stringInTail.isNotEmpty()) return false + if (currentQwertyRomajiModeForSession) return false + val candidate = firstCandidate ?: return false + if (!isQwertyGlideCandidate(candidate)) return false + if (currentQwertyGlideCompositionText == null) return false + return inputString == candidate.string && currentQwertyGlideCompositionText == candidate.string + } + + fun resolvePreviousGlideCommitText( + firstCandidate: Candidate, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference: Boolean + ): String { + return if (qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference) { + firstCandidate.string + " " + } else { + firstCandidate.string + } + } + + fun resolvePreviousGlideCommitDecision( + qwertyGlideInputPreference: Boolean, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference: Boolean, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference: Boolean, + inputString: String, + stringInTail: String, + currentQwertyRomajiModeForSession: Boolean, + firstCandidate: Candidate?, + currentQwertyGlideCompositionText: String? + ): QwertyGlidePreviousCandidateCommitDecision { + if (!shouldCommitPreviousGlideCandidateOnNewGlide( + qwertyGlideInputPreference = qwertyGlideInputPreference, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference = + qwertyGlideCommitPreviousCandidateOnNewGlidePreference, + inputString = inputString, + stringInTail = stringInTail, + currentQwertyRomajiModeForSession = currentQwertyRomajiModeForSession, + firstCandidate = firstCandidate, + currentQwertyGlideCompositionText = currentQwertyGlideCompositionText + ) + ) { + return QwertyGlidePreviousCandidateCommitDecision.Skip + } + val candidate = requireNotNull(firstCandidate) + return QwertyGlidePreviousCandidateCommitDecision.Commit( + resolvePreviousGlideCommitText( + firstCandidate = candidate, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference = + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference + ) + ) + } +} diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinator.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinator.kt index 48402d5b..c07ef62c 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinator.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinator.kt @@ -23,6 +23,7 @@ class QwertyGlideInputCoordinator( private val previousTextProvider: () -> String, private val onPreviewCandidates: (List) -> Unit, private val onFinalCandidates: (List) -> Unit, + private val onGlideStarted: () -> Unit = {}, private val onCancel: () -> Unit = {}, private val onProcessingChanged: (Boolean) -> Unit = {}, private val decodeDispatcher: CoroutineDispatcher = Dispatchers.Default @@ -39,6 +40,7 @@ class QwertyGlideInputCoordinator( previewJob?.cancel() finalJob?.cancel() clearProcessing() + onGlideStarted() } override fun onQwertyGlideUpdated( diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/adapters/SuggestionAdapter.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/adapters/SuggestionAdapter.kt index 6489f57e..8f340a4a 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/adapters/SuggestionAdapter.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/adapters/SuggestionAdapter.kt @@ -23,6 +23,7 @@ import com.kazumaproject.core.domain.extensions.setDrawableSolidColor import com.kazumaproject.core.domain.state.TenKeyQWERTYMode import com.kazumaproject.markdownhelperkeyboard.R import com.kazumaproject.markdownhelperkeyboard.converter.candidate.Candidate +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.QWERTY_GLIDE_CANDIDATE_TYPE import com.kazumaproject.markdownhelperkeyboard.custom_keyboard.data.CustomKeyboardLayout import com.kazumaproject.markdownhelperkeyboard.gemma.GemmaTranslationManager import com.kazumaproject.markdownhelperkeyboard.ime_service.extensions.correctReading @@ -638,6 +639,7 @@ class SuggestionAdapter : RecyclerView.Adapter() { (38).toByte() -> "" (39).toByte() -> "" (40).toByte() -> "[AI]" + QWERTY_GLIDE_CANDIDATE_TYPE -> "" GemmaTranslationManager.TRANSLATED_CANDIDATE_TYPE.toByte() -> "[訳]" GemmaTranslationManager.PROMPT_RESULT_CANDIDATE_TYPE.toByte() -> "[AI]" GemmaTranslationManager.SELECTION_TRANSLATE_ACTION_CANDIDATE_TYPE.toByte() -> "[訳]" diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/AppPreference.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/AppPreference.kt index 41d21909..723e4600 100644 --- a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/AppPreference.kt +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/AppPreference.kt @@ -93,6 +93,12 @@ object AppPreference { private val QWERTY_GLIDE_INPUT_PREFERENCE = Pair("qwerty_glide_input_preference", false) + private val QWERTY_GLIDE_COMMIT_PREVIOUS_CANDIDATE_ON_NEW_GLIDE_PREFERENCE = + Pair("qwerty_glide_commit_previous_candidate_on_new_glide_preference", false) + + private val QWERTY_GLIDE_INSERT_SPACE_AFTER_COMMITTING_PREVIOUS_CANDIDATE_PREFERENCE = + Pair("qwerty_glide_insert_space_after_committing_previous_candidate_preference", false) + private val QWERTY_ENABLE_FLICK_UP_WINDOW = Pair("qwerty_enable_flick_up_preference", false) private val QWERTY_ENABLE_FLICK_DOWN_WINDOW = Pair("qwerty_enable_flick_down_preference", false) @@ -664,6 +670,30 @@ object AppPreference { it.putBoolean(QWERTY_GLIDE_INPUT_PREFERENCE.first, value) } + var qwerty_glide_commit_previous_candidate_on_new_glide_preference: Boolean + get() = preferences.getBoolean( + QWERTY_GLIDE_COMMIT_PREVIOUS_CANDIDATE_ON_NEW_GLIDE_PREFERENCE.first, + QWERTY_GLIDE_COMMIT_PREVIOUS_CANDIDATE_ON_NEW_GLIDE_PREFERENCE.second + ) + set(value) = preferences.edit { + it.putBoolean( + QWERTY_GLIDE_COMMIT_PREVIOUS_CANDIDATE_ON_NEW_GLIDE_PREFERENCE.first, + value + ) + } + + var qwerty_glide_insert_space_after_committing_previous_candidate_preference: Boolean + get() = preferences.getBoolean( + QWERTY_GLIDE_INSERT_SPACE_AFTER_COMMITTING_PREVIOUS_CANDIDATE_PREFERENCE.first, + QWERTY_GLIDE_INSERT_SPACE_AFTER_COMMITTING_PREVIOUS_CANDIDATE_PREFERENCE.second + ) + set(value) = preferences.edit { + it.putBoolean( + QWERTY_GLIDE_INSERT_SPACE_AFTER_COMMITTING_PREVIOUS_CANDIDATE_PREFERENCE.first, + value + ) + } + var switch_qwerty_password: Boolean? get() = preferences.getBoolean( SWITCH_QWERTY_PASSWORD.first, SWITCH_QWERTY_PASSWORD.second diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5debcd76..33a100d3 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -517,6 +517,10 @@ キーボード上にローマ字入力と英語入力を切り替えるキー(あa)を表示します 英語 QWERTY のグライド入力 β 英語 QWERTY キーボードで、指を滑らせた軌跡から英単語候補を表示します。 + 次のグライド開始時に前の候補を確定 + グライド候補が入力中の状態で次のグライドを開始したとき、候補を置換せず現在の一番目候補を確定します。 + 前のグライド候補の確定後に空白を追加 + 次のグライド開始前に前の候補を確定するとき、後ろに半角スペースを追加します。 キーボードテーマ 反映には一度キーボードを再起動する必要があります。 ベースカラーの選択 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ba1857e..25994993 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -515,6 +515,10 @@ Show a key (あa) to switch between Romaji input and English input Glide input for English QWERTY β Enable word suggestions from sliding gestures on the English QWERTY keyboard. + Commit previous glide candidate on new glide + When starting a new glide while a glide candidate is composing, commit the current first candidate instead of replacing it. + Add space after committing previous glide candidate + When committing the previous glide candidate before a new glide, insert a half-width space after it. Keyboard Theme Choose the keyboard theme color.\nTo apply changes, please switch the keyboard once. Select Base Color diff --git a/app/src/main/res/xml/pref_qwerty.xml b/app/src/main/res/xml/pref_qwerty.xml index 62f712a4..6cede6eb 100644 --- a/app/src/main/res/xml/pref_qwerty.xml +++ b/app/src/main/res/xml/pref_qwerty.xml @@ -10,6 +10,18 @@ app:defaultValue="false" app:summary="@string/qwerty_glide_input_preference_summary" /> + + + + + assertEquals(QWERTY_GLIDE_CANDIDATE_TYPE, candidate.type) + assertEquals(45.toByte(), candidate.type) + assertNotEquals(36.toByte(), candidate.type) + } + } + private fun decoder( entries: List, metricsListener: ((QwertyGlideDecodeMetrics) -> Unit)? = null diff --git a/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicyTest.kt b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicyTest.kt new file mode 100644 index 00000000..7a4070ed --- /dev/null +++ b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideCommitPolicyTest.kt @@ -0,0 +1,163 @@ +package com.kazumaproject.markdownhelperkeyboard.ime_service + +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.Candidate +import com.kazumaproject.markdownhelperkeyboard.converter.candidate.QWERTY_GLIDE_CANDIDATE_TYPE +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test + +class QwertyGlideCommitPolicyTest { + @Test + fun tapQwertyGlideCandidateCommitsCandidateStringWithoutTail() { + val decision = QwertyGlideCommitPolicy.resolveTapCommitDecision( + candidate = candidate("hero", QWERTY_GLIDE_CANDIDATE_TYPE, length = 4), + insertString = "hello" + ) + + assertTrue(decision is QwertyGlideTapCommitDecision.CommitQwertyGlideCandidate) + assertEquals( + "hero", + (decision as QwertyGlideTapCommitDecision.CommitQwertyGlideCandidate).commitText + ) + } + + @Test + fun normalCandidateWithExcessInputKeepsTailInStandardFlow() { + val decision = QwertyGlideCommitPolicy.resolveTapCommitDecision( + candidate = candidate("hero", type = 1, length = 4), + insertString = "hello" + ) + + assertTrue(decision is QwertyGlideTapCommitDecision.UseStandardCandidateFlow) + assertEquals( + "o", + (decision as QwertyGlideTapCommitDecision.UseStandardCandidateFlow).tailForPartialOrExcess + ) + } + + @Test + fun preferenceOneFalseSkipsPreviousGlideCommitOnNewGlide() { + val decision = previousDecision( + commitPrevious = false, + insertSpace = true + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, decision) + } + + @Test + fun preferenceOneTrueAndPreferenceTwoFalseCommitsPreviousCandidateWithoutSpace() { + val decision = previousDecision( + commitPrevious = true, + insertSpace = false + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Commit("hello"), decision) + } + + @Test + fun preferenceOneTrueAndPreferenceTwoTrueCommitsPreviousCandidateWithSpace() { + val decision = previousDecision( + commitPrevious = true, + insertSpace = true + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Commit("hello "), decision) + } + + @Test + fun nonQwertyFirstCandidateSkipsPreviousGlideCommitOnNewGlide() { + val decision = previousDecision( + commitPrevious = true, + insertSpace = true, + firstCandidate = candidate("なにか", type = 1, length = 3), + inputString = "なにか", + currentQwertyGlideCompositionText = "なにか" + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, decision) + } + + @Test + fun nonEmptyStringInTailSkipsPreviousGlideCommitOnNewGlide() { + val decision = previousDecision( + commitPrevious = true, + stringInTail = "tail" + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, decision) + } + + @Test + fun romajiModeSkipsPreviousGlideCommitOnNewGlide() { + val decision = previousDecision( + commitPrevious = true, + currentQwertyRomajiModeForSession = true + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, decision) + } + + @Test + fun glideInputDisabledSkipsPreviousGlideCommitOnNewGlide() { + val decision = previousDecision( + qwertyGlideInputPreference = false, + commitPrevious = true + ) + + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, decision) + } + + @Test + fun type36IsNotQwertyGlideCandidate() { + val type36Candidate = candidate("hello", type = 36.toByte(), length = 5) + + assertFalse(QwertyGlideCommitPolicy.isQwertyGlideCandidate(type36Candidate)) + val tapDecision = QwertyGlideCommitPolicy.resolveTapCommitDecision( + candidate = type36Candidate, + insertString = "hello" + ) + assertTrue(tapDecision is QwertyGlideTapCommitDecision.UseStandardCandidateFlow) + assertNull( + (tapDecision as QwertyGlideTapCommitDecision.UseStandardCandidateFlow).tailForPartialOrExcess + ) + val previousDecision = previousDecision( + commitPrevious = true, + firstCandidate = type36Candidate + ) + assertEquals(QwertyGlidePreviousCandidateCommitDecision.Skip, previousDecision) + } + + private fun previousDecision( + qwertyGlideInputPreference: Boolean = true, + commitPrevious: Boolean, + insertSpace: Boolean = false, + inputString: String = "hello", + stringInTail: String = "", + currentQwertyRomajiModeForSession: Boolean = false, + firstCandidate: Candidate? = candidate("hello", QWERTY_GLIDE_CANDIDATE_TYPE, 5), + currentQwertyGlideCompositionText: String? = "hello" + ): QwertyGlidePreviousCandidateCommitDecision { + return QwertyGlideCommitPolicy.resolvePreviousGlideCommitDecision( + qwertyGlideInputPreference = qwertyGlideInputPreference, + qwertyGlideCommitPreviousCandidateOnNewGlidePreference = commitPrevious, + qwertyGlideInsertSpaceAfterCommittingPreviousCandidatePreference = insertSpace, + inputString = inputString, + stringInTail = stringInTail, + currentQwertyRomajiModeForSession = currentQwertyRomajiModeForSession, + firstCandidate = firstCandidate, + currentQwertyGlideCompositionText = currentQwertyGlideCompositionText + ) + } + + private fun candidate(string: String, type: Byte, length: Int): Candidate { + return Candidate( + string = string, + type = type, + length = length.toUByte(), + score = 1000 + ) + } +} diff --git a/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinatorTest.kt b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinatorTest.kt index d82d33a2..2e699e6a 100644 --- a/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinatorTest.kt +++ b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/QwertyGlideInputCoordinatorTest.kt @@ -93,6 +93,31 @@ class QwertyGlideInputCoordinatorTest { assertEquals(listOf(true, false), events) } + @Test + fun glideStartedCallbackRunsAfterPendingWorkIsCancelledAndProcessingCleared() = runTest { + val requests = mutableListOf>>() + val events = mutableListOf() + val callbackEventSnapshots = mutableListOf>() + val coordinator = coordinator( + scope = this, + provider = deferredProvider(requests), + events = events, + onGlideStarted = { + callbackEventSnapshots += events.toList() + } + ) + + coordinator.onQwertyGlideEnded(pointers, proximityInfo) + runCurrent() + assertEquals(listOf(true), events) + + coordinator.onQwertyGlideStarted() + runCurrent() + + assertEquals(listOf(true, false), events) + assertEquals(listOf(listOf(true, false)), callbackEventSnapshots) + } + @Test fun cancelledPreviewDoesNotHideNewFinalProcessing() = runTest { val requests = mutableListOf>>() @@ -175,7 +200,8 @@ class QwertyGlideInputCoordinatorTest { provider: QwertyGlideCandidateProvider, events: MutableList, previews: MutableList> = mutableListOf(), - finals: MutableList> = mutableListOf() + finals: MutableList> = mutableListOf(), + onGlideStarted: () -> Unit = {} ): QwertyGlideInputCoordinator { val dispatcher = StandardTestDispatcher(scope.testScheduler) return QwertyGlideInputCoordinator( @@ -184,6 +210,7 @@ class QwertyGlideInputCoordinatorTest { previousTextProvider = { "" }, onPreviewCandidates = previews::add, onFinalCandidates = finals::add, + onGlideStarted = onGlideStarted, onProcessingChanged = events::add, decodeDispatcher = dispatcher )