refactor: extract ConjugationHandler from GeneralKeyboardIME (Part 12) - #426 - #687
Conversation
|
Would you be able to fix the merge conflicts, @prince-0408? We'd then get to the review :) |
1cd39ae to
d2543e8
Compare
f2a4f9e to
71c7ea3
Compare
|
Thanks for the rebase, @prince-0408! We'll focus on bringing this one in next :) |
| var subsequentAreaRequired: Boolean = false | ||
| var subsequentData: MutableList<List<String>> = mutableListOf() | ||
|
|
||
| var conjugateOutput: MutableMap<String, MutableMap<String, Collection<String>>>? |
There was a problem hiding this comment.
This only passes through to ime.conjugateOutput, so read it from ime directly and drop the property.
| ime.conjugateOutput = value | ||
| } | ||
|
|
||
| var conjugateLabels: Set<String> |
There was a problem hiding this comment.
ConjugateLabels is never used in the handler, so it can be deleted.
| ) { | ||
| val mode = | ||
| if (isSubsequent) { | ||
| "2x1" |
There was a problem hiding this comment.
Sub-view now saves "2x1" here, but it used to save "none". Please keep the original behavior.
| if (isSubsequent) { | ||
| "2x1" | ||
| } else { | ||
| when (getLanguageAlias(language).lowercase()) { |
There was a problem hiding this comment.
SaveConjugateModeType("none") now resolves to English and saves 2x2, so the idle keyboard gets conjugation key heights
| "2x1" | ||
| } else { | ||
| when (getLanguageAlias(language).lowercase()) { | ||
| "es", "it" -> "3x2" |
There was a problem hiding this comment.
3x2 has no branch in KeyboardBase, so Spanish and Italian fall through to 3x3 height when they used to get 2x2.
| conjugationHandler.subsequentAreaRequired = value | ||
| } | ||
|
|
||
| internal var subsequentData: MutableList<List<String>> |
There was a problem hiding this comment.
Keep it private or remove the wrapper
| * Delegated to [ConjugationHandler]. | ||
| */ | ||
| private fun getKeyboardLayoutForState( | ||
| internal fun getKeyboardLayoutForState( |
There was a problem hiding this comment.
This was private and is now internal ,does anything outside the class use it?
| } | ||
|
|
||
| @Test | ||
| fun saveConjugateModeType_spanishReturns3x2() { |
There was a problem hiding this comment.
Please add a test for saveConjugateModeType(none) that expects none
|
|
||
| val prefs = context.getSharedPreferences("keyboard_preferences", Context.MODE_PRIVATE) | ||
| assertEquals("2x1", prefs.getString("conjugate_mode_type", null)) | ||
| verify { keyboardView.setKeyLabel("hablo", "HI", KeyboardBase.CODE_1X3_RIGHT) } |
There was a problem hiding this comment.
This asserts the LEFT/RIGHT bug, so please update it once line 164 is fixed.
| } | ||
|
|
||
| @Test | ||
| fun returnSubsequentData_and_conjugateLabels() { |
There was a problem hiding this comment.
This only checks that values are passed through,please test the behavior instead
There was a problem hiding this comment.
@Roniscend, big question for the initial review is whether this has been resolved. Feel free to resolve the thread if so :)
6d344f3 to
2af3627
Compare
2af3627 to
949c234
Compare
|
Looks like there are a few minor edits from @Roniscend's review here, @prince-0408 😊 Let us know if you need any support finalizing them 😊 |
Hi @andrewtavis Everything is up to date and ready for review! 😊 |
|
CC @Roniscend that an initial review here would be appreciated :) |
| val flattenList = filteredData.flatten() | ||
| saveConjugateModeType(language = ime.language, isSubsequent = true) | ||
| val keyboardXmlId = getKeyboardLayoutForState(ime.currentState, isSubsequentArea = true, dataSize = flattenList.size) | ||
| ime.uiManager.initializeKeyboard(keyboardXmlId) |
There was a problem hiding this comment.
Conjugate_mode_type is none when the sub-view inflates here, but on main the removed saveConjugateModeType inside getKeyboardLayoutForState left it 2x2, was the row-height change intended?
| when (language) { | ||
| "English", "Russian", "Swedish", | ||
| "German", "French", "Italian", "Portuguese", "Spanish", | ||
| "en", "ru", "sv", "de", "fr", "it", "pt", "es", |
There was a problem hiding this comment.
Ime.language is scribeLanguage.displayName , so these ISO-code branches are unreachable.
| if (!isSubsequent) { | ||
| when (language) { | ||
| "English", "Russian", "Swedish", | ||
| "German", "French", "Italian", "Portuguese", "Spanish", |
There was a problem hiding this comment.
This hardcoded list duplicates defaultConjugateModeType, which each IME already overrides , expose that on KeyboardIMEContext and read it instead.
| * | ||
| * @return A valid, zero-based index for the conjugation type. | ||
| */ | ||
| fun getValidatedConjugateIndex(): Int { |
There was a problem hiding this comment.
This is byte-identical to the private getValidatedConjugateIndex already in KeyboardUIManager, keep one and delete the other
| private val ime: KeyboardIMEContext, | ||
| ) { | ||
| var subsequentAreaRequired: Boolean = false | ||
| var subsequentData: MutableList<List<String>> = mutableListOf() |
There was a problem hiding this comment.
SubsequentData is never assigned anywhere in the codebase, so returnSubsequentData() always returns empty wire it up or drop it
|
|
||
| val prefs = context.getSharedPreferences("keyboard_preferences", Context.MODE_PRIVATE) | ||
| assertEquals("none", prefs.getString("conjugate_mode_type", null)) | ||
| verify { uiManager.initializeKeyboard(R.xml.conjugate_view_2x1) } |
There was a problem hiding this comment.
UiManager is a real KeyboardUIManager , not a mockk, so MockK verifies the relaxed listener calls made inside initializeKeyboard instead and this passes even with the wrong XML id.
|
|
||
| val prefs = context.getSharedPreferences("keyboard_preferences", Context.MODE_PRIVATE) | ||
| assertEquals("none", prefs.getString("conjugate_mode_type", null)) | ||
| verify { uiManager.initializeKeyboard(R.xml.conjugate_view_1x3) } |
There was a problem hiding this comment.
Same here ,mock uiManager or assert on the inflated KeyboardBase so the layout id is actually checked
|
|
||
| @Test | ||
| fun saveConjugateModeType_noneReturnsNone() { | ||
| handler.saveConjugateModeType("none", isSubsequent = false) |
There was a problem hiding this comment.
None isn't a language the IME can pass , use a genuinely unsupported one like Hindi
| every { ime.getInputConnection() } returns inputConnection | ||
| every { ime.suggestionHandler } returns suggestionHandler | ||
| every { ime.uiManager } returns uiManager | ||
| every { ime.binding } returns binding |
There was a problem hiding this comment.
Every { ime.binding } returns binding is unused , the handler reads ime.uiManager.binding.
| assertEquals(View.GONE, binding.ivInfo.visibility) | ||
| assertFalse(handler.subsequentAreaRequired) | ||
| } | ||
| } |
There was a problem hiding this comment.
No test covers the dataSize == 0 path returning defaultConjugateLayoutXML, which is the only branch using the new interface member.
| // Language-specific layout and behavior configurations (decoupled from base class). | ||
| open val defaultConjugateModeType: String = "3x2" | ||
| open val defaultConjugateLayoutXML: Int = R.xml.conjugate_view_3x2 | ||
| open override val defaultConjugateModeType: String = "3x2" |
There was a problem hiding this comment.
German, French, Italian, Portuguese and Spanish don't override this, so they go from 2x2 to 3x2, which KeyboardBase has no case for their conjugation keys silently fall to the 73dp 3x3 height instead of 113dp
| } else { | ||
| val word = ime.handleConjugateKeys(code, true) | ||
| ime.setupConjugateSubView(ime.returnSubsequentData(), word) | ||
| ime.setupConjugateSubView(emptyList(), word) |
There was a problem hiding this comment.
Hardcoding emptyList() here guarantees setupConjugateSubView always hits its else -> return, permanently disabling the sub-view path instead of keeping the returnSubsequentData() seam
|
@andrewtavis Requesting a final review on this pr lgtm from my side |
andrewtavis
left a comment
There was a problem hiding this comment.
praise: From my end this is looking great :) Thanks for the collaboration, @prince-0408 and @Roniscend! We'll see how all of this goes once the verb data is back up and running, which hopefully will be soon. Back to Scribe-Data now 😊
Description
This PR is Part 12 in modularizing GeneralKeyboardIME for #426.
It extracts verb conjugation state management, conjugation table layout calculation (2x1, 1x3, 3x2, 2x2), capitalization formatting, index boundary validation, and sub-view setup out of GeneralKeyboardIME.kt into a standalone helper class ConjugationHandler.
Detailed Changes Table
ConjugationHandler.ktsubsequentAreaRequired,subsequentData,conjugateOutput,conjugateLabels), layout mode saving (saveConjugateModeType), capitalization formatting (applyCapitalizationToConjugations), index validation (getValidatedConjugateIndex), conjugation key press handling (handleConjugateKeys), secondary sub-view setup (setupConjugateSubView), and layout XML selection (getKeyboardLayoutForState).GeneralKeyboardIME.ktinto a dedicated helper class.GeneralKeyboardIME.ktconjugationHandlerand delegated conjugation state properties (subsequentAreaRequired,subsequentData) and helper methods (saveConjugateModeType,applyCapitalizationToConjugations,getValidatedConjugateIndex,returnIsSubsequentRequired,returnSubsequentData,handleConjugateKeys,setupConjugateSubView,getKeyboardLayoutForState). Removed duplicate private helper implementations and unused constants.GeneralKeyboardIME.ktwhile maintaining 100% backward compatibility for all callers.ConjugationHandlerTest.ktapplyCapitalizationToConjugations), index boundary clamping (getValidatedConjugateIndex), layout mode saving (saveConjugateModeType), and XML layout selection (getKeyboardLayoutForState).CHANGELOG.md### ♻️ Code Refactoringdetailing the extraction ofConjugationHandlerfromGeneralKeyboardIME.ci_changelog_checkworkflow requirement for pull requests targetingmain.Key Benefits
2x1,1x3,3x2,2x2), verb tense capitalization rules, and multi-option selection sub-views fromGeneralKeyboardIME.kt.Related Issue
Refactors part of #426