Refactor LiveData extensions

This commit is contained in:
Koitharu
2022-07-13 15:58:20 +03:00
parent 29c82177a9
commit 4607e5ba0f
9 changed files with 21 additions and 61 deletions

View File

@@ -106,14 +106,14 @@ class DetailsViewModel(
val branches: LiveData<List<String?>> = delegate.manga.map {
val chapters = it?.chapters ?: return@map emptyList()
chapters.mapToSet { x -> x.branch }.sortedWith(BranchComparator())
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
val selectedBranchIndex = combine(
branches.asFlow(),
delegate.selectedBranch
) { branches, selected ->
branches.indexOf(selected)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, -1)
val isChaptersEmpty: LiveData<Boolean> = combine(
delegate.manga,

View File

@@ -26,7 +26,7 @@ class MangaCategoriesViewModel(
isChecked = it.id in checked
)
}
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
fun setChecked(categoryId: Long, isChecked: Boolean) {
launchJob(Dispatchers.Default) {

View File

@@ -2,9 +2,6 @@ package org.koitharu.kotatsu.main.ui
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.core.prefs.AppSection
@@ -41,13 +38,7 @@ class MainViewModel(
val isResumeEnabled = historyRepository
.observeHasItems()
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
val remoteSources = settings.observe()
.filter { it == AppSettings.KEY_SOURCES_ORDER || it == AppSettings.KEY_SOURCES_HIDDEN }
.onStart { emit("") }
.map { settings.getMangaSources(includeHidden = false) }
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
fun openLastReader() {
launchLoadingJob {

View File

@@ -347,8 +347,12 @@ class ReaderActivity :
menuItem.setIcon(if (isAdded) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark)
}
private fun onUiStateChanged(uiState: ReaderUiState, previous: ReaderUiState?) {
title = uiState.chapterName ?: uiState.mangaName ?: getString(R.string.loading_)
private fun onUiStateChanged(uiState: ReaderUiState?, previous: ReaderUiState?) {
title = uiState?.chapterName ?: uiState?.mangaName ?: getString(R.string.loading_)
if (uiState == null) {
supportActionBar?.subtitle = null
return
}
supportActionBar?.subtitle = if (uiState.chapterNumber in 1..uiState.chaptersTotal) {
getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal)
} else {

View File

@@ -64,7 +64,7 @@ class ReaderViewModel(
val readerMode = MutableLiveData<ReaderMode>()
val onPageSaved = SingleLiveEvent<Uri?>()
val onShowToast = SingleLiveEvent<Int>()
val uiState = combine(
val uiState: LiveData<ReaderUiState?> = combine(
mangaData,
currentState,
) { manga, state ->
@@ -75,7 +75,7 @@ class ReaderViewModel(
chapterNumber = chapter?.number ?: 0,
chaptersTotal = chapters.size()
)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, null)
val content = MutableLiveData(ReaderContent(emptyList(), null))
val manga: Manga?
@@ -93,7 +93,7 @@ class ReaderViewModel(
) { manga, policy ->
policy == ScreenshotsPolicy.BLOCK_ALL ||
(policy == ScreenshotsPolicy.BLOCK_NSFW && manga != null && manga.isNsfw)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
val onZoomChanged = SingleLiveEvent<Unit>()
@@ -105,7 +105,7 @@ class ReaderViewModel(
bookmarksRepository.observeBookmark(manga, state.chapterId, state.page)
.map { it != null }
}
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
init {
loadImpl()

View File

@@ -14,7 +14,6 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocalesAdapter
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
import org.koitharu.kotatsu.utils.ext.observeNotNull
import org.koitharu.kotatsu.utils.ext.showAllowStateLoss
import org.koitharu.kotatsu.utils.ext.withArgs
@@ -56,8 +55,8 @@ class OnboardDialogFragment :
val adapter = SourceLocalesAdapter(this)
binding.recyclerView.adapter = adapter
binding.textViewTitle.setText(R.string.onboard_text)
viewModel.list.observeNotNull(viewLifecycleOwner) {
adapter.items = it
viewModel.list.observe(viewLifecycleOwner) {
adapter.items = it.orEmpty()
}
}

View File

@@ -17,7 +17,7 @@ class ProtectSetupViewModel(
val isSecondStep = firstPassword.map {
it != null
}.asLiveDataDistinct(viewModelScope.coroutineContext)
}.asLiveDataDistinct(viewModelScope.coroutineContext, false)
val onPasswordSet = SingleLiveEvent<Unit>()
val onPasswordMismatch = SingleLiveEvent<Unit>()
val onClearText = SingleLiveEvent<Unit>()

View File

@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.utils.ext
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.liveData
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -10,14 +9,6 @@ import org.koitharu.kotatsu.utils.BufferedObserver
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
fun <T> LiveData<T?>.observeNotNull(owner: LifecycleOwner, observer: Observer<T>) {
this.observe(owner) {
if (it != null) {
observer.onChanged(it)
}
}
}
fun <T> LiveData<T>.requireValue(): T = checkNotNull(value) {
"LiveData value is null"
}
@@ -30,17 +21,6 @@ fun <T> LiveData<T>.observeWithPrevious(owner: LifecycleOwner, observer: Buffere
}
}
@Deprecated("Use variant with default value")
fun <T> Flow<T>.asLiveDataDistinct(
context: CoroutineContext = EmptyCoroutineContext
): LiveData<T> = liveData(context) {
collect {
if (it != latestValue) {
emit(it)
}
}
}
fun <T> StateFlow<T>.asLiveDataDistinct(
context: CoroutineContext = EmptyCoroutineContext
): LiveData<T> = asLiveDataDistinct(context, value)
@@ -48,7 +28,7 @@ fun <T> StateFlow<T>.asLiveDataDistinct(
fun <T> Flow<T>.asLiveDataDistinct(
context: CoroutineContext = EmptyCoroutineContext,
defaultValue: T
): LiveData<T> = liveData(context, 0L) {
): LiveData<T> = liveData(context) {
if (latestValue == null) {
emit(defaultValue)
}
@@ -57,18 +37,4 @@ fun <T> Flow<T>.asLiveDataDistinct(
emit(it)
}
}
}
fun <T> Flow<T>.asLiveDataDistinct(
context: CoroutineContext = EmptyCoroutineContext,
defaultValue: suspend () -> T
): LiveData<T> = liveData(context) {
if (latestValue == null) {
emit(defaultValue())
}
collect {
if (it != latestValue) {
emit(it)
}
}
}

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.widget.shelf
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@@ -8,7 +9,6 @@ import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
import java.util.*
class ShelfConfigViewModel(
favouritesRepository: FavouritesRepository
@@ -16,7 +16,7 @@ class ShelfConfigViewModel(
private val selectedCategoryId = MutableStateFlow(0L)
val content = combine(
val content: LiveData<List<CategoryItem>> = combine(
favouritesRepository.observeCategories(),
selectedCategoryId
) { categories, selectedId ->
@@ -26,7 +26,7 @@ class ShelfConfigViewModel(
CategoryItem(it.id, it.title, selectedId == it.id)
}
list
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
var checkedId: Long by selectedCategoryId::value
}