Fix sources catalog content types

This commit is contained in:
Koitharu
2024-09-24 10:18:10 +03:00
parent bc4622d610
commit a7a0a7f0db
8 changed files with 70 additions and 44 deletions

View File

@@ -80,6 +80,7 @@ val Demographic.titleResId: Int
Demographic.SHOUJO -> R.string.demographic_shoujo
Demographic.SEINEN -> R.string.demographic_seinen
Demographic.JOSEI -> R.string.demographic_josei
Demographic.KODOMO -> R.string.demographic_kodomo
Demographic.NONE -> R.string.none
}

View File

@@ -61,6 +61,7 @@ val ContentType.titleResId
ContentType.MANHWA -> R.string.content_type_manhwa
ContentType.MANHUA -> R.string.content_type_manhua
ContentType.NOVEL -> R.string.content_type_novel
ContentType.ONE_SHOT -> R.string.content_type_one_shot
}
tailrec fun MangaSource.unwrap(): MangaSource = if (this is MangaSourceInfo) {

View File

@@ -89,7 +89,7 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
is HttpException -> getHttpDisplayMessage(response.code, resources)
is HttpStatusException -> getHttpDisplayMessage(statusCode, resources)
else -> getDisplayMessage(message, resources) ?: localizedMessage
else -> getDisplayMessage(message, resources) ?: message
}.ifNullOrEmpty {
resources.getString(R.string.error_occurred)
}

View File

@@ -5,6 +5,7 @@ import kotlinx.coroutines.flow.combine
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel
import org.koitharu.kotatsu.filter.ui.model.FilterProperty
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
@@ -19,6 +20,7 @@ class FilterHeaderProducer @Inject constructor(
return combine(filterCoordinator.tags, filterCoordinator.query) { tags, query ->
createChipsList(
source = filterCoordinator.mangaSource,
capabilities = filterCoordinator.capabilities,
property = tags,
query = query,
limit = 8,
@@ -34,42 +36,45 @@ class FilterHeaderProducer @Inject constructor(
private suspend fun createChipsList(
source: MangaSource,
capabilities: MangaListFilterCapabilities,
property: FilterProperty<MangaTag>,
query: String?,
limit: Int,
): List<ChipsView.ChipModel> {
val selectedTags = property.selectedItems.toMutableSet()
var tags = if (selectedTags.isEmpty()) {
searchRepository.getTagsSuggestion("", limit, source)
} else {
searchRepository.getTagsSuggestion(selectedTags).take(limit)
}
if (tags.size < limit) {
tags = tags + property.availableItems.take(limit - tags.size)
}
if (tags.isEmpty() && selectedTags.isEmpty()) {
return emptyList()
}
val result = ArrayDeque<ChipsView.ChipModel>(tags.size + selectedTags.size + 1)
for (tag in tags) {
val model = ChipsView.ChipModel(
title = tag.title,
isChecked = selectedTags.remove(tag),
data = tag,
)
if (model.isChecked) {
result.addFirst(model)
val result = ArrayDeque<ChipsView.ChipModel>(limit + 3)
if (query.isNullOrEmpty() || capabilities.isSearchWithFiltersSupported) {
val selectedTags = property.selectedItems.toMutableSet()
var tags = if (selectedTags.isEmpty()) {
searchRepository.getTagsSuggestion("", limit, source)
} else {
result.addLast(model)
searchRepository.getTagsSuggestion(selectedTags).take(limit)
}
if (tags.size < limit) {
tags = tags + property.availableItems.take(limit - tags.size)
}
if (tags.isEmpty() && selectedTags.isEmpty()) {
return emptyList()
}
for (tag in tags) {
val model = ChipsView.ChipModel(
title = tag.title,
isChecked = selectedTags.remove(tag),
data = tag,
)
if (model.isChecked) {
result.addFirst(model)
} else {
result.addLast(model)
}
}
for (tag in selectedTags) {
val model = ChipsView.ChipModel(
title = tag.title,
isChecked = true,
data = tag,
)
result.addFirst(model)
}
}
for (tag in selectedTags) {
val model = ChipsView.ChipModel(
title = tag.title,
isChecked = true,
data = tag,
)
result.addFirst(model)
}
if (!query.isNullOrEmpty()) {
result.addFirst(

View File

@@ -64,8 +64,8 @@ class SourcesCatalogActivity : BaseActivity<ActivitySourcesCatalogBinding>(),
this,
ReversibleActionObserver(viewBinding.recyclerView),
)
combine(viewModel.appliedFilter, viewModel.hasNewSources, ::Pair).observe(this) {
updateFilers(it.first, it.second)
combine(viewModel.appliedFilter, viewModel.hasNewSources, viewModel.contentTypes, ::Triple).observe(this) {
updateFilers(it.first, it.second, it.third)
}
addMenuProvider(SourcesCatalogMenuProvider(this, viewModel, this))
}
@@ -111,8 +111,9 @@ class SourcesCatalogActivity : BaseActivity<ActivitySourcesCatalogBinding>(),
private fun updateFilers(
appliedFilter: SourcesCatalogFilter,
hasNewSources: Boolean,
contentTypes: List<ContentType>,
) {
val chips = ArrayList<ChipModel>(ContentType.entries.size + 2)
val chips = ArrayList<ChipModel>(contentTypes.size + 2)
chips += ChipModel(
title = appliedFilter.locale?.toLocale().getDisplayName(this),
icon = R.drawable.ic_language,
@@ -126,11 +127,8 @@ class SourcesCatalogActivity : BaseActivity<ActivitySourcesCatalogBinding>(),
data = true,
)
}
for (type in ContentType.entries) {
if (type == ContentType.HENTAI && viewModel.isNsfwDisabled) {
continue
}
chips += ChipModel(
contentTypes.mapTo(chips) { type ->
ChipModel(
title = getString(type.titleResId),
isChecked = type in appliedFilter.types,
data = type,

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.settings.sources.catalog
import androidx.annotation.WorkerThread
import androidx.lifecycle.viewModelScope
import androidx.room.invalidationTrackerFlow
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -13,6 +14,7 @@ import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.TABLE_SOURCES
import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
@@ -23,7 +25,9 @@ import org.koitharu.kotatsu.explore.data.SourcesSortOrder
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource
import java.util.EnumMap
import java.util.EnumSet
import java.util.Locale
import javax.inject.Inject
@@ -49,11 +53,11 @@ class SourcesCatalogViewModel @Inject constructor(
),
)
val isNsfwDisabled = settings.isNsfwContentDisabled
val hasNewSources = repository.observeHasNewSources()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, false)
val contentTypes = MutableStateFlow<List<ContentType>>(emptyList())
val content: StateFlow<List<ListModel>> = combine(
searchQuery,
appliedFilter,
@@ -64,6 +68,9 @@ class SourcesCatalogViewModel @Inject constructor(
init {
repository.clearNewSourcesBadge()
launchJob(Dispatchers.Default) {
contentTypes.value = getContentTypes(settings.isNsfwContentDisabled)
}
}
fun performSearch(query: String?) {
@@ -129,4 +136,16 @@ class SourcesCatalogViewModel @Inject constructor(
}
}
}
@WorkerThread
private fun getContentTypes(isNsfwDisabled: Boolean): List<ContentType> {
val map = EnumMap<ContentType, Int>(ContentType::class.java)
for (e in MangaParserSource.entries) {
if (isNsfwDisabled && e.isNsfw()) {
continue
}
map[e.contentType] = map.getOrDefault(e.contentType, 0) + 1
}
return map.entries.sortedByDescending { it.value }.map { it.key }
}
}

View File

@@ -727,4 +727,6 @@
<string name="years">Years</string>
<string name="any">Any</string>
<string name="filter_search_warning">This source does not support search with filters. Your filters have been cleared</string>
<string name="demographic_kodomo">Kodomo</string>
<string name="content_type_one_shot">One shot</string>
</resources>