feat: increment catalog version from 4 to 5 with comprehensive grocery domain restructuring and expanded item coverage
- Bump catalog version to 5 - Reorganize grocery domain structure with refined category hierarchy - Expand item definitions with enhanced metadata, aliases, and tagging - Add comprehensive bilingual support across all domains and categories - Include detailed emoji, color, and sort order specifications for improved UI presentation - Extend coverage across fruits, vegetables, grains, condiments, beverages, dairy, meat, produce, and specialty items
This commit is contained in:
parent
d569c344b0
commit
49eafca209
File diff suppressed because it is too large
Load Diff
@ -990,6 +990,7 @@ private fun SuggestionRow(
|
|||||||
is ListDetailViewModel.Suggestion.Active -> "Sur la liste" to MaterialTheme.colorScheme.tertiary
|
is ListDetailViewModel.Suggestion.Active -> "Sur la liste" to MaterialTheme.colorScheme.tertiary
|
||||||
is ListDetailViewModel.Suggestion.Recent -> "Recently Used" to LocalStatusColors.current.safe
|
is ListDetailViewModel.Suggestion.Recent -> "Recently Used" to LocalStatusColors.current.safe
|
||||||
is ListDetailViewModel.Suggestion.Catalog -> suggestion.item.category to MaterialTheme.colorScheme.onSurfaceVariant
|
is ListDetailViewModel.Suggestion.Catalog -> suggestion.item.category to MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
is ListDetailViewModel.Suggestion.RoomCatalog -> (suggestion.categoryName ?: "Catalogue") to MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
is ListDetailViewModel.Suggestion.Create -> "Créer" to MaterialTheme.colorScheme.primary
|
is ListDetailViewModel.Suggestion.Create -> "Créer" to MaterialTheme.colorScheme.primary
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -87,6 +88,10 @@ class ListDetailViewModel @Inject constructor(
|
|||||||
override val label: String = item.name
|
override val label: String = item.name
|
||||||
override val emoji: String = item.emoji
|
override val emoji: String = item.emoji
|
||||||
}
|
}
|
||||||
|
data class RoomCatalog(val item: CatalogItemEntity, val categoryName: String?) : Suggestion() {
|
||||||
|
override val label: String = item.name
|
||||||
|
override val emoji: String = item.emoji
|
||||||
|
}
|
||||||
data class Recent(val item: ShoppingListItemUi) : Suggestion() {
|
data class Recent(val item: ShoppingListItemUi) : Suggestion() {
|
||||||
override val label: String = item.productName
|
override val label: String = item.productName
|
||||||
override val emoji: String = item.emoji
|
override val emoji: String = item.emoji
|
||||||
@ -152,31 +157,51 @@ class ListDetailViewModel @Inject constructor(
|
|||||||
val suggestions: StateFlow<List<Suggestion>> = combine(
|
val suggestions: StateFlow<List<Suggestion>> = combine(
|
||||||
_searchQuery,
|
_searchQuery,
|
||||||
state
|
state
|
||||||
) { rawQuery, uiState ->
|
) { rawQuery, uiState -> rawQuery to uiState }
|
||||||
|
.flatMapLatest { (rawQuery, uiState) ->
|
||||||
val query = rawQuery.trim()
|
val query = rawQuery.trim()
|
||||||
if (query.isEmpty()) return@combine emptyList()
|
if (query.isEmpty() || uiState !is UiState.Ready) {
|
||||||
|
return@flatMapLatest flowOf(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
val ready = uiState as? UiState.Ready ?: return@combine emptyList()
|
val ready = uiState
|
||||||
val results = mutableListOf<Suggestion>()
|
val staticResults = mutableListOf<Suggestion>()
|
||||||
|
|
||||||
// 1) Articles déjà sur la liste active (priorité haute pour rappel)
|
// 1) Articles déjà sur la liste active (priorité haute pour rappel)
|
||||||
ready.activeItems
|
ready.activeItems
|
||||||
.filter { it.productName.contains(query, ignoreCase = true) }
|
.filter { it.productName.contains(query, ignoreCase = true) }
|
||||||
.take(2)
|
.take(2)
|
||||||
.forEach { results.add(Suggestion.Active(it)) }
|
.forEach { staticResults.add(Suggestion.Active(it)) }
|
||||||
|
|
||||||
// 2) Recently used → restauration rapide
|
// 2) Recently used → restauration rapide
|
||||||
ready.recentlyUsed
|
ready.recentlyUsed
|
||||||
.filter { it.productName.contains(query, ignoreCase = true) }
|
.filter { it.productName.contains(query, ignoreCase = true) }
|
||||||
.take(3)
|
.take(3)
|
||||||
.forEach { results.add(Suggestion.Recent(it)) }
|
.forEach { staticResults.add(Suggestion.Recent(it)) }
|
||||||
|
|
||||||
// 3) Catalogue
|
// 3) Catalogue statique (fallback si absent de la DB)
|
||||||
catalog.search(query, limit = 6)
|
val staticCatalogItems = catalog.search(query, limit = 20)
|
||||||
.filter { item ->
|
.filter { item -> staticResults.none { it.label.equals(item.name, ignoreCase = true) } }
|
||||||
results.none { it.label.equals(item.name, ignoreCase = true) }
|
|
||||||
|
val categoryMap = catalogDomains.value.flatMap { it.categoriesWithItems }
|
||||||
|
.associate { it.category.categoryId to it.category.name }
|
||||||
|
|
||||||
|
// 3bis) Catalogue Room (tous domaines/catégories + items futurs)
|
||||||
|
catalogRepository.search(query, limit = 20).map { dbItems ->
|
||||||
|
val results = staticResults.toMutableList()
|
||||||
|
|
||||||
|
dbItems.forEach { item ->
|
||||||
|
if (results.none { it.label.equals(item.name, ignoreCase = true) }) {
|
||||||
|
val catName = item.primaryCategoryId?.let { categoryMap[it] } ?: "Catalogue"
|
||||||
|
results.add(Suggestion.RoomCatalog(item, catName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
staticCatalogItems.forEach { item ->
|
||||||
|
if (results.none { it.label.equals(item.name, ignoreCase = true) }) {
|
||||||
|
results.add(Suggestion.Catalog(item))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.forEach { results.add(Suggestion.Catalog(it)) }
|
|
||||||
|
|
||||||
// 4) Création d'un own item si aucune correspondance exacte
|
// 4) Création d'un own item si aucune correspondance exacte
|
||||||
val exact = results.any { it.label.equals(query, ignoreCase = true) }
|
val exact = results.any { it.label.equals(query, ignoreCase = true) }
|
||||||
@ -184,6 +209,7 @@ class ListDetailViewModel @Inject constructor(
|
|||||||
results.add(0, Suggestion.Create(query))
|
results.add(0, Suggestion.Create(query))
|
||||||
}
|
}
|
||||||
results
|
results
|
||||||
|
}
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
||||||
|
|
||||||
// ── Actions ─────────────────────────────────────────────────────────────
|
// ── Actions ─────────────────────────────────────────────────────────────
|
||||||
@ -203,6 +229,7 @@ class ListDetailViewModel @Inject constructor(
|
|||||||
fun applySuggestion(suggestion: Suggestion) {
|
fun applySuggestion(suggestion: Suggestion) {
|
||||||
when (suggestion) {
|
when (suggestion) {
|
||||||
is Suggestion.Catalog -> addCatalogItem(suggestion.item)
|
is Suggestion.Catalog -> addCatalogItem(suggestion.item)
|
||||||
|
is Suggestion.RoomCatalog -> addCatalogItem(suggestion.item)
|
||||||
is Suggestion.Recent -> restoreItem(suggestion.item.id)
|
is Suggestion.Recent -> restoreItem(suggestion.item.id)
|
||||||
is Suggestion.Active -> { /* déjà sur la liste, ne fait rien */ }
|
is Suggestion.Active -> { /* déjà sur la liste, ne fait rien */ }
|
||||||
is Suggestion.Create -> addCustomItem(suggestion.rawText)
|
is Suggestion.Create -> addCustomItem(suggestion.rawText)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
MAJOR=1
|
MAJOR=1
|
||||||
MINOR=22
|
MINOR=24
|
||||||
PATCH=0
|
PATCH=0
|
||||||
CODE=33
|
CODE=35
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user