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 1836e5ba..d905da95 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 @@ -222,6 +222,7 @@ import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateS import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateQueryModeResolver import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshCoordinator import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshRequest +import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshTransitionPolicy import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRequestToken import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRequestTracker import com.kazumaproject.markdownhelperkeyboard.ime_service.clipboard.ClipboardUtil @@ -14645,10 +14646,11 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, prevFlag, currentFlag, ) - if ( - prevFlag == CandidateShowFlag.Idle && - currentFlag == CandidateShowFlag.Updating && - insertString.isNotEmpty() + if (CandidateRefreshTransitionPolicy.shouldEnterActiveCandidatePhase( + previousFlag = prevFlag, + currentFlag = currentFlag, + input = insertString, + ) ) { clearZeroQueryAllState(refresh = false) shortcutToolbarHiddenForCandidates = true @@ -14798,7 +14800,10 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection, } } } - prevFlag = currentFlag + prevFlag = CandidateRefreshTransitionPolicy.nextUiPreviousFlag( + currentFlag = currentFlag, + input = insertString, + ) } } diff --git a/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshTransitionPolicy.kt b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshTransitionPolicy.kt new file mode 100644 index 00000000..5a691ce5 --- /dev/null +++ b/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshTransitionPolicy.kt @@ -0,0 +1,34 @@ +package com.kazumaproject.markdownhelperkeyboard.ime_service.candidate + +import com.kazumaproject.markdownhelperkeyboard.ime_service.models.CandidateShowFlag + +/** + * Keeps non-user candidate refreshes from changing the visible conversion phase. + * + * Dictionary loading can publish an Updating request while the composing input is empty. That + * request refreshes data, but it must not consume the Idle -> Updating transition used by the + * candidate-strip UI to show the full-candidate toggle. + */ +internal object CandidateRefreshTransitionPolicy { + + fun shouldEnterActiveCandidatePhase( + previousFlag: CandidateShowFlag?, + currentFlag: CandidateShowFlag, + input: String, + ): Boolean { + return previousFlag == CandidateShowFlag.Idle && + currentFlag == CandidateShowFlag.Updating && + input.isNotEmpty() + } + + fun nextUiPreviousFlag( + currentFlag: CandidateShowFlag, + input: String, + ): CandidateShowFlag { + return if (currentFlag == CandidateShowFlag.Updating && input.isEmpty()) { + CandidateShowFlag.Idle + } else { + currentFlag + } + } +} diff --git a/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshCoordinatorTest.kt b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshCoordinatorTest.kt index cae735d9..da1589c5 100644 --- a/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshCoordinatorTest.kt +++ b/app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/candidate/CandidateRefreshCoordinatorTest.kt @@ -14,6 +14,34 @@ import org.junit.Test class CandidateRefreshCoordinatorTest { + @Test + fun emptyUpdatingDoesNotConsumeTheNextActiveCandidateTransition() { + val afterDictionaryRefresh = CandidateRefreshTransitionPolicy.nextUiPreviousFlag( + currentFlag = CandidateShowFlag.Updating, + input = "", + ) + + assertEquals(CandidateShowFlag.Idle, afterDictionaryRefresh) + assertTrue( + CandidateRefreshTransitionPolicy.shouldEnterActiveCandidatePhase( + previousFlag = afterDictionaryRefresh, + currentFlag = CandidateShowFlag.Updating, + input = "かな", + ) + ) + } + + @Test + fun nonEmptyUpdatingRemainsTheActiveCandidatePhase() { + assertEquals( + CandidateShowFlag.Updating, + CandidateRefreshTransitionPolicy.nextUiPreviousFlag( + currentFlag = CandidateShowFlag.Updating, + input = "かな", + ) + ) + } + @Test fun repeatedUpdatingRequestsRemainDistinctAndCarryTheirInputSnapshot() { val coordinator = CandidateRefreshCoordinator()