From 4607e5ba0fcd71775af41c35e82d375236d01ba6 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 13 Jul 2022 15:58:20 +0300 Subject: [PATCH] Refactor LiveData extensions --- .../kotatsu/details/ui/DetailsViewModel.kt | 4 +-- .../select/MangaCategoriesViewModel.kt | 2 +- .../koitharu/kotatsu/main/ui/MainViewModel.kt | 11 +----- .../kotatsu/reader/ui/ReaderActivity.kt | 8 +++-- .../kotatsu/reader/ui/ReaderViewModel.kt | 8 ++--- .../settings/onboard/OnboardDialogFragment.kt | 5 ++- .../settings/protect/ProtectSetupViewModel.kt | 2 +- .../koitharu/kotatsu/utils/ext/LiveDataExt.kt | 36 +------------------ .../widget/shelf/ShelfConfigViewModel.kt | 6 ++-- 9 files changed, 21 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index d77ef9aba..6c46cc25e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -106,14 +106,14 @@ class DetailsViewModel( val branches: LiveData> = 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 = combine( delegate.manga, diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt index b9f906549..0984c47d8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt @@ -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) { diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt index c3a681343..139e9939f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt @@ -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 { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 98ca6c988..b83d1d959 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -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 { diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 0384e44aa..0f18ea1a8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -64,7 +64,7 @@ class ReaderViewModel( val readerMode = MutableLiveData() val onPageSaved = SingleLiveEvent() val onShowToast = SingleLiveEvent() - val uiState = combine( + val uiState: LiveData = 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() @@ -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() diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt index 4f695b154..932306fe3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt @@ -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() } } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt index c9013d23d..0018a61a1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt @@ -17,7 +17,7 @@ class ProtectSetupViewModel( val isSecondStep = firstPassword.map { it != null - }.asLiveDataDistinct(viewModelScope.coroutineContext) + }.asLiveDataDistinct(viewModelScope.coroutineContext, false) val onPasswordSet = SingleLiveEvent() val onPasswordMismatch = SingleLiveEvent() val onClearText = SingleLiveEvent() diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt index c4172000f..769aec051 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt @@ -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 LiveData.observeNotNull(owner: LifecycleOwner, observer: Observer) { - this.observe(owner) { - if (it != null) { - observer.onChanged(it) - } - } -} - fun LiveData.requireValue(): T = checkNotNull(value) { "LiveData value is null" } @@ -30,17 +21,6 @@ fun LiveData.observeWithPrevious(owner: LifecycleOwner, observer: Buffere } } -@Deprecated("Use variant with default value") -fun Flow.asLiveDataDistinct( - context: CoroutineContext = EmptyCoroutineContext -): LiveData = liveData(context) { - collect { - if (it != latestValue) { - emit(it) - } - } -} - fun StateFlow.asLiveDataDistinct( context: CoroutineContext = EmptyCoroutineContext ): LiveData = asLiveDataDistinct(context, value) @@ -48,7 +28,7 @@ fun StateFlow.asLiveDataDistinct( fun Flow.asLiveDataDistinct( context: CoroutineContext = EmptyCoroutineContext, defaultValue: T -): LiveData = liveData(context, 0L) { +): LiveData = liveData(context) { if (latestValue == null) { emit(defaultValue) } @@ -57,18 +37,4 @@ fun Flow.asLiveDataDistinct( emit(it) } } -} - -fun Flow.asLiveDataDistinct( - context: CoroutineContext = EmptyCoroutineContext, - defaultValue: suspend () -> T -): LiveData = liveData(context) { - if (latestValue == null) { - emit(defaultValue()) - } - collect { - if (it != latestValue) { - emit(it) - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt index a9d5c09f6..6804f8967 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt @@ -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> = 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 } \ No newline at end of file