Fix isLoading LiveData

This commit is contained in:
Koitharu
2022-05-12 13:44:05 +03:00
parent d9044b2d03
commit 317252e1dd
6 changed files with 49 additions and 25 deletions

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.base.ui
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlin.coroutines.CoroutineContext
@@ -11,8 +12,14 @@ import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
abstract class BaseViewModel : ViewModel() {
val onError = SingleLiveEvent<Throwable>()
val isLoading = CountedBooleanLiveData()
protected val loadingCounter = CountedBooleanLiveData()
protected val errorEvent = SingleLiveEvent<Throwable>()
val onError: LiveData<Throwable>
get() = errorEvent
val isLoading: LiveData<Boolean>
get() = loadingCounter
protected fun launchJob(
context: CoroutineContext = EmptyCoroutineContext,
@@ -25,18 +32,18 @@ abstract class BaseViewModel : ViewModel() {
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job = viewModelScope.launch(context + createErrorHandler(), start) {
isLoading.postValue(true)
loadingCounter.increment()
try {
block()
} finally {
isLoading.postValue(false)
loadingCounter.decrement()
}
}
private fun createErrorHandler() = CoroutineExceptionHandler { _, throwable ->
throwable.printStackTraceDebug()
if (throwable !is CancellationException) {
onError.postCall(throwable)
errorEvent.postCall(throwable)
}
}
}

View File

@@ -1,20 +1,31 @@
package org.koitharu.kotatsu.base.ui.util
import androidx.lifecycle.MutableLiveData
import androidx.annotation.AnyThread
import androidx.lifecycle.LiveData
import java.util.concurrent.atomic.AtomicInteger
class CountedBooleanLiveData : MutableLiveData<Boolean>(false) {
class CountedBooleanLiveData : LiveData<Boolean>(false) {
private var counter = 0
private val counter = AtomicInteger(0)
override fun setValue(value: Boolean) {
if (value) {
counter++
} else {
counter--
@AnyThread
fun increment() {
if (counter.getAndIncrement() == 0) {
postValue(true)
}
val newValue = counter > 0
if (newValue != this.value) {
super.setValue(newValue)
}
@AnyThread
fun decrement() {
if (counter.decrementAndGet() == 0) {
postValue(false)
}
}
@AnyThread
fun reset() {
if (counter.getAndSet(0) != 0) {
postValue(false)
}
}
}

View File

@@ -2,10 +2,13 @@ package org.koitharu.kotatsu.history.ui
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import java.util.*
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.ReversibleHandle
import org.koitharu.kotatsu.base.domain.plus
@@ -23,8 +26,6 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.daysDiff
import org.koitharu.kotatsu.utils.ext.onFirst
import java.util.*
import java.util.concurrent.TimeUnit
class HistoryListViewModel(
private val repository: HistoryRepository,
@@ -55,8 +56,10 @@ class HistoryListViewModel(
)
else -> mapList(list, grouped, mode)
}
}.onStart {
loadingCounter.increment()
}.onFirst {
isLoading.postValue(false)
loadingCounter.decrement()
}.catch {
it.toErrorState(canRetry = false)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))

View File

@@ -136,7 +136,7 @@ class RemoteListViewModel(
e.printStackTraceDebug()
listError.value = e
if (!mangaList.value.isNullOrEmpty()) {
onError.postCall(e)
errorEvent.postCall(e)
}
}
}

View File

@@ -67,19 +67,19 @@ class GlobalSearchViewModel(
searchJob = repository.globalSearch(query)
.catch { e ->
listError.value = e
isLoading.postValue(false)
loadingCounter.reset()
}.onStart {
mangaList.value = null
listError.value = null
isLoading.postValue(true)
loadingCounter.increment()
hasNextPage.value = true
}.onEmpty {
mangaList.value = emptyList()
}.onCompletion {
isLoading.postValue(false)
loadingCounter.reset()
hasNextPage.value = false
}.onFirst {
isLoading.postValue(false)
loadingCounter.reset()
}.onEach {
mangaList.value = mangaList.value?.plus(it) ?: listOf(it)
}.launchIn(viewModelScope + Dispatchers.Default)

View File

@@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onStart
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.list.ui.MangaListViewModel
@@ -37,8 +38,10 @@ class SuggestionsViewModel(
list.toUi(this, mode)
}
}
}.onStart {
loadingCounter.increment()
}.onFirst {
isLoading.postValue(false)
loadingCounter.decrement()
}.catch {
it.toErrorState(canRetry = false)
}.asLiveDataDistinct(