Improve filter
This commit is contained in:
@@ -332,6 +332,15 @@ class FilterCoordinator @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleDemographic(value: Demographic, isSelected: Boolean) {
|
||||
currentListFilter.update { oldValue ->
|
||||
oldValue.copy(
|
||||
demographics = if (isSelected) oldValue.demographics + value else oldValue.demographics - value,
|
||||
query = oldValue.takeQueryIfSupported(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleContentType(value: ContentType, isSelected: Boolean) {
|
||||
currentListFilter.update { oldValue ->
|
||||
oldValue.copy(
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.core.view.isInvisible
|
||||
@@ -68,6 +69,10 @@ class FilterFieldLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setTitle(@StringRes titleResId: Int) {
|
||||
binding.textViewTitle.setText(titleResId)
|
||||
}
|
||||
|
||||
fun setError(errorMessage: String?) {
|
||||
if (errorMessage == null && errorView == null) {
|
||||
return
|
||||
|
||||
@@ -16,7 +16,13 @@ import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.databinding.FragmentFilterHeaderBinding
|
||||
import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel
|
||||
import org.koitharu.kotatsu.filter.ui.tags.TagsCatalogSheet
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Demographic
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.YEAR_UNKNOWN
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -55,6 +61,13 @@ class FilterHeaderFragment : BaseFragment<FragmentFilterHeaderBinding>(), ChipsV
|
||||
override fun onChipCloseClick(chip: Chip, data: Any?) {
|
||||
when (data) {
|
||||
is String -> filter.setQuery(null)
|
||||
is ContentRating -> filter.toggleContentRating(data, false)
|
||||
is Demographic -> filter.toggleDemographic(data, false)
|
||||
is ContentType -> filter.toggleContentType(data, false)
|
||||
is MangaState -> filter.toggleState(data, false)
|
||||
is Locale -> filter.setLocale(null)
|
||||
is Int -> filter.setYear(YEAR_UNKNOWN)
|
||||
is IntRange -> filter.setYearRange(YEAR_UNKNOWN, YEAR_UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,15 @@ package org.koitharu.kotatsu.filter.ui
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.titleResId
|
||||
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.MangaListFilter
|
||||
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.parsers.util.toTitleCase
|
||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
@@ -18,15 +21,14 @@ class FilterHeaderProducer @Inject constructor(
|
||||
) {
|
||||
|
||||
fun observeHeader(filterCoordinator: FilterCoordinator): Flow<FilterHeaderModel> {
|
||||
return combine(filterCoordinator.tags, filterCoordinator.query) { tags, query ->
|
||||
createChipsList(
|
||||
return combine(filterCoordinator.tags, filterCoordinator.observe()) { tags, snapshot ->
|
||||
val chipList = createChipsList(
|
||||
source = filterCoordinator.mangaSource,
|
||||
capabilities = filterCoordinator.capabilities,
|
||||
property = tags,
|
||||
query = query,
|
||||
tagsProperty = tags,
|
||||
snapshot = snapshot.listFilter,
|
||||
limit = 8,
|
||||
)
|
||||
}.combine(filterCoordinator.observe()) { chipList, snapshot ->
|
||||
FilterHeaderModel(
|
||||
chips = chipList,
|
||||
sortOrder = snapshot.sortOrder,
|
||||
@@ -38,20 +40,20 @@ class FilterHeaderProducer @Inject constructor(
|
||||
private suspend fun createChipsList(
|
||||
source: MangaSource,
|
||||
capabilities: MangaListFilterCapabilities,
|
||||
property: FilterProperty<MangaTag>,
|
||||
query: String?,
|
||||
tagsProperty: FilterProperty<MangaTag>,
|
||||
snapshot: MangaListFilter,
|
||||
limit: Int,
|
||||
): List<ChipsView.ChipModel> {
|
||||
val result = ArrayDeque<ChipsView.ChipModel>(limit + 3)
|
||||
if (query.isNullOrEmpty() || capabilities.isSearchWithFiltersSupported) {
|
||||
val selectedTags = property.selectedItems.toMutableSet()
|
||||
if (snapshot.query.isNullOrEmpty() || capabilities.isSearchWithFiltersSupported) {
|
||||
val selectedTags = tagsProperty.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)
|
||||
tags = tags + tagsProperty.availableItems.take(limit - tags.size)
|
||||
}
|
||||
if (tags.isEmpty() && selectedTags.isEmpty()) {
|
||||
return emptyList()
|
||||
@@ -77,13 +79,59 @@ class FilterHeaderProducer @Inject constructor(
|
||||
result.addFirst(model)
|
||||
}
|
||||
}
|
||||
if (!query.isNullOrEmpty()) {
|
||||
snapshot.locale?.let {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
title = query,
|
||||
title = it.getDisplayName(it).toTitleCase(it),
|
||||
icon = R.drawable.ic_language,
|
||||
isCloseable = true,
|
||||
data = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
snapshot.types.forEach {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
titleResId = it.titleResId,
|
||||
isCloseable = true,
|
||||
data = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
snapshot.demographics.forEach {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
titleResId = it.titleResId,
|
||||
isCloseable = true,
|
||||
data = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
snapshot.contentRating.forEach {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
titleResId = it.titleResId,
|
||||
isCloseable = true,
|
||||
data = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
snapshot.states.forEach {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
titleResId = it.titleResId,
|
||||
isCloseable = true,
|
||||
data = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (!snapshot.query.isNullOrEmpty()) {
|
||||
result.addFirst(
|
||||
ChipsView.ChipModel(
|
||||
title = snapshot.query,
|
||||
icon = materialR.drawable.abc_ic_search_api_material,
|
||||
isCloseable = true,
|
||||
data = query,
|
||||
data = snapshot.query,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -97,6 +145,5 @@ class FilterHeaderProducer @Inject constructor(
|
||||
private fun moreTagsChip() = ChipsView.ChipModel(
|
||||
titleResId = R.string.more,
|
||||
isDropdown = true,
|
||||
// icon = materialR.drawable.abc_ic_menu_overflow_material,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,12 +68,20 @@ class FilterSheetFragment : BaseAdaptiveSheet<SheetFilterBinding>(),
|
||||
filter.year.observe(viewLifecycleOwner, this::onYearChanged)
|
||||
filter.yearRange.observe(viewLifecycleOwner, this::onYearRangeChanged)
|
||||
|
||||
binding.layoutGenres.setTitle(
|
||||
if (filter.capabilities.isMultipleTagsSupported) {
|
||||
R.string.genres
|
||||
} else {
|
||||
R.string.genre
|
||||
},
|
||||
)
|
||||
binding.spinnerLocale.onItemSelectedListener = this
|
||||
binding.spinnerOriginalLocale.onItemSelectedListener = this
|
||||
binding.spinnerOrder.onItemSelectedListener = this
|
||||
binding.chipsState.onChipClickListener = this
|
||||
binding.chipsTypes.onChipClickListener = this
|
||||
binding.chipsContentRating.onChipClickListener = this
|
||||
binding.chipsDemographics.onChipClickListener = this
|
||||
binding.chipsGenres.onChipClickListener = this
|
||||
binding.chipsGenresExclude.onChipClickListener = this
|
||||
binding.sliderYear.addOnChangeListener(this::onSliderValueChange)
|
||||
@@ -143,6 +151,7 @@ class FilterSheetFragment : BaseAdaptiveSheet<SheetFilterBinding>(),
|
||||
|
||||
is ContentType -> filter.toggleContentType(data, !chip.isChecked)
|
||||
is ContentRating -> filter.toggleContentRating(data, !chip.isChecked)
|
||||
is Demographic -> filter.toggleDemographic(data, !chip.isChecked)
|
||||
null -> TagsCatalogSheet.show(getChildFragmentManager(), chip.parentView?.id == R.id.chips_genresExclude)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,4 +741,5 @@
|
||||
<string name="start_download">Start download</string>
|
||||
<string name="save_manga_confirm">Save selected manga? This may consume traffic and disk space</string>
|
||||
<string name="save_manga">Save manga</string>
|
||||
<string name="genre">Genre</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user