|
|
|
@ -62,6 +62,7 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
dataRepository.findTags(repository.source)
|
|
|
|
dataRepository.findTags(repository.source)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private var availableTagsDeferred = loadTagsAsync()
|
|
|
|
private var availableTagsDeferred = loadTagsAsync()
|
|
|
|
|
|
|
|
private var availableLocalesDeferred = loadLocalesAsync()
|
|
|
|
|
|
|
|
|
|
|
|
override val filterItems: StateFlow<List<ListModel>> = getItemsFlow()
|
|
|
|
override val filterItems: StateFlow<List<ListModel>> = getItemsFlow()
|
|
|
|
.stateIn(coroutineScope + Dispatchers.Default, SharingStarted.Lazily, listOf(LoadingState))
|
|
|
|
.stateIn(coroutineScope + Dispatchers.Default, SharingStarted.Lazily, listOf(LoadingState))
|
|
|
|
@ -120,12 +121,18 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onLanguageItemClick(item: FilterItem.Language) {
|
|
|
|
|
|
|
|
currentState.update { oldValue ->
|
|
|
|
|
|
|
|
oldValue.copy(locale = item.locale)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onListHeaderClick(item: ListHeader, view: View) {
|
|
|
|
override fun onListHeaderClick(item: ListHeader, view: View) {
|
|
|
|
currentState.update { oldValue ->
|
|
|
|
currentState.update { oldValue ->
|
|
|
|
oldValue.copy(
|
|
|
|
oldValue.copy(
|
|
|
|
sortOrder = oldValue.sortOrder,
|
|
|
|
sortOrder = oldValue.sortOrder,
|
|
|
|
tags = if (item.payload == R.string.genres) emptySet() else oldValue.tags,
|
|
|
|
tags = if (item.payload == R.string.genres) emptySet() else oldValue.tags,
|
|
|
|
locale = null,
|
|
|
|
locale = if (item.payload == R.string.language) null else oldValue.locale,
|
|
|
|
states = if (item.payload == R.string.state) emptySet() else oldValue.states,
|
|
|
|
states = if (item.payload == R.string.state) emptySet() else oldValue.states,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -173,20 +180,31 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
|
|
|
|
|
|
|
|
private fun getItemsFlow() = combine(
|
|
|
|
private fun getItemsFlow() = combine(
|
|
|
|
getTagsAsFlow(),
|
|
|
|
getTagsAsFlow(),
|
|
|
|
|
|
|
|
getLocalesAsFlow(),
|
|
|
|
currentState,
|
|
|
|
currentState,
|
|
|
|
searchQuery,
|
|
|
|
searchQuery,
|
|
|
|
) { tags, state, query ->
|
|
|
|
) { tags, locales, state, query ->
|
|
|
|
buildFilterList(tags, state, query)
|
|
|
|
buildFilterList(tags, locales, state, query)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun getTagsAsFlow() = flow {
|
|
|
|
private fun getTagsAsFlow() = flow {
|
|
|
|
val localTags = localTags.get()
|
|
|
|
val localTags = localTags.get()
|
|
|
|
emit(TagsWrapper(localTags, isLoading = true, isError = false))
|
|
|
|
emit(PendingSet(localTags, isLoading = true, isError = false))
|
|
|
|
val remoteTags = tryLoadTags()
|
|
|
|
val remoteTags = tryLoadTags()
|
|
|
|
if (remoteTags == null) {
|
|
|
|
if (remoteTags == null) {
|
|
|
|
emit(TagsWrapper(localTags, isLoading = false, isError = true))
|
|
|
|
emit(PendingSet(localTags, isLoading = false, isError = true))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
emit(TagsWrapper(mergeTags(remoteTags, localTags), isLoading = false, isError = false))
|
|
|
|
emit(PendingSet(mergeTags(remoteTags, localTags), isLoading = false, isError = false))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun getLocalesAsFlow(): Flow<PendingSet<Locale>> = flow {
|
|
|
|
|
|
|
|
emit(PendingSet(emptySet(), isLoading = true, isError = false))
|
|
|
|
|
|
|
|
val locales = tryLoadLocales()
|
|
|
|
|
|
|
|
if (locales == null) {
|
|
|
|
|
|
|
|
emit(PendingSet(emptySet(), isLoading = false, isError = true))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
emit(PendingSet(locales, isLoading = false, isError = false))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -239,13 +257,14 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
|
|
|
|
|
|
|
|
@WorkerThread
|
|
|
|
@WorkerThread
|
|
|
|
private fun buildFilterList(
|
|
|
|
private fun buildFilterList(
|
|
|
|
allTags: TagsWrapper,
|
|
|
|
allTags: PendingSet<MangaTag>,
|
|
|
|
|
|
|
|
allLocales: PendingSet<Locale>,
|
|
|
|
state: MangaListFilter.Advanced,
|
|
|
|
state: MangaListFilter.Advanced,
|
|
|
|
query: String,
|
|
|
|
query: String,
|
|
|
|
): List<ListModel> {
|
|
|
|
): List<ListModel> {
|
|
|
|
val sortOrders = repository.sortOrders.sortedByOrdinal()
|
|
|
|
val sortOrders = repository.sortOrders.sortedByOrdinal()
|
|
|
|
val states = repository.states
|
|
|
|
val states = repository.states
|
|
|
|
val tags = mergeTags(state.tags, allTags.tags).toList()
|
|
|
|
val tags = mergeTags(state.tags, allTags.items).toList()
|
|
|
|
val list = ArrayList<ListModel>(tags.size + states.size + sortOrders.size + 4)
|
|
|
|
val list = ArrayList<ListModel>(tags.size + states.size + sortOrders.size + 4)
|
|
|
|
val isMultiTag = repository.isMultipleTagsSupported
|
|
|
|
val isMultiTag = repository.isMultipleTagsSupported
|
|
|
|
if (query.isEmpty()) {
|
|
|
|
if (query.isEmpty()) {
|
|
|
|
@ -267,6 +286,19 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
FilterItem.State(it, isChecked = it in state.states)
|
|
|
|
FilterItem.State(it, isChecked = it in state.states)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (allLocales.items.isNotEmpty()) {
|
|
|
|
|
|
|
|
list.add(
|
|
|
|
|
|
|
|
ListHeader(
|
|
|
|
|
|
|
|
textRes = R.string.language,
|
|
|
|
|
|
|
|
buttonTextRes = if (state.locale == null) 0 else R.string.reset,
|
|
|
|
|
|
|
|
payload = R.string.language,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
list.add(FilterItem.Language(null, isChecked = state.locale == null))
|
|
|
|
|
|
|
|
allLocales.items.mapTo(list) {
|
|
|
|
|
|
|
|
FilterItem.Language(it, isChecked = state.locale == it)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (allTags.isLoading || allTags.isError || tags.isNotEmpty()) {
|
|
|
|
if (allTags.isLoading || allTags.isError || tags.isNotEmpty()) {
|
|
|
|
list.add(
|
|
|
|
list.add(
|
|
|
|
ListHeader(
|
|
|
|
ListHeader(
|
|
|
|
@ -309,6 +341,16 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
return result
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private suspend fun tryLoadLocales(): Set<Locale>? {
|
|
|
|
|
|
|
|
val shouldRetryOnError = availableLocalesDeferred.isCompleted
|
|
|
|
|
|
|
|
val result = availableLocalesDeferred.await()
|
|
|
|
|
|
|
|
if (result == null && shouldRetryOnError) {
|
|
|
|
|
|
|
|
availableLocalesDeferred = loadLocalesAsync()
|
|
|
|
|
|
|
|
return availableLocalesDeferred.await()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun loadTagsAsync() = coroutineScope.async(Dispatchers.Default, CoroutineStart.LAZY) {
|
|
|
|
private fun loadTagsAsync() = coroutineScope.async(Dispatchers.Default, CoroutineStart.LAZY) {
|
|
|
|
runCatchingCancellable {
|
|
|
|
runCatchingCancellable {
|
|
|
|
repository.getTags()
|
|
|
|
repository.getTags()
|
|
|
|
@ -317,6 +359,14 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
}.getOrNull()
|
|
|
|
}.getOrNull()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun loadLocalesAsync() = coroutineScope.async(Dispatchers.Default, CoroutineStart.LAZY) {
|
|
|
|
|
|
|
|
runCatchingCancellable {
|
|
|
|
|
|
|
|
repository.getLocales()
|
|
|
|
|
|
|
|
}.onFailure { error ->
|
|
|
|
|
|
|
|
error.printStackTraceDebug()
|
|
|
|
|
|
|
|
}.getOrNull()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun mergeTags(primary: Set<MangaTag>, secondary: Set<MangaTag>): Set<MangaTag> {
|
|
|
|
private fun mergeTags(primary: Set<MangaTag>, secondary: Set<MangaTag>): Set<MangaTag> {
|
|
|
|
val result = TreeSet(TagTitleComparator(repository.source.locale))
|
|
|
|
val result = TreeSet(TagTitleComparator(repository.source.locale))
|
|
|
|
result.addAll(secondary)
|
|
|
|
result.addAll(secondary)
|
|
|
|
@ -324,8 +374,8 @@ class FilterCoordinator @Inject constructor(
|
|
|
|
return result
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private data class TagsWrapper(
|
|
|
|
private data class PendingSet<T>(
|
|
|
|
val tags: Set<MangaTag>,
|
|
|
|
val items: Set<T>,
|
|
|
|
val isLoading: Boolean,
|
|
|
|
val isLoading: Boolean,
|
|
|
|
val isError: Boolean,
|
|
|
|
val isError: Boolean,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|