Refactor LiveData extensions
This commit is contained in:
@@ -106,14 +106,14 @@ class DetailsViewModel(
|
|||||||
val branches: LiveData<List<String?>> = delegate.manga.map {
|
val branches: LiveData<List<String?>> = delegate.manga.map {
|
||||||
val chapters = it?.chapters ?: return@map emptyList()
|
val chapters = it?.chapters ?: return@map emptyList()
|
||||||
chapters.mapToSet { x -> x.branch }.sortedWith(BranchComparator())
|
chapters.mapToSet { x -> x.branch }.sortedWith(BranchComparator())
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
|
||||||
|
|
||||||
val selectedBranchIndex = combine(
|
val selectedBranchIndex = combine(
|
||||||
branches.asFlow(),
|
branches.asFlow(),
|
||||||
delegate.selectedBranch
|
delegate.selectedBranch
|
||||||
) { branches, selected ->
|
) { branches, selected ->
|
||||||
branches.indexOf(selected)
|
branches.indexOf(selected)
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, -1)
|
||||||
|
|
||||||
val isChaptersEmpty: LiveData<Boolean> = combine(
|
val isChaptersEmpty: LiveData<Boolean> = combine(
|
||||||
delegate.manga,
|
delegate.manga,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class MangaCategoriesViewModel(
|
|||||||
isChecked = it.id in checked
|
isChecked = it.id in checked
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
|
||||||
|
|
||||||
fun setChecked(categoryId: Long, isChecked: Boolean) {
|
fun setChecked(categoryId: Long, isChecked: Boolean) {
|
||||||
launchJob(Dispatchers.Default) {
|
launchJob(Dispatchers.Default) {
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ package org.koitharu.kotatsu.main.ui
|
|||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
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.base.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSection
|
import org.koitharu.kotatsu.core.prefs.AppSection
|
||||||
@@ -41,13 +38,7 @@ class MainViewModel(
|
|||||||
|
|
||||||
val isResumeEnabled = historyRepository
|
val isResumeEnabled = historyRepository
|
||||||
.observeHasItems()
|
.observeHasItems()
|
||||||
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
fun openLastReader() {
|
fun openLastReader() {
|
||||||
launchLoadingJob {
|
launchLoadingJob {
|
||||||
|
|||||||
@@ -347,8 +347,12 @@ class ReaderActivity :
|
|||||||
menuItem.setIcon(if (isAdded) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark)
|
menuItem.setIcon(if (isAdded) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUiStateChanged(uiState: ReaderUiState, previous: ReaderUiState?) {
|
private fun onUiStateChanged(uiState: ReaderUiState?, previous: ReaderUiState?) {
|
||||||
title = uiState.chapterName ?: uiState.mangaName ?: getString(R.string.loading_)
|
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) {
|
supportActionBar?.subtitle = if (uiState.chapterNumber in 1..uiState.chaptersTotal) {
|
||||||
getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal)
|
getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class ReaderViewModel(
|
|||||||
val readerMode = MutableLiveData<ReaderMode>()
|
val readerMode = MutableLiveData<ReaderMode>()
|
||||||
val onPageSaved = SingleLiveEvent<Uri?>()
|
val onPageSaved = SingleLiveEvent<Uri?>()
|
||||||
val onShowToast = SingleLiveEvent<Int>()
|
val onShowToast = SingleLiveEvent<Int>()
|
||||||
val uiState = combine(
|
val uiState: LiveData<ReaderUiState?> = combine(
|
||||||
mangaData,
|
mangaData,
|
||||||
currentState,
|
currentState,
|
||||||
) { manga, state ->
|
) { manga, state ->
|
||||||
@@ -75,7 +75,7 @@ class ReaderViewModel(
|
|||||||
chapterNumber = chapter?.number ?: 0,
|
chapterNumber = chapter?.number ?: 0,
|
||||||
chaptersTotal = chapters.size()
|
chaptersTotal = chapters.size()
|
||||||
)
|
)
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, null)
|
||||||
|
|
||||||
val content = MutableLiveData(ReaderContent(emptyList(), null))
|
val content = MutableLiveData(ReaderContent(emptyList(), null))
|
||||||
val manga: Manga?
|
val manga: Manga?
|
||||||
@@ -93,7 +93,7 @@ class ReaderViewModel(
|
|||||||
) { manga, policy ->
|
) { manga, policy ->
|
||||||
policy == ScreenshotsPolicy.BLOCK_ALL ||
|
policy == ScreenshotsPolicy.BLOCK_ALL ||
|
||||||
(policy == ScreenshotsPolicy.BLOCK_NSFW && manga != null && manga.isNsfw)
|
(policy == ScreenshotsPolicy.BLOCK_NSFW && manga != null && manga.isNsfw)
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
|
||||||
|
|
||||||
val onZoomChanged = SingleLiveEvent<Unit>()
|
val onZoomChanged = SingleLiveEvent<Unit>()
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class ReaderViewModel(
|
|||||||
bookmarksRepository.observeBookmark(manga, state.chapterId, state.page)
|
bookmarksRepository.observeBookmark(manga, state.chapterId, state.page)
|
||||||
.map { it != null }
|
.map { it != null }
|
||||||
}
|
}
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadImpl()
|
loadImpl()
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
|||||||
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
|
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
|
||||||
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocalesAdapter
|
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocalesAdapter
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
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.showAllowStateLoss
|
||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
@@ -56,8 +55,8 @@ class OnboardDialogFragment :
|
|||||||
val adapter = SourceLocalesAdapter(this)
|
val adapter = SourceLocalesAdapter(this)
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
binding.textViewTitle.setText(R.string.onboard_text)
|
binding.textViewTitle.setText(R.string.onboard_text)
|
||||||
viewModel.list.observeNotNull(viewLifecycleOwner) {
|
viewModel.list.observe(viewLifecycleOwner) {
|
||||||
adapter.items = it
|
adapter.items = it.orEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class ProtectSetupViewModel(
|
|||||||
|
|
||||||
val isSecondStep = firstPassword.map {
|
val isSecondStep = firstPassword.map {
|
||||||
it != null
|
it != null
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext, false)
|
||||||
val onPasswordSet = SingleLiveEvent<Unit>()
|
val onPasswordSet = SingleLiveEvent<Unit>()
|
||||||
val onPasswordMismatch = SingleLiveEvent<Unit>()
|
val onPasswordMismatch = SingleLiveEvent<Unit>()
|
||||||
val onClearText = SingleLiveEvent<Unit>()
|
val onClearText = SingleLiveEvent<Unit>()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.utils.ext
|
|||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.liveData
|
import androidx.lifecycle.liveData
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -10,14 +9,6 @@ import org.koitharu.kotatsu.utils.BufferedObserver
|
|||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
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) {
|
fun <T> LiveData<T>.requireValue(): T = checkNotNull(value) {
|
||||||
"LiveData value is null"
|
"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(
|
fun <T> StateFlow<T>.asLiveDataDistinct(
|
||||||
context: CoroutineContext = EmptyCoroutineContext
|
context: CoroutineContext = EmptyCoroutineContext
|
||||||
): LiveData<T> = asLiveDataDistinct(context, value)
|
): LiveData<T> = asLiveDataDistinct(context, value)
|
||||||
@@ -48,7 +28,7 @@ fun <T> StateFlow<T>.asLiveDataDistinct(
|
|||||||
fun <T> Flow<T>.asLiveDataDistinct(
|
fun <T> Flow<T>.asLiveDataDistinct(
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
defaultValue: T
|
defaultValue: T
|
||||||
): LiveData<T> = liveData(context, 0L) {
|
): LiveData<T> = liveData(context) {
|
||||||
if (latestValue == null) {
|
if (latestValue == null) {
|
||||||
emit(defaultValue)
|
emit(defaultValue)
|
||||||
}
|
}
|
||||||
@@ -57,18 +37,4 @@ fun <T> Flow<T>.asLiveDataDistinct(
|
|||||||
emit(it)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.koitharu.kotatsu.widget.shelf
|
package org.koitharu.kotatsu.widget.shelf
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
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.favourites.domain.FavouritesRepository
|
||||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||||
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
|
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class ShelfConfigViewModel(
|
class ShelfConfigViewModel(
|
||||||
favouritesRepository: FavouritesRepository
|
favouritesRepository: FavouritesRepository
|
||||||
@@ -16,7 +16,7 @@ class ShelfConfigViewModel(
|
|||||||
|
|
||||||
private val selectedCategoryId = MutableStateFlow(0L)
|
private val selectedCategoryId = MutableStateFlow(0L)
|
||||||
|
|
||||||
val content = combine(
|
val content: LiveData<List<CategoryItem>> = combine(
|
||||||
favouritesRepository.observeCategories(),
|
favouritesRepository.observeCategories(),
|
||||||
selectedCategoryId
|
selectedCategoryId
|
||||||
) { categories, selectedId ->
|
) { categories, selectedId ->
|
||||||
@@ -26,7 +26,7 @@ class ShelfConfigViewModel(
|
|||||||
CategoryItem(it.id, it.title, selectedId == it.id)
|
CategoryItem(it.id, it.title, selectedId == it.id)
|
||||||
}
|
}
|
||||||
list
|
list
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
|
||||||
|
|
||||||
var checkedId: Long by selectedCategoryId::value
|
var checkedId: Long by selectedCategoryId::value
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user