Replace LiveData with StateFlow

This commit is contained in:
Koitharu
2023-05-27 12:25:49 +03:00
parent 47f346b42c
commit 5a0c54e00f
147 changed files with 1047 additions and 1039 deletions

View File

@@ -19,6 +19,8 @@ import org.koitharu.kotatsu.core.ui.list.decor.TypedSpacingItemDecoration
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.databinding.ActivityScrobblerConfigBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
@@ -64,7 +66,7 @@ class ScrobblerConfigActivity : BaseActivity<ActivityScrobblerConfigBinding>(),
viewModel.content.observe(this, listAdapter::setItems)
viewModel.user.observe(this, this::onUserChanged)
viewModel.isLoading.observe(this, this::onLoadingStateChanged)
viewModel.onError.observe(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
viewModel.onLoggedOut.observe(this) {
finishAfterTransition()
}

View File

@@ -1,23 +1,24 @@
package org.koitharu.kotatsu.scrobbling.common.ui.config
import android.net.Uri
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.SingleLiveEvent
import org.koitharu.kotatsu.core.util.asFlowLiveData
import org.koitharu.kotatsu.core.util.ext.emitValue
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.onFirst
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.list.ui.model.EmptyState
@@ -40,34 +41,34 @@ class ScrobblerConfigViewModel @Inject constructor(
val titleResId = scrobbler.scrobblerService.titleResId
val user = MutableLiveData<ScrobblerUser?>(null)
val onLoggedOut = SingleLiveEvent<Unit>()
val user = MutableStateFlow<ScrobblerUser?>(null)
val onLoggedOut = MutableEventFlow<Unit>()
val content = scrobbler.observeAllScrobblingInfo()
.onStart { loadingCounter.increment() }
.onFirst { loadingCounter.decrement() }
.catch { errorEvent.postCall(it) }
.catch { errorEvent.call(it) }
.map { buildContentList(it) }
.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
init {
scrobbler.user
.onEach { user.emitValue(it) }
.onEach { user.value = it }
.launchIn(viewModelScope + Dispatchers.Default)
}
fun onAuthCodeReceived(authCode: String) {
launchLoadingJob(Dispatchers.Default) {
val newUser = scrobbler.authorize(authCode)
user.emitValue(newUser)
user.value = newUser
}
}
fun logout() {
launchLoadingJob(Dispatchers.Default) {
scrobbler.logout()
user.emitValue(null)
onLoggedOut.emitCall(Unit)
user.value = null
onLoggedOut.call(Unit)
}
}

View File

@@ -22,6 +22,8 @@ import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener
import org.koitharu.kotatsu.core.ui.util.CollapseActionViewCallback
import org.koitharu.kotatsu.core.util.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.SheetScrobblingSelectorBinding
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
@@ -72,8 +74,8 @@ class ScrobblingSelectorBottomSheet :
decoration.checkedItemId = it
binding.recyclerView.invalidateItemDecorations()
}
viewModel.onError.observe(viewLifecycleOwner, ::onError)
viewModel.onClose.observe(viewLifecycleOwner) {
viewModel.onError.observeEvent(viewLifecycleOwner, ::onError)
viewModel.onClose.observeEvent(viewLifecycleOwner) {
dismiss()
}
viewModel.selectedScrobblerIndex.observe(viewLifecycleOwner) { index ->

View File

@@ -1,7 +1,5 @@
package org.koitharu.kotatsu.scrobbling.common.ui.selector
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView.NO_ID
@@ -9,14 +7,17 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.SingleLiveEvent
import org.koitharu.kotatsu.core.util.asFlowLiveData
import org.koitharu.kotatsu.core.util.ext.emitValue
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.core.util.ext.requireValue
import org.koitharu.kotatsu.list.ui.model.ListModel
@@ -39,7 +40,7 @@ class ScrobblingSelectorViewModel @Inject constructor(
val availableScrobblers = scrobblers.filter { it.isAvailable }
val selectedScrobblerIndex = MutableLiveData(0)
val selectedScrobblerIndex = MutableStateFlow(0)
private val scrobblerMangaList = MutableStateFlow<List<ScrobblerManga>>(emptyList())
private val hasNextPage = MutableStateFlow(true)
@@ -51,7 +52,7 @@ class ScrobblingSelectorViewModel @Inject constructor(
private val currentScrobbler: Scrobbler
get() = availableScrobblers[selectedScrobblerIndex.requireValue()]
val content: LiveData<List<ListModel>> = combine(
val content: StateFlow<List<ListModel>> = combine(
scrobblerMangaList,
listError,
hasNextPage,
@@ -71,11 +72,11 @@ class ScrobblingSelectorViewModel @Inject constructor(
},
)
}
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
val selectedItemId = MutableLiveData(NO_ID)
val searchQuery = MutableLiveData(manga.title)
val onClose = SingleLiveEvent<Unit>()
val selectedItemId = MutableStateFlow(NO_ID)
val searchQuery = MutableStateFlow(manga.title)
val onClose = MutableEventFlow<Unit>()
val isEmpty: Boolean
get() = scrobblerMangaList.value.isEmpty()
@@ -130,13 +131,13 @@ class ScrobblingSelectorViewModel @Inject constructor(
if (doneJob?.isActive == true) {
return
}
val targetId = selectedItemId.value ?: NO_ID
val targetId = selectedItemId.value
if (targetId == NO_ID) {
onClose.call(Unit)
}
doneJob = launchJob(Dispatchers.Default) {
currentScrobbler.linkManga(manga.id, targetId)
onClose.emitCall(Unit)
onClose.call(Unit)
}
}
@@ -155,7 +156,7 @@ class ScrobblingSelectorViewModel @Inject constructor(
try {
val info = currentScrobbler.getScrobblingInfoOrNull(manga.id)
if (info != null) {
selectedItemId.emitValue(info.targetId)
selectedItemId.value = info.targetId
}
} finally {
loadList(append = false)