Merge pull request #7724 from vector-im/feature/bma/launchWhenResumed
Observe ViewEvents only when resumed
This commit is contained in:
commit
93021a6028
|
@ -0,0 +1 @@
|
||||||
|
Observe ViewEvents only when resumed and ensure ViewEvents are not lost.
|
|
@ -41,6 +41,7 @@ import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
|
@ -91,6 +92,7 @@ import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.failure.GlobalError
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
|
@ -123,14 +125,20 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
||||||
protected val viewModelProvider
|
protected val viewModelProvider
|
||||||
get() = ViewModelProvider(this, viewModelFactory)
|
get() = ViewModelProvider(this, viewModelFactory)
|
||||||
|
|
||||||
fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(
|
||||||
viewEvents
|
observer: (T) -> Unit,
|
||||||
.stream()
|
) {
|
||||||
.onEach {
|
val tag = this@VectorBaseActivity::class.simpleName.toString()
|
||||||
hideWaitingView()
|
lifecycleScope.launch {
|
||||||
observer(it)
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
}
|
viewEvents
|
||||||
.launchIn(lifecycleScope)
|
.stream(tag)
|
||||||
|
.collect {
|
||||||
|
hideWaitingView()
|
||||||
|
observer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolbar: ToolbarConfig? = null
|
var toolbar: ToolbarConfig? = null
|
||||||
|
|
|
@ -26,8 +26,10 @@ import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.annotation.FloatRange
|
import androidx.annotation.FloatRange
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
@ -43,6 +45,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import io.github.hyuwah.draggableviewlib.Utils
|
import io.github.hyuwah.draggableviewlib.Utils
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -199,12 +202,18 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
|
||||||
* ViewEvents
|
* ViewEvents
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(
|
||||||
viewEvents
|
observer: (T) -> Unit,
|
||||||
.stream()
|
) {
|
||||||
.onEach {
|
val tag = this@VectorBaseBottomSheetDialogFragment::class.simpleName.toString()
|
||||||
observer(it)
|
lifecycleScope.launch {
|
||||||
}
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
viewEvents
|
||||||
|
.stream(tag)
|
||||||
|
.collect {
|
||||||
|
observer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,10 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import dagger.hilt.android.EntryPointAccessors
|
import dagger.hilt.android.EntryPointAccessors
|
||||||
|
@ -37,6 +39,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -145,11 +148,15 @@ abstract class VectorBaseDialogFragment<VB : ViewBinding> : DialogFragment(), Ma
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
||||||
viewEvents
|
val tag = this@VectorBaseDialogFragment::class.simpleName.toString()
|
||||||
.stream()
|
lifecycleScope.launch {
|
||||||
.onEach {
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
observer(it)
|
viewEvents
|
||||||
}
|
.stream(tag)
|
||||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
.collect {
|
||||||
|
observer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.bumptech.glide.util.Util.assertMainThread
|
import com.bumptech.glide.util.Util.assertMainThread
|
||||||
|
@ -53,6 +54,7 @@ import im.vector.app.features.navigation.Navigator
|
||||||
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
|
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -272,14 +274,20 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
||||||
* ViewEvents
|
* ViewEvents
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(
|
||||||
viewEvents
|
observer: (T) -> Unit,
|
||||||
.stream()
|
) {
|
||||||
.onEach {
|
val tag = this@VectorBaseFragment::class.simpleName.toString()
|
||||||
dismissLoadingDialog()
|
lifecycleScope.launch {
|
||||||
observer(it)
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
}
|
viewEvents
|
||||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
.stream(tag)
|
||||||
|
.collect {
|
||||||
|
dismissLoadingDialog()
|
||||||
|
observer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
|
|
|
@ -18,15 +18,16 @@ package im.vector.app.core.platform
|
||||||
|
|
||||||
import com.airbnb.mvrx.MavericksState
|
import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.MavericksViewModel
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
import im.vector.app.core.utils.DataSource
|
import im.vector.app.core.utils.EventQueue
|
||||||
import im.vector.app.core.utils.PublishDataSource
|
import im.vector.app.core.utils.SharedEvents
|
||||||
|
|
||||||
abstract class VectorViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(initialState: S) :
|
abstract class VectorViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(initialState: S) :
|
||||||
MavericksViewModel<S>(initialState) {
|
MavericksViewModel<S>(initialState) {
|
||||||
|
|
||||||
// Used to post transient events to the View
|
// Used to post transient events to the View
|
||||||
protected val _viewEvents = PublishDataSource<VE>()
|
protected val _viewEvents = EventQueue<VE>(capacity = 64)
|
||||||
val viewEvents: DataSource<VE> = _viewEvents
|
val viewEvents: SharedEvents<VE>
|
||||||
|
get() = _viewEvents
|
||||||
|
|
||||||
abstract fun handle(action: VA)
|
abstract fun handle(action: VA)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.transform
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
|
|
||||||
|
interface SharedEvents<out T> {
|
||||||
|
fun stream(consumerId: String): Flow<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventQueue<T>(capacity: Int) : SharedEvents<T> {
|
||||||
|
|
||||||
|
private val innerQueue = MutableSharedFlow<OneTimeEvent<T>>(replay = capacity)
|
||||||
|
|
||||||
|
fun post(event: T) {
|
||||||
|
innerQueue.tryEmit(OneTimeEvent(event))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stream(consumerId: String): Flow<T> = innerQueue.filterNotHandledBy(consumerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event designed to be delivered only once to a concrete entity,
|
||||||
|
* but it can also be delivered to multiple different entities.
|
||||||
|
*
|
||||||
|
* Keeps track of who has already handled its content.
|
||||||
|
*/
|
||||||
|
private class OneTimeEvent<out T>(private val content: T) {
|
||||||
|
|
||||||
|
private val handlers = CopyOnWriteArraySet<String>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param asker Used to identify, whether this "asker" has already handled this Event.
|
||||||
|
* @return Event content or null if it has been already handled by asker
|
||||||
|
*/
|
||||||
|
fun getIfNotHandled(asker: String): T? = if (handlers.add(asker)) content else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> Flow<OneTimeEvent<T>>.filterNotHandledBy(consumerId: String): Flow<T> = transform { event ->
|
||||||
|
event.getIfNotHandled(consumerId)?.let { emit(it) }
|
||||||
|
}
|
|
@ -55,8 +55,6 @@ import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
@ -142,9 +140,9 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
||||||
startAppViewModel.onEach {
|
startAppViewModel.onEach {
|
||||||
renderState(it)
|
renderState(it)
|
||||||
}
|
}
|
||||||
startAppViewModel.viewEvents.stream()
|
startAppViewModel.observeViewEvents {
|
||||||
.onEach(::handleViewEvents)
|
handleViewEvents(it)
|
||||||
.launchIn(lifecycleScope)
|
}
|
||||||
|
|
||||||
startAppViewModel.handle(StartAppAction.StartApp)
|
startAppViewModel.handle(StartAppAction.StartApp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ class SharedSecureStorageActivity :
|
||||||
|
|
||||||
views.toolbar.visibility = View.GONE
|
views.toolbar.visibility = View.GONE
|
||||||
|
|
||||||
viewModel.observeViewEvents { observeViewEvents(it) }
|
viewModel.observeViewEvents { onViewEvents(it) }
|
||||||
|
|
||||||
viewModel.onEach { renderState(it) }
|
viewModel.onEach { renderState(it) }
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ class SharedSecureStorageActivity :
|
||||||
showFragment(fragment)
|
showFragment(fragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeViewEvents(it: SharedSecureStorageViewEvent?) {
|
private fun onViewEvents(it: SharedSecureStorageViewEvent) {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SharedSecureStorageViewEvent.Dismiss -> {
|
is SharedSecureStorageViewEvent.Dismiss -> {
|
||||||
finish()
|
finish()
|
||||||
|
|
|
@ -29,7 +29,9 @@ import androidx.core.transition.addListener
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.transition.Transition
|
import androidx.transition.Transition
|
||||||
import com.airbnb.mvrx.viewModel
|
import com.airbnb.mvrx.viewModel
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
@ -50,8 +52,6 @@ import im.vector.lib.attachmentviewer.AttachmentViewerActivity
|
||||||
import im.vector.lib.core.utils.compat.getParcelableArrayListExtraCompat
|
import im.vector.lib.core.utils.compat.getParcelableArrayListExtraCompat
|
||||||
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
@ -239,10 +239,15 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), AttachmentInt
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeViewEvents() {
|
private fun observeViewEvents() {
|
||||||
viewModel.viewEvents
|
val tag = this::class.simpleName.toString()
|
||||||
.stream()
|
lifecycleScope.launch {
|
||||||
.onEach(::handleViewEvents)
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
.launchIn(lifecycleScope)
|
viewModel
|
||||||
|
.viewEvents
|
||||||
|
.stream(tag)
|
||||||
|
.collect(::handleViewEvents)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleViewEvents(event: VectorAttachmentViewerViewEvents) {
|
private fun handleViewEvents(event: VectorAttachmentViewerViewEvents) {
|
||||||
|
|
|
@ -20,7 +20,9 @@ import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
@ -35,6 +37,7 @@ import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -66,13 +69,19 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick
|
||||||
* ViewEvents
|
* ViewEvents
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(
|
||||||
viewEvents
|
observer: (T) -> Unit,
|
||||||
.stream()
|
) {
|
||||||
.onEach {
|
val tag = this@VectorSettingsBaseFragment::class.simpleName.toString()
|
||||||
observer(it)
|
lifecycleScope.launch {
|
||||||
}
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
viewEvents
|
||||||
|
.stream(tag)
|
||||||
|
.collect {
|
||||||
|
observer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
|
|
|
@ -28,7 +28,7 @@ fun String.trimIndentOneLine() = trimIndent().replace("\n", "")
|
||||||
fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(): ViewModelTest<S, VE> {
|
fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(): ViewModelTest<S, VE> {
|
||||||
val testResultCollectingScope = CoroutineScope(Dispatchers.Unconfined)
|
val testResultCollectingScope = CoroutineScope(Dispatchers.Unconfined)
|
||||||
val state = stateFlow.test(testResultCollectingScope)
|
val state = stateFlow.test(testResultCollectingScope)
|
||||||
val viewEvents = viewEvents.stream().test(testResultCollectingScope)
|
val viewEvents = viewEvents.stream("test").test(testResultCollectingScope)
|
||||||
return ViewModelTest(state, viewEvents)
|
return ViewModelTest(state, viewEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue