Repository navigation
Fix resolve verb conjugations in a single pass and close auxiliary DB connections - #743
Conversation
|
As expected there are some merge conflicts here now, @Roniscend :) Would you be able to fix those? And will merging this PR in close #571, or if not what further work do we need to do? |
Sure, will fix the merge conflicts also yeah this pr closes the issue |
cfdf4f8 to
6ece7c7
Compare
Signed-off-by: Owm <owmdubey163@gmail.com>
6ece7c7 to
8c39409
Compare
|
Thanks for fixing the conflicts, @Roniscend! Let's plan on bringing this in tomorrow during the call :) CC @ashb155 as well 👋 |
prince-0408
left a comment
There was a problem hiding this comment.
Thanks for the work here @Roniscend!
The ViewModel architecture (ConjugationSelectionUiState), the error/empty states with retry handling, and the Compose cell layout improvements (heightIn(min = 100.dp) / maxLines = 2) look great and nicely address #571.
A few key points to address before this is ready to merge:
- Reusing
getStructuredConjugationsfrom PR #742:
Commit264c2f06onmainalready introducedgetStructuredConjugationsand its helper methods, which already resolve conjugations in a single pass while properly quoting SQL identifiers, applyingLIMIT 1, handling case-insensitivity, prefix-stripping, and inflected form fallback. We can removegetConjugationsForVerb(and its helper methods) fromConjugateDataManager.ktand haveConjugationSelectionViewModelcallgetStructuredConjugations(languageAlias, contract, verb)directly. This will also allow removing the duplicate tests and@Suppress("LargeClass")fromConjugateDataManagerTest.kt. - Case-sensitivity bug in
databaseExists:
Conjugate database filenames are uppercase (${alias.uppercase()}ConjugateData.sqlite). On case-sensitive Android filesystems, lowercase aliases like"en"or"de"will fail.exists()and get stuck inNoData. - Keying
selectedTenseGroup:
KeyingrememberSaveable(verb, languageAlias)ensures the tense selection is cleared when navigating between verbs or languages.
Detailed inline comments and suggestions are below.
| return allFormKeys | ||
| } | ||
|
|
||
| fun getConjugationsForVerb( |
There was a problem hiding this comment.
In commit 264c2f06 (PR #742), ConjugateDataManager.kt on main already introduced:
getStructuredConjugations(language, yamlData, word)getVerbRowData(handles case-insensitive search, prefix stripping for"to ","se ","sich ", and fallback to inflected forms)resolveConjugatedValueparseComplexFormFromRow(properly quoting target columns withSqlIdentifier.quoteand addingLIMIT 1)
The newly added getConjugationsForVerb, getColumnIndexWithFallback, getConjugatedValueFromCursor, parseComplexForm, and getVerbCursor duplicate this entire pipeline while missing SqlIdentifier.quote, LIMIT 1, and the prefix-stripping/inflected search improvements.
We can remove getConjugationsForVerb and its private helper methods completely and have ConjugationSelectionViewModel call getStructuredConjugations(languageAlias, contract, verb) directly.
| private val conjugateDataManager: ConjugateDataManager = ConjugateDataManager(DatabaseFileManager(application)), | ||
| private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, | ||
| private val databaseExists: (String) -> Boolean = { alias -> | ||
| application.getDatabasePath("${alias}ConjugateData.sqlite").exists() |
There was a problem hiding this comment.
Conjugate database files created by ConjugateDynamicDbHelper and checked by DatabaseFileManager are uppercase (e.g., ENConjugateData.sqlite, DEConjugateData.sqlite). On Android's Linux filesystem, file lookups are case-sensitive.
If languageAlias is passed as lowercase ("en", "de", "fr"), application.getDatabasePath("${alias}ConjugateData.sqlite") looks for enConjugateData.sqlite, which fails .exists() and permanently leaves the screen in ConjugationSelectionUiState.NoData.
| application.getDatabasePath("${alias}ConjugateData.sqlite").exists() | |
| application.getDatabasePath("${alias.uppercase()}ConjugateData.sqlite").exists() |
| val contract = contractDataLoader.loadOrDownloadContract(languageAlias) | ||
| if (contract == null) { | ||
| _uiState.value = ConjugationSelectionUiState.Error | ||
| return@launch | ||
| } | ||
| if (!databaseExists(languageAlias)) { | ||
| _uiState.value = ConjugationSelectionUiState.NoData | ||
| return@launch | ||
| } | ||
| val data = conjugateDataManager.getConjugationsForVerb(verb, languageAlias, contract) |
There was a problem hiding this comment.
Checking databaseExists(languageAlias) before loadOrDownloadContract avoids unnecessary network and file operations if the conjugate database isn't downloaded yet.
Additionally, we can call the existing getStructuredConjugations(languageAlias, contract, verb) from main instead of getConjugationsForVerb.
| val contract = contractDataLoader.loadOrDownloadContract(languageAlias) | |
| if (contract == null) { | |
| _uiState.value = ConjugationSelectionUiState.Error | |
| return@launch | |
| } | |
| if (!databaseExists(languageAlias)) { | |
| _uiState.value = ConjugationSelectionUiState.NoData | |
| return@launch | |
| } | |
| val data = conjugateDataManager.getConjugationsForVerb(verb, languageAlias, contract) | |
| if (!databaseExists(languageAlias)) { | |
| _uiState.value = ConjugationSelectionUiState.NoData | |
| return@launch | |
| } | |
| val contract = contractDataLoader.loadOrDownloadContract(languageAlias) | |
| if (contract == null) { | |
| _uiState.value = ConjugationSelectionUiState.Error | |
| return@launch | |
| } | |
| val data = conjugateDataManager.getStructuredConjugations(languageAlias, contract, verb) |
|
|
||
| val conjugationData = (uiState as? ConjugationSelectionUiState.Data)?.conjugationData | ||
| var expanded by remember { mutableStateOf(false) } | ||
| var selectedTenseGroup by rememberSaveable { mutableStateOf<String?>(null) } |
There was a problem hiding this comment.
selectedTenseGroup is remembered with rememberSaveable without keys. When navigating to another verb or language, the selected tense filter persists from the previous verb. If that tense group does not exist in the new verb's contract, tenseGroups[targetGroup] resolves to null and the card renders blank.
Keying rememberSaveable by verb and languageAlias resets the tense filter when the verb or language changes.
| var selectedTenseGroup by rememberSaveable { mutableStateOf<String?>(null) } | |
| var selectedTenseGroup by rememberSaveable(verb, languageAlias) { mutableStateOf<String?>(null) } |
angrezichatterbox
left a comment
There was a problem hiding this comment.
Thanks for the review @prince-0408 and awesome work on the PR @Roniscend. I have made some minor changes to finalise the PR. Once again thanks for the work.
Contributor checklist
./gradlew lintKotlin detekt testcommand as directed in the testing section of the contributing guideDescription
Populates conjugation tables from the database in contract order using a single DB pass, fixes a leaked DB connection, and adds an explicit loading/error ViewModel with tests.
Closes #571