Fix search
parent
cef5d91eec
commit
a215d9ebfc
@ -1,29 +1,64 @@
|
|||||||
package org.koitharu.kotatsu.search.ui
|
package org.koitharu.kotatsu.search.ui
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.drop
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.IndeterminateProgress
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toGridModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toListModel
|
||||||
|
|
||||||
class SearchViewModel(
|
class SearchViewModel(
|
||||||
private val repository: MangaRepository,
|
private val repository: MangaRepository,
|
||||||
|
private val query: String,
|
||||||
settings: AppSettings
|
settings: AppSettings
|
||||||
) : MangaListViewModel(settings) {
|
) : MangaListViewModel(settings) {
|
||||||
|
|
||||||
override val content = MutableLiveData<List<Any>>()
|
private val mangaList = MutableStateFlow<List<Manga>>(emptyList())
|
||||||
|
private val hasNextPage = MutableStateFlow(false)
|
||||||
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
fun loadList(query: String, append: Boolean) {
|
override val content = combine(mangaList.drop(1), createListModeFlow()) { list, mode ->
|
||||||
launchLoadingJob {
|
when (mode) {
|
||||||
val list = withContext(Dispatchers.Default) {
|
ListMode.LIST -> list.map { it.toListModel() }
|
||||||
repository.getList(TODO(), query = query)
|
ListMode.DETAILED_LIST -> list.map { it.toListDetailedModel() }
|
||||||
}
|
ListMode.GRID -> list.map { it.toGridModel() }
|
||||||
|
}
|
||||||
|
}.onEach {
|
||||||
|
isEmptyState.postValue(it.isEmpty())
|
||||||
|
}.combine(hasNextPage) { list, isHasNextPage ->
|
||||||
|
if (isHasNextPage && list.isNotEmpty()) list + IndeterminateProgress else list
|
||||||
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadList(append = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadList(append: Boolean) {
|
||||||
|
if (loadingJob?.isActive == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadingJob = launchLoadingJob(Dispatchers.Default) {
|
||||||
|
val list = repository.getList(
|
||||||
|
offset = if (append) mangaList.value.size else 0,
|
||||||
|
query = query
|
||||||
|
)
|
||||||
if (!append) {
|
if (!append) {
|
||||||
content.value = list
|
mangaList.value = list
|
||||||
} else {
|
} else if (list.isNotEmpty()) {
|
||||||
content.value = content.value.orEmpty() + list
|
mangaList.value += list
|
||||||
}
|
}
|
||||||
|
hasNextPage.value = list.isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,43 +1,70 @@
|
|||||||
package org.koitharu.kotatsu.search.ui.global
|
package org.koitharu.kotatsu.search.ui.global
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.IndeterminateProgress
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toGridModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toListModel
|
||||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||||
import org.koitharu.kotatsu.utils.ext.onFirst
|
import org.koitharu.kotatsu.utils.ext.onFirst
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class GlobalSearchViewModel(
|
class GlobalSearchViewModel(
|
||||||
|
private val query: String,
|
||||||
private val repository: MangaSearchRepository,
|
private val repository: MangaSearchRepository,
|
||||||
settings: AppSettings
|
settings: AppSettings
|
||||||
) : MangaListViewModel(settings) {
|
) : MangaListViewModel(settings) {
|
||||||
|
|
||||||
override val content = MutableLiveData<List<Any>>()
|
private val mangaList = MutableStateFlow<List<Manga>>(emptyList())
|
||||||
|
private val hasNextPage = MutableStateFlow(false)
|
||||||
private var searchJob: Job? = null
|
private var searchJob: Job? = null
|
||||||
|
|
||||||
fun startSearch(query: String) {
|
override val content = combine(mangaList.drop(1), createListModeFlow()) { list, mode ->
|
||||||
isLoading.value = true
|
when (mode) {
|
||||||
|
ListMode.LIST -> list.map { it.toListModel() }
|
||||||
|
ListMode.DETAILED_LIST -> list.map { it.toListDetailedModel() }
|
||||||
|
ListMode.GRID -> list.map { it.toGridModel() }
|
||||||
|
}
|
||||||
|
}.combine(hasNextPage) { list, isHasNextPage ->
|
||||||
|
if (isHasNextPage && list.isNotEmpty()) list + IndeterminateProgress else list
|
||||||
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
|
init {
|
||||||
|
onRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRefresh() {
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
searchJob = repository.globalSearch(query)
|
searchJob = repository.globalSearch(query)
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.catch { e ->
|
.catch { e ->
|
||||||
if (e is IOException) {
|
onError.postCall(e)
|
||||||
onError.call(e)
|
isLoading.postValue(false)
|
||||||
}
|
hasNextPage.value = false
|
||||||
}.filterNot { x -> x.isEmpty() }
|
}.filterNot { x -> x.isEmpty() }
|
||||||
.onEmpty {
|
.onStart {
|
||||||
content.value = emptyList()
|
isLoading.postValue(true)
|
||||||
isLoading.value = false
|
}.onEmpty {
|
||||||
|
mangaList.value = emptyList()
|
||||||
|
isEmptyState.postValue(true)
|
||||||
|
isLoading.postValue(false)
|
||||||
}.onCompletion {
|
}.onCompletion {
|
||||||
// TODO
|
isLoading.postValue(false)
|
||||||
|
hasNextPage.value = false
|
||||||
}.onFirst {
|
}.onFirst {
|
||||||
|
isEmptyState.postValue(false)
|
||||||
|
hasNextPage.value = true
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}.onEach {
|
}.onEach {
|
||||||
content.value = content.value.orEmpty() + it
|
mangaList.value += it
|
||||||
}.launchIn(viewModelScope)
|
}.launchIn(viewModelScope + Dispatchers.Default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue