diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeader2AD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeader2AD.kt index 068ad74bc..843c1f18f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeader2AD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeader2AD.kt @@ -29,7 +29,7 @@ fun listHeader2AD( binding.scrollView.smoothScrollTo(0, 0) } ignoreChecking = true - binding.chipsTags.setChips(item.chips) + binding.chipsTags.setChips(item.chips) // TODO use recyclerview ignoreChecking = false binding.textViewFilter.setTextAndVisible(item.sortOrder?.titleRes ?: 0) } diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt index d01cac4f1..310d2366f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterCoordinator.kt @@ -30,7 +30,7 @@ class FilterCoordinator( private var availableTagsDeferred = loadTagsAsync() val items: LiveData> = getItemsFlow() - .asLiveDataDistinct(coroutineScope.coroutineContext + Dispatchers.Default) + .asLiveDataDistinct(coroutineScope.coroutineContext + Dispatchers.Default, listOf(FilterItem.Loading)) init { observeState() @@ -54,6 +54,13 @@ class FilterCoordinator( } } + fun observeAvailableTags(): Flow?> = flow { + if (!availableTagsDeferred.isCompleted) { + emit(emptySet()) + } + emit(availableTagsDeferred.await()) + } + fun observeState() = currentState.asStateFlow() fun setTags(tags: Set) { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListHeader2.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListHeader2.kt index 95fc79c4e..0f053bfd6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListHeader2.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListHeader2.kt @@ -3,7 +3,28 @@ package org.koitharu.kotatsu.list.ui.model import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.parsers.model.SortOrder -data class ListHeader2( +class ListHeader2( val chips: Collection, val sortOrder: SortOrder?, -) : ListModel \ No newline at end of file + val hasSelectedTags: Boolean, +) : ListModel { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ListHeader2 + + if (chips != other.chips) return false + if (sortOrder != other.sortOrder) return false + // Not need to check hasSelectedTags + + return true + } + + override fun hashCode(): Int { + var result = chips.hashCode() + result = 31 * result + (sortOrder?.hashCode() ?: 0) + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index cdaac9e12..0c4fdd362 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -45,16 +45,16 @@ class RemoteListViewModel( override val content = combine( mangaList, createListModeFlow(), - filter.observeState(), + createHeaderFlow(), listError, hasNextPage, - ) { list, mode, filterState, error, hasNext -> + ) { list, mode, header, error, hasNext -> buildList(list?.size?.plus(2) ?: 2) { - add(ListHeader2(createChipsList(filterState), filterState.sortOrder)) + add(header) when { list.isNullOrEmpty() && error != null -> add(error.toErrorState(canRetry = true)) list == null -> add(LoadingState) - list.isEmpty() -> add(createEmptyState(filterState)) + list.isEmpty() -> add(createEmptyState(header.hasSelectedTags)) else -> { list.toUi(this, mode) when { @@ -64,10 +64,7 @@ class RemoteListViewModel( } } } - }.asLiveDataDistinct( - viewModelScope.coroutineContext + Dispatchers.Default, - listOf(ListHeader(repository.source.title, 0, null), LoadingState), - ) + }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) init { filter.observeState() @@ -144,16 +141,33 @@ class RemoteListViewModel( } } - private fun createEmptyState(filterState: FilterState) = EmptyState( + private fun createEmptyState(canResetFilter: Boolean) = EmptyState( icon = R.drawable.ic_empty_search, textPrimary = R.string.nothing_found, textSecondary = 0, - actionStringRes = if (filterState.tags.isEmpty()) 0 else R.string.reset_filter, + actionStringRes = if (canResetFilter) R.string.reset_filter else 0, ) - private suspend fun createChipsList(filterState: FilterState): List { + private fun createHeaderFlow() = combine( + filter.observeState(), + filter.observeAvailableTags(), + ) { state, available -> + val chips = createChipsList(state, available.orEmpty()) + ListHeader2(chips, state.sortOrder, state.tags.isNotEmpty()) + } + + private suspend fun createChipsList( + filterState: FilterState, + availableTags: Set + ): List { val selectedTags = filterState.tags.toMutableSet() - val tags = searchRepository.getTagsSuggestion("", 6, repository.source) + var tags = searchRepository.getTagsSuggestion("", 6, repository.source) + if (tags.isEmpty()) { + tags = availableTags.take(6) + } + if (tags.isEmpty() && selectedTags.isEmpty()) { + return emptyList() + } val result = LinkedList() for (tag in tags) { val model = ChipsView.ChipModel(