Implement intelligent merging for duplicate vocabulary items
This commit is contained in:
@@ -335,7 +335,6 @@ class VocabularyViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun deleteVocabularyItemsById(list: List<Int>) {
|
||||
Log.d(TAG, "Deleting vocabulary items with IDs: $list")
|
||||
viewModelScope.launch {
|
||||
@@ -407,18 +406,116 @@ class VocabularyViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the merging of two duplicate vocabulary items.
|
||||
* Placeholder logic: Deletes the new item, effectively keeping the original.
|
||||
* A full implementation would merge properties like stage, categories, and features.
|
||||
* Handles the merging of two duplicate vocabulary items intelligently.
|
||||
* Merges learning progress (stages, counts), categories, and features.
|
||||
* Keeps the existing item and updates it with merged data.
|
||||
*
|
||||
* @param newItem The duplicate item to merge (will be deleted)
|
||||
* @param existingItem The original item to keep and update
|
||||
*/
|
||||
fun mergeDuplicateItems(newItem: VocabularyItem, existingItem: VocabularyItem) {
|
||||
Log.d(TAG, "mergeDuplicateItems: Merging ${newItem.id} into ${existingItem.id}. (Placeholder logic)")
|
||||
//TODO
|
||||
// Placeholder: For now, this just deletes the new item.
|
||||
// A full implementation would merge stages, categories, etc., and update the existing item based on the rules.
|
||||
Log.d(TAG, "mergeDuplicateItems: Intelligently merging ${newItem.id} into ${existingItem.id}")
|
||||
viewModelScope.launch {
|
||||
statusService.showSuccessMessage("Items merged!", 2)
|
||||
try {
|
||||
// 1. Get states for both items
|
||||
val newState = vocabularyRepository.getVocabularyItemStateById(newItem.id)
|
||||
val existingState = vocabularyRepository.getVocabularyItemStateById(existingItem.id)
|
||||
|
||||
// 2. Get stages for both items
|
||||
val newStage = vocabularyRepository.getVocabularyItemStage(newItem.id).first()
|
||||
val existingStage = vocabularyRepository.getVocabularyItemStage(existingItem.id).first()
|
||||
|
||||
// 3. Merge learning progress - keep the better stage (higher in progression)
|
||||
val stageOrder = listOf(
|
||||
VocabularyStage.NEW, VocabularyStage.STAGE_1, VocabularyStage.STAGE_2,
|
||||
VocabularyStage.STAGE_3, VocabularyStage.STAGE_4, VocabularyStage.STAGE_5,
|
||||
VocabularyStage.LEARNED
|
||||
)
|
||||
val mergedStage = if (stageOrder.indexOf(newStage) > stageOrder.indexOf(existingStage)) {
|
||||
newStage
|
||||
} else {
|
||||
existingStage
|
||||
}
|
||||
|
||||
// 4. Merge answer counts and timestamps - keep higher counts and most recent timestamps
|
||||
val mergedCorrectCount = (newState?.correctAnswerCount ?: 0) + (existingState?.correctAnswerCount ?: 0)
|
||||
val mergedIncorrectCount = (newState?.incorrectAnswerCount ?: 0) + (existingState?.incorrectAnswerCount ?: 0)
|
||||
|
||||
val mergedLastCorrect = listOfNotNull(
|
||||
newState?.lastCorrectAnswer,
|
||||
existingState?.lastCorrectAnswer
|
||||
).maxOrNull()
|
||||
|
||||
val mergedLastIncorrect = listOfNotNull(
|
||||
newState?.lastIncorrectAnswer,
|
||||
existingState?.lastIncorrectAnswer
|
||||
).maxOrNull()
|
||||
|
||||
// 5. Merge features - prefer non-null, non-empty features
|
||||
val mergedFeatures = when {
|
||||
!existingItem.features.isNullOrBlank() -> existingItem.features
|
||||
!newItem.features.isNullOrBlank() -> newItem.features
|
||||
else -> null
|
||||
}
|
||||
|
||||
// 6. Merge zipf frequencies - prefer non-null values
|
||||
val mergedZipfFirst = existingItem.zipfFrequencyFirst ?: newItem.zipfFrequencyFirst
|
||||
val mergedZipfSecond = existingItem.zipfFrequencySecond ?: newItem.zipfFrequencySecond
|
||||
|
||||
// 7. Keep the earlier creation date
|
||||
val mergedCreatedAt = listOfNotNull(
|
||||
newItem.createdAt,
|
||||
existingItem.createdAt
|
||||
).minOrNull() ?: existingItem.createdAt
|
||||
|
||||
// 8. Get categories for both items and merge them
|
||||
val allMappings = vocabularyRepository.getCategoryMappings()
|
||||
val newCategories = allMappings.filter { it.vocabularyItemId == newItem.id }.map { it.categoryId }
|
||||
val existingCategories = allMappings.filter { it.vocabularyItemId == existingItem.id }.map { it.categoryId }
|
||||
val mergedCategories = (newCategories + existingCategories).distinct()
|
||||
|
||||
// 9. Update the existing item with merged data
|
||||
val updatedItem = existingItem.copy(
|
||||
features = mergedFeatures,
|
||||
zipfFrequencyFirst = mergedZipfFirst,
|
||||
zipfFrequencySecond = mergedZipfSecond,
|
||||
createdAt = mergedCreatedAt
|
||||
)
|
||||
|
||||
vocabularyRepository.editVocabularyItem(updatedItem)
|
||||
|
||||
// 10. Update stage if it changed
|
||||
if (mergedStage != existingStage) {
|
||||
vocabularyRepository.changeVocabularyItemStage(updatedItem, mergedStage)
|
||||
}
|
||||
|
||||
// 11. Update state with merged progress
|
||||
val mergedState = eu.gaudian.translator.model.VocabularyItemState(
|
||||
vocabularyItemId = existingItem.id,
|
||||
lastCorrectAnswer = mergedLastCorrect,
|
||||
lastIncorrectAnswer = mergedLastIncorrect,
|
||||
correctAnswerCount = mergedCorrectCount,
|
||||
incorrectAnswerCount = mergedIncorrectCount
|
||||
)
|
||||
vocabularyRepository.saveVocabularyItemState(mergedState)
|
||||
|
||||
// 12. Add any new categories to the existing item
|
||||
val categoriesToAdd = mergedCategories - existingCategories.toSet()
|
||||
categoriesToAdd.forEach { categoryId ->
|
||||
vocabularyRepository.addVocabularyItemToList(existingItem.id, categoryId)
|
||||
}
|
||||
|
||||
// 13. Finally, delete the duplicate item
|
||||
deleteVocabularyItemsById(listOf(newItem.id))
|
||||
|
||||
statusService.showSuccessMessage("Items merged successfully! Progress and categories preserved.", 3)
|
||||
Log.i(TAG, "mergeDuplicateItems: Successfully merged ${newItem.id} into ${existingItem.id}. " +
|
||||
"Stage: $existingStage→$mergedStage, Correct: ${existingState?.correctAnswerCount ?: 0}→$mergedCorrectCount, " +
|
||||
"Categories: ${existingCategories.size}→${mergedCategories.size}")
|
||||
} catch (e: Exception) {
|
||||
statusService.showErrorMessage("Error merging items: ${e.message}")
|
||||
Log.e(TAG, "Error in mergeDuplicateItems: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user