feat: add genre support to catalog sources and update UI accordingly

This commit is contained in:
tapframe 2026-04-15 17:07:02 +05:30
parent d44d3ea002
commit 7727436272
5 changed files with 77 additions and 3 deletions

View file

@ -202,10 +202,12 @@ object CollectionEditorRepository {
fun addCatalogSource(catalog: AvailableCatalog) { fun addCatalogSource(catalog: AvailableCatalog) {
val folder = _uiState.value.editingFolder ?: return val folder = _uiState.value.editingFolder ?: return
val defaultGenre = if (catalog.genreRequired) catalog.genreOptions.firstOrNull() else null
val source = CollectionCatalogSource( val source = CollectionCatalogSource(
addonId = catalog.addonId, addonId = catalog.addonId,
type = catalog.type, type = catalog.type,
catalogId = catalog.catalogId, catalogId = catalog.catalogId,
genre = defaultGenre,
) )
if (folder.catalogSources.any { if (folder.catalogSources.any {
it.addonId == source.addonId && it.type == source.type && it.catalogId == source.catalogId it.addonId == source.addonId && it.type == source.type && it.catalogId == source.catalogId
@ -225,6 +227,16 @@ object CollectionEditorRepository {
) )
} }
fun updateCatalogSourceGenre(index: Int, genre: String?) {
val folder = _uiState.value.editingFolder ?: return
if (index !in folder.catalogSources.indices) return
val updated = folder.catalogSources.toMutableList()
updated[index] = updated[index].copy(genre = genre)
_uiState.value = _uiState.value.copy(
editingFolder = folder.copy(catalogSources = updated),
)
}
fun toggleCatalogSource(catalog: AvailableCatalog) { fun toggleCatalogSource(catalog: AvailableCatalog) {
val folder = _uiState.value.editingFolder ?: return val folder = _uiState.value.editingFolder ?: return
val existingIndex = folder.catalogSources.indexOfFirst { val existingIndex = folder.catalogSources.indexOfFirst {

View file

@ -697,6 +697,10 @@ private fun FolderEditorSheet(
} }
itemsIndexed(folder.catalogSources) { index, source -> itemsIndexed(folder.catalogSources) { index, source ->
val matchingCatalog = state.availableCatalogs.find {
it.addonId == source.addonId && it.type == source.type && it.catalogId == source.catalogId
}
val genreOptions = matchingCatalog?.genreOptions.orEmpty()
NuvioSurfaceCard { NuvioSurfaceCard {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@ -711,7 +715,10 @@ private fun FolderEditorSheet(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
Text( Text(
text = source.addonId, text = buildString {
append(source.addonId)
if (source.genre != null) append(" · ${source.genre}")
},
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1, maxLines = 1,
@ -730,6 +737,51 @@ private fun FolderEditorSheet(
) )
} }
} }
if (genreOptions.isNotEmpty()) {
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Genre",
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface,
)
Spacer(modifier = Modifier.height(4.dp))
FlowRow(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
FilterChip(
selected = source.genre == null,
onClick = { CollectionEditorRepository.updateCatalogSourceGenre(index, null) },
label = { Text("All") },
leadingIcon = if (source.genre == null) {
{
Icon(
imageVector = Icons.Rounded.Check,
contentDescription = null,
modifier = Modifier.size(18.dp),
)
}
} else null,
)
genreOptions.forEach { genre ->
FilterChip(
selected = source.genre == genre,
onClick = { CollectionEditorRepository.updateCatalogSourceGenre(index, genre) },
label = { Text(genre) },
leadingIcon = if (source.genre == genre) {
{
Icon(
imageVector = Icons.Rounded.Check,
contentDescription = null,
modifier = Modifier.size(18.dp),
)
}
} else null,
)
}
}
}
} }
} }

View file

@ -27,6 +27,7 @@ data class CollectionCatalogSource(
val addonId: String, val addonId: String,
val type: String, val type: String,
val catalogId: String, val catalogId: String,
val genre: String? = null,
) )
@Immutable @Immutable
@ -73,6 +74,8 @@ data class AvailableCatalog(
val type: String, val type: String,
val catalogId: String, val catalogId: String,
val catalogName: String, val catalogName: String,
val genreOptions: List<String> = emptyList(),
val genreRequired: Boolean = false,
) )
@Serializable @Serializable

View file

@ -157,14 +157,17 @@ object CollectionRepository {
addon to manifest addon to manifest
}.flatMap { (addon, manifest) -> }.flatMap { (addon, manifest) ->
manifest.catalogs manifest.catalogs
.filter { catalog -> catalog.extra.none { it.isRequired } } .filter { catalog -> catalog.extra.none { it.isRequired && it.name != "genre" } }
.map { catalog -> .map { catalog ->
val genreExtra = catalog.extra.firstOrNull { it.name == "genre" }
AvailableCatalog( AvailableCatalog(
addonId = manifest.id, addonId = manifest.id,
addonName = addon.displayTitle, addonName = addon.displayTitle,
type = catalog.type, type = catalog.type,
catalogId = catalog.id, catalogId = catalog.id,
catalogName = catalog.name, catalogName = catalog.name,
genreOptions = genreExtra?.options.orEmpty(),
genreRequired = genreExtra?.isRequired == true,
) )
} }
} }

View file

@ -24,6 +24,7 @@ data class FolderTab(
val manifestUrl: String? = null, val manifestUrl: String? = null,
val type: String = "", val type: String = "",
val catalogId: String = "", val catalogId: String = "",
val genre: String? = null,
val supportsPagination: Boolean = false, val supportsPagination: Boolean = false,
val items: List<MetaPreview> = emptyList(), val items: List<MetaPreview> = emptyList(),
val isLoading: Boolean = true, val isLoading: Boolean = true,
@ -123,13 +124,15 @@ object FolderDetailRepository {
val typeLabel = source.type.replaceFirstChar { val typeLabel = source.type.replaceFirstChar {
if (it.isLowerCase()) it.titlecase() else it.toString() if (it.isLowerCase()) it.titlecase() else it.toString()
} }
val genreSuffix = if (source.genre != null) " · ${source.genre}" else ""
add( add(
FolderTab( FolderTab(
label = "$label ($typeLabel)", label = "$label ($typeLabel)$genreSuffix",
typeLabel = typeLabel, typeLabel = typeLabel,
manifestUrl = addon?.manifestUrl, manifestUrl = addon?.manifestUrl,
type = source.type, type = source.type,
catalogId = source.catalogId, catalogId = source.catalogId,
genre = source.genre,
supportsPagination = catalog?.supportsPagination() == true, supportsPagination = catalog?.supportsPagination() == true,
isLoading = true, isLoading = true,
), ),
@ -236,6 +239,7 @@ object FolderDetailRepository {
manifestUrl = manifestUrl, manifestUrl = manifestUrl,
type = currentTab.type, type = currentTab.type,
catalogId = currentTab.catalogId, catalogId = currentTab.catalogId,
genre = currentTab.genre,
skip = requestedSkip.takeIf { it > 0 }, skip = requestedSkip.takeIf { it > 0 },
) )
}.onSuccess { page -> }.onSuccess { page ->