Handle filter loading errors
This commit is contained in:
@@ -10,4 +10,5 @@ class FilterAdapter(
|
||||
filterTagDelegate(listener),
|
||||
filterHeaderDelegate(),
|
||||
filterLoadingDelegate(),
|
||||
filterErrorDelegate(),
|
||||
)
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.koitharu.kotatsu.list.ui.filter
|
||||
|
||||
import android.widget.TextView
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableMultipleBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableSingleBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemFilterHeaderBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemLoadingFooterBinding
|
||||
|
||||
fun filterSortDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
@@ -47,6 +49,11 @@ fun filterHeaderDelegate() = adapterDelegateViewBinding<FilterItem.Header, Filte
|
||||
}
|
||||
}
|
||||
|
||||
fun filterLoadingDelegate() = adapterDelegateViewBinding<FilterItem.Loading, FilterItem, ItemLoadingFooterBinding>(
|
||||
{ layoutInflater, parent -> ItemLoadingFooterBinding.inflate(layoutInflater, parent, false) }
|
||||
) { }
|
||||
fun filterLoadingDelegate() = adapterDelegate<FilterItem.Loading, FilterItem>(R.layout.item_loading_footer) {}
|
||||
|
||||
fun filterErrorDelegate() = adapterDelegate<FilterItem.Error, FilterItem>(R.layout.item_sources_empty) {
|
||||
|
||||
bind {
|
||||
(itemView as TextView).setText(item.textResId)
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,18 @@ class FilterDiffCallback : DiffUtil.ItemCallback<FilterItem>() {
|
||||
oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> {
|
||||
oldItem.order == newItem.order
|
||||
}
|
||||
oldItem is FilterItem.Error && newItem is FilterItem.Error -> {
|
||||
oldItem.textResId == newItem.textResId
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: FilterItem, newItem: FilterItem): Boolean {
|
||||
return when {
|
||||
oldItem === newItem -> true
|
||||
oldItem == FilterItem.Loading && newItem == FilterItem.Loading -> true
|
||||
oldItem is FilterItem.Header && newItem is FilterItem.Header -> true
|
||||
oldItem is FilterItem.Error && newItem is FilterItem.Error -> true
|
||||
oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> {
|
||||
oldItem.isChecked == newItem.isChecked
|
||||
}
|
||||
|
||||
@@ -21,4 +21,8 @@ sealed interface FilterItem {
|
||||
) : FilterItem
|
||||
|
||||
object Loading : FilterItem
|
||||
|
||||
class Error(
|
||||
@StringRes val textResId: Int,
|
||||
) : FilterItem
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import kotlinx.coroutines.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
import org.koitharu.kotatsu.core.model.SortOrder
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import java.util.*
|
||||
@@ -21,12 +22,10 @@ class FilterViewModel(
|
||||
private var job: Job? = null
|
||||
private var selectedSortOrder: SortOrder? = state.sortOrder
|
||||
private val selectedTags = HashSet(state.tags)
|
||||
private val availableTagsDeferred = viewModelScope.async(Dispatchers.Default + createErrorHandler()) {
|
||||
repository.getTags()
|
||||
}
|
||||
private val localTagsDeferred = viewModelScope.async(Dispatchers.Default + createErrorHandler()) {
|
||||
private val localTagsDeferred = viewModelScope.async(Dispatchers.Default) {
|
||||
dataRepository.findTags(repository.source)
|
||||
}
|
||||
private var availableTagsDeferred = loadTagsAsync()
|
||||
|
||||
init {
|
||||
showFilter()
|
||||
@@ -52,21 +51,24 @@ class FilterViewModel(
|
||||
val previousJob = job
|
||||
job = launchJob(Dispatchers.Default) {
|
||||
previousJob?.cancelAndJoin()
|
||||
val tags = availableTagsDeferred.await()
|
||||
val tags = tryLoadTags()
|
||||
val localTags = localTagsDeferred.await()
|
||||
val sortOrders = repository.sortOrders
|
||||
val list = ArrayList<FilterItem>(sortOrders.size + tags.size + 2)
|
||||
val list = ArrayList<FilterItem>(sortOrders.size + (tags?.size ?: 1) + 2)
|
||||
list.add(FilterItem.Header(R.string.sort_order))
|
||||
sortOrders.sortedBy { it.ordinal }.mapTo(list) {
|
||||
FilterItem.Sort(it, isSelected = it == selectedSortOrder)
|
||||
}
|
||||
if (tags.isNotEmpty() || selectedTags.isNotEmpty()) {
|
||||
if (tags == null || tags.isNotEmpty() || selectedTags.isNotEmpty()) {
|
||||
list.add(FilterItem.Header(R.string.genres))
|
||||
val mappedTags = TreeSet<FilterItem.Tag>(compareBy({ !it.isChecked }, { it.tag.title }))
|
||||
localTags.mapTo(mappedTags) { FilterItem.Tag(it, isChecked = it in selectedTags) }
|
||||
tags.mapTo(mappedTags) { FilterItem.Tag(it, isChecked = it in selectedTags) }
|
||||
tags?.mapTo(mappedTags) { FilterItem.Tag(it, isChecked = it in selectedTags) }
|
||||
selectedTags.mapTo(mappedTags) { FilterItem.Tag(it, isChecked = true) }
|
||||
list.addAll(mappedTags)
|
||||
if (tags == null) {
|
||||
list.add(FilterItem.Error(R.string.filter_load_error))
|
||||
}
|
||||
}
|
||||
ensureActive()
|
||||
filter.postValue(list)
|
||||
@@ -93,4 +95,20 @@ class FilterViewModel(
|
||||
updateFilters()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun tryLoadTags(): Set<MangaTag>? {
|
||||
val shouldRetryOnError = availableTagsDeferred.isCompleted
|
||||
val result = availableTagsDeferred.await()
|
||||
if (result == null && shouldRetryOnError) {
|
||||
availableTagsDeferred = loadTagsAsync()
|
||||
return availableTagsDeferred.await()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun loadTagsAsync() = viewModelScope.async(Dispatchers.Default) {
|
||||
kotlin.runCatching {
|
||||
repository.getTags()
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
@@ -253,4 +253,5 @@
|
||||
<string name="screenshots_allow">Разрешить</string>
|
||||
<string name="screenshots_block_nsfw">Запретить для NSFW</string>
|
||||
<string name="screenshots_block_all">Запретить всегда</string>
|
||||
<string name="filter_load_error">Не удалось загрузить список жанров</string>
|
||||
</resources>
|
||||
@@ -255,4 +255,5 @@
|
||||
<string name="screenshots_allow">Allow</string>
|
||||
<string name="screenshots_block_nsfw">Block on NSFW</string>
|
||||
<string name="screenshots_block_all">Block always</string>
|
||||
<string name="filter_load_error">Unable to load genres list</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user