|
|
|
@ -14,8 +14,10 @@ import kotlinx.coroutines.flow.channelFlow
|
|
|
|
import kotlinx.coroutines.flow.combine
|
|
|
|
import kotlinx.coroutines.flow.combine
|
|
|
|
import kotlinx.coroutines.flow.filterNotNull
|
|
|
|
import kotlinx.coroutines.flow.filterNotNull
|
|
|
|
import kotlinx.coroutines.flow.flatMapLatest
|
|
|
|
import kotlinx.coroutines.flow.flatMapLatest
|
|
|
|
|
|
|
|
import kotlinx.coroutines.flow.onEmpty
|
|
|
|
import kotlinx.coroutines.flow.runningFold
|
|
|
|
import kotlinx.coroutines.flow.runningFold
|
|
|
|
import kotlinx.coroutines.flow.stateIn
|
|
|
|
import kotlinx.coroutines.flow.stateIn
|
|
|
|
|
|
|
|
import kotlinx.coroutines.joinAll
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.plus
|
|
|
|
import kotlinx.coroutines.plus
|
|
|
|
import kotlinx.coroutines.sync.Semaphore
|
|
|
|
import kotlinx.coroutines.sync.Semaphore
|
|
|
|
@ -112,37 +114,39 @@ class MultiSearchViewModel @Inject constructor(
|
|
|
|
return@channelFlow
|
|
|
|
return@channelFlow
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val semaphore = Semaphore(MAX_PARALLELISM)
|
|
|
|
val semaphore = Semaphore(MAX_PARALLELISM)
|
|
|
|
for (source in sources) {
|
|
|
|
sources.mapNotNull { source ->
|
|
|
|
val repository = mangaRepositoryFactory.create(source)
|
|
|
|
val repository = mangaRepositoryFactory.create(source)
|
|
|
|
if (!repository.isSearchSupported) {
|
|
|
|
if (!repository.isSearchSupported) {
|
|
|
|
continue
|
|
|
|
null
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
launch {
|
|
|
|
launch {
|
|
|
|
val item = runCatchingCancellable {
|
|
|
|
val item = runCatchingCancellable {
|
|
|
|
semaphore.withPermit {
|
|
|
|
semaphore.withPermit {
|
|
|
|
mangaListMapper.toListModelList(
|
|
|
|
mangaListMapper.toListModelList(
|
|
|
|
manga = repository.getList(offset = 0, filter = MangaListFilter.Search(q)),
|
|
|
|
manga = repository.getList(offset = 0, filter = MangaListFilter.Search(q)),
|
|
|
|
mode = ListMode.GRID,
|
|
|
|
mode = ListMode.GRID,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
}.fold(
|
|
|
|
|
|
|
|
onSuccess = { list ->
|
|
|
|
|
|
|
|
if (list.isEmpty()) {
|
|
|
|
|
|
|
|
null
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list, null)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}.fold(
|
|
|
|
onFailure = { error ->
|
|
|
|
onSuccess = { list ->
|
|
|
|
error.printStackTraceDebug()
|
|
|
|
if (list.isEmpty()) {
|
|
|
|
MultiSearchListModel(source, true, emptyList(), error)
|
|
|
|
null
|
|
|
|
},
|
|
|
|
} else {
|
|
|
|
)
|
|
|
|
MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list, null)
|
|
|
|
if (item != null) {
|
|
|
|
}
|
|
|
|
send(item)
|
|
|
|
},
|
|
|
|
|
|
|
|
onFailure = { error ->
|
|
|
|
|
|
|
|
error.printStackTraceDebug()
|
|
|
|
|
|
|
|
MultiSearchListModel(source, true, emptyList(), error)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if (item != null) {
|
|
|
|
|
|
|
|
send(item)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.joinAll()
|
|
|
|
}.runningFold<MultiSearchListModel, List<MultiSearchListModel>?>(null) { list, item -> list.orEmpty() + item }
|
|
|
|
}.runningFold<MultiSearchListModel, List<MultiSearchListModel>?>(null) { list, item -> list.orEmpty() + item }
|
|
|
|
.filterNotNull()
|
|
|
|
.filterNotNull()
|
|
|
|
|
|
|
|
.onEmpty { emit(emptyList()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|