Flow migration: start replacing Rx by Flow

This commit is contained in:
ganfra 2021-10-26 14:24:23 +02:00
parent f2c22c1985
commit c936954119
61 changed files with 408 additions and 375 deletions

View File

@ -388,9 +388,6 @@ dependencies {
kapt libs.airbnb.epoxyProcessor
implementation libs.airbnb.epoxyPaging
implementation libs.airbnb.mavericks
//TODO: remove when entirely migrated to Flow
implementation libs.airbnb.mavericksRx
// Work
implementation libs.androidx.work

View File

@ -25,12 +25,19 @@ import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.session.coroutineScope
import im.vector.app.features.ui.UiStateRepository
import io.reactivex.disposables.CompositeDisposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.CancelableBag
import javax.inject.Inject
import javax.inject.Singleton
@ -54,10 +61,10 @@ class AppStateHandler @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder
) : LifecycleObserver {
private val compositeDisposable = CompositeDisposable()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomGroupingMethod>>(Option.empty())
val selectedRoomGroupingObservable = selectedSpaceDataSource.observe()
val selectedRoomGroupingObservable = selectedSpaceDataSource.stream()
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? {
// XXX we should somehow make it live :/ just a work around
@ -105,9 +112,9 @@ class AppStateHandler @Inject constructor(
}
private fun observeActiveSession() {
sessionDataSource.observe()
sessionDataSource.stream()
.distinctUntilChanged()
.subscribe {
.onEach {
// sessionDataSource could already return a session while activeSession holder still returns null
it.orNull()?.let { session ->
if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) {
@ -116,9 +123,8 @@ class AppStateHandler @Inject constructor(
setCurrentGroup(uiStateRepository.getSelectedGroup(session.sessionId), session)
}
}
}.also {
compositeDisposable.add(it)
}
.launchIn(coroutineScope)
}
fun safeActiveSpaceId(): String? {
@ -136,7 +142,7 @@ class AppStateHandler @Inject constructor(
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun entersBackground() {
compositeDisposable.clear()
coroutineScope.coroutineContext.cancelChildren()
val session = activeSessionHolder.getSafeActiveSession() ?: return
when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) {
is RoomGroupingMethod.BySpace -> {

View File

@ -39,6 +39,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.MavericksView
import com.bumptech.glide.util.Util
@ -80,6 +81,10 @@ import im.vector.app.receivers.DebugReceiver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.GlobalError
import timber.log.Timber
@ -104,13 +109,12 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
.stream()
.onEach {
hideWaitingView()
observer(it)
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
}
/* ==========================================================================================

View File

@ -26,6 +26,7 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.CallSuper
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.MavericksView
@ -39,6 +40,10 @@ import im.vector.app.core.utils.DimensionConverter
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import java.util.concurrent.TimeUnit
@ -193,11 +198,10 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
.stream()
.onEach {
observer(it)
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
}

View File

@ -29,6 +29,7 @@ import androidx.annotation.MainThread
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.MavericksView
import com.bumptech.glide.util.Util.assertMainThread
@ -47,6 +48,12 @@ import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import java.util.concurrent.TimeUnit
@ -237,13 +244,12 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
.stream()
.onEach {
dismissLoadingDialog()
observer(it)
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
/* ==========================================================================================

View File

@ -16,53 +16,17 @@
package im.vector.app.core.platform
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.BaseMvRxViewModel
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.MavericksViewModel
import im.vector.app.core.utils.DataSource
import im.vector.app.core.utils.PublishDataSource
import io.reactivex.Observable
import io.reactivex.Single
abstract class VectorViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(initialState: S) :
BaseMvRxViewModel<S>(initialState) {
interface Factory<S : MavericksState> {
fun create(state: S): BaseMvRxViewModel<S>
}
MavericksViewModel<S>(initialState) {
// Used to post transient events to the View
protected val _viewEvents = PublishDataSource<VE>()
val viewEvents: DataSource<VE> = _viewEvents
/**
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
* so you can use this in a switchMap or a flatMap
*/
// False positive
@Suppress("USELESS_CAST", "NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER")
fun <T> Single<T>.toAsync(stateReducer: S.(Async<T>) -> S): Single<Async<T>> {
setState { stateReducer(Loading()) }
return map { Success(it) as Async<T> }
.onErrorReturn { Fail(it) }
.doOnSuccess { setState { stateReducer(it) } }
}
/**
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
* so you can use this in a switchMap or a flatMap
*/
// False positive
@Suppress("USELESS_CAST", "NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER")
fun <T> Observable<T>.toAsync(stateReducer: S.(Async<T>) -> S): Observable<Async<T>> {
setState { stateReducer(Loading()) }
return map { Success(it) as Async<T> }
.onErrorReturn { Fail(it) }
.doOnNext { setState { stateReducer(it) } }
}
abstract fun handle(action: VA)
}

View File

@ -17,12 +17,12 @@
package im.vector.app.core.utils
import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
interface DataSource<T> {
fun observe(): Observable<T>
fun stream(): Flow<T>
}
interface MutableDataSource<T> : DataSource<T> {
@ -34,17 +34,17 @@ interface MutableDataSource<T> : DataSource<T> {
*/
open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableDataSource<T> {
private val behaviorRelay = createRelay()
private val mutableFlow = MutableSharedFlow<T>(replay = 1)
val currentValue: T?
get() = behaviorRelay.value
get() = mutableFlow.replayCache.firstOrNull()
override fun observe(): Observable<T> {
return behaviorRelay.hide().observeOn(AndroidSchedulers.mainThread())
override fun stream(): Flow<T> {
return mutableFlow
}
override fun post(value: T) {
behaviorRelay.accept(value!!)
mutableFlow.tryEmit(value)
}
private fun createRelay(): BehaviorRelay<T> {
@ -61,13 +61,13 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
*/
open class PublishDataSource<T> : MutableDataSource<T> {
private val publishRelay = PublishRelay.create<T>()
private val mutableFlow = MutableSharedFlow<T>(replay = 0, extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override fun observe(): Observable<T> {
return publishRelay.hide().observeOn(AndroidSchedulers.mainThread())
override fun stream(): Flow<T> {
return mutableFlow
}
override fun post(value: T) {
publishRelay.accept(value!!)
mutableFlow.tryEmit(value)
}
}

View File

@ -39,7 +39,7 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
callViewModel.subscribe(this) {
callViewModel.onEach {
renderState(it)
}

View File

@ -35,6 +35,7 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
@ -62,6 +63,10 @@ import im.vector.app.features.home.room.detail.RoomDetailArgs
import io.github.hyuwah.draggableviewlib.DraggableView
import io.github.hyuwah.draggableviewlib.setupDraggable
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.logger.LoggerTag
@ -130,7 +135,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
setSupportActionBar(views.callToolbar)
configureCallViews()
callViewModel.subscribe(this) {
callViewModel.onEach {
renderState(it)
}
@ -141,12 +146,11 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
}
callViewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
.stream()
.onEach {
handleViewEvents(it)
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
callViewModel.onEach(VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall ->
if (isVideoCall) {

View File

@ -68,7 +68,7 @@ class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMee
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
jitsiViewModel.subscribe(this) {
jitsiViewModel.onEach {
renderState(it)
}

View File

@ -22,6 +22,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
@ -46,6 +47,8 @@ import im.vector.app.features.userdirectory.UserListFragment
import im.vector.app.features.userdirectory.UserListFragmentArgs
import im.vector.app.features.userdirectory.UserListSharedAction
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import java.net.HttpURLConnection
@ -64,8 +67,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
when (action) {
UserListSharedAction.Close -> finish()
UserListSharedAction.GoBack -> onBackPressed()
@ -74,7 +77,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
UserListSharedAction.AddByQrCode -> openAddByQrCode()
}.exhaustive
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
if (isFirstCreation()) {
addFragment(
R.id.container,

View File

@ -63,7 +63,7 @@ class SharedSecureStorageActivity :
viewModel.observeViewEvents { observeViewEvents(it) }
viewModel.subscribe(this) { renderState(it) }
viewModel.onEach { renderState(it) }
}
override fun onDestroy() {

View File

@ -55,7 +55,7 @@ class SharedSecuredStorageResetAllFragment @Inject constructor() :
}
}
sharedViewModel.subscribe(this) { state ->
sharedViewModel.onEach { state ->
views.ssssResetOtherDevices.setTextOrHide(
state.activeDeviceCount
.takeIf { it > 0 }

View File

@ -66,7 +66,7 @@ class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStac
override fun initUiAndData() {
super.initUiAndData()
viewModel.subscribe(this) {
viewModel.onEach {
renderState(it)
}

View File

@ -73,6 +73,8 @@ import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import im.vector.app.push.fcm.FcmHelper
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
@ -178,8 +180,8 @@ class HomeActivity :
}
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
@ -222,7 +224,7 @@ class HomeActivity :
}
}.exhaustive
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
val args = intent.getParcelableExtra<HomeActivityArgs>(Mavericks.KEY_ARG)
@ -243,13 +245,13 @@ class HomeActivity :
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
}.exhaustive
}
homeActivityViewModel.subscribe(this) { renderState(it) }
homeActivityViewModel.onEach { renderState(it) }
shortcutsHandler.observeRoomsAndBuildShortcuts()
.disposeOnDestroy()
if (!vectorPreferences.didPromoteNewRestrictedFeature()) {
promoteRestrictedViewModel.subscribe(this) {
promoteRestrictedViewModel.onEach {
if (it.activeSpaceSummary != null && !it.activeSpaceSummary.isPublic &&
it.activeSpaceSummary.otherMemberIds.isNotEmpty()) {
// It's a private space with some members show this once

View File

@ -299,7 +299,7 @@ class HomeDetailFragment @Inject constructor(
private fun setupKeysBackupBanner() {
serverBackupStatusViewModel
.subscribe(this) {
.onEach {
when (val banState = it.bannerState.invoke()) {
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)

View File

@ -39,7 +39,13 @@ import im.vector.app.features.ui.UiStateRepository
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.flow.switchMap
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter
@ -66,7 +72,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
private val directRoomHelper: DirectRoomHelper,
private val appStateHandler: AppStateHandler,
private val autoAcceptInvites: AutoAcceptInvites) :
VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
CallProtocolsChecker.Listener {
@AssistedFactory
@ -194,18 +200,15 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
private fun observeRoomGroupingMethod() {
appStateHandler.selectedRoomGroupingObservable
.subscribe {
setState {
copy(
roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
)
}
.setOnEach {
copy(
roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
)
}
.disposeOnClear()
}
private fun observeRoomSummaries() {
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged().switchMap {
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged().flatMapLatest {
// we use it as a trigger to all changes in room, but do not really load
// the actual models
session.getPagedRoomSummariesLive(
@ -213,11 +216,10 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
memberships = Membership.activeMemberships()
},
sortOrder = RoomSortOrder.NONE
).asObservable()
).asFlow()
}
.observeOn(Schedulers.computation())
.throttleFirst(300, TimeUnit.MILLISECONDS)
.subscribe {
.sample(300)
.onEach {
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
is RoomGroupingMethod.ByLegacyGroup -> {
// TODO!!
@ -274,6 +276,6 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
}
}
}
.disposeOnClear()
.launchIn(viewModelScope)
}
}

View File

@ -29,6 +29,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import kotlinx.coroutines.flow.distinctUntilChanged
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel

View File

@ -16,6 +16,7 @@
package im.vector.app.features.home
import androidx.lifecycle.asFlow
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
@ -30,8 +31,12 @@ import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.sample
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSortOrder
@ -57,7 +62,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
private val vectorPreferences: VectorPreferences,
appStateHandler: AppStateHandler,
private val autoAcceptInvites: AutoAcceptInvites) :
VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<UnreadMessagesSharedViewModel, UnreadMessagesState> {
@ -75,8 +80,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
this.memberships = listOf(Membership.JOIN)
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
}, sortOrder = RoomSortOrder.NONE
).asObservable()
.throttleFirst(300, TimeUnit.MILLISECONDS)
).asFlow()
.sample(300)
.execute {
val counts = session.getNotificationCountForRooms(
roomSummaryQueryParams {
@ -103,91 +108,92 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
)
}
Observable.combineLatest(
combine(
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged(),
appStateHandler.selectedRoomGroupingObservable.switchMap {
appStateHandler.selectedRoomGroupingObservable.flatMapLatest {
session.getPagedRoomSummariesLive(
roomSummaryQueryParams {
this.memberships = Membership.activeMemberships()
}, sortOrder = RoomSortOrder.NONE
).asObservable()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.computation())
},
{ groupingMethod, _ ->
when (groupingMethod.orNull()) {
is RoomGroupingMethod.ByLegacyGroup -> {
// currently not supported
CountInfo(
RoomAggregateNotificationCount(0, 0),
RoomAggregateNotificationCount(0, 0)
)
}
is RoomGroupingMethod.BySpace -> {
val selectedSpace = appStateHandler.safeActiveSpaceId()
).asFlow()
.sample(300)
val inviteCount = if (autoAcceptInvites.hideInvites) {
0
} else {
session.getRoomSummaries(
roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
).size
}
val spaceInviteCount = if (autoAcceptInvites.hideInvites) {
0
} else {
session.getRoomSummaries(
spaceSummaryQueryParams {
this.memberships = listOf(Membership.INVITE)
}
).size
}
val totalCount = session.getNotificationCountForRooms(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
!vectorPreferences.prefSpacesShowAllRoomInHome()
} ?: ActiveSpaceFilter.None
}
)
val counts = RoomAggregateNotificationCount(
totalCount.notificationCount + inviteCount,
totalCount.highlightCount + inviteCount
)
val rootCounts = session.spaceService().getRootSpaceSummaries()
.filter {
// filter out current selection
it.roomId != selectedSpace
}
CountInfo(
homeCount = counts,
otherCount = RoomAggregateNotificationCount(
notificationCount = rootCounts.fold(0, { acc, rs -> acc + rs.notificationCount }) +
(counts.notificationCount.takeIf { selectedSpace != null } ?: 0) +
spaceInviteCount,
highlightCount = rootCounts.fold(0, { acc, rs -> acc + rs.highlightCount }) +
(counts.highlightCount.takeIf { selectedSpace != null } ?: 0) +
spaceInviteCount
)
)
}
null -> {
CountInfo(
RoomAggregateNotificationCount(0, 0),
RoomAggregateNotificationCount(0, 0)
)
}
}
}
).execute {
copy(
homeSpaceUnread = it.invoke()?.homeCount ?: RoomAggregateNotificationCount(0, 0),
otherSpacesUnread = it.invoke()?.otherCount ?: RoomAggregateNotificationCount(0, 0)
)
) { groupingMethod, _ ->
when (groupingMethod.orNull()) {
is RoomGroupingMethod.ByLegacyGroup -> {
// currently not supported
CountInfo(
RoomAggregateNotificationCount(0, 0),
RoomAggregateNotificationCount(0, 0)
)
}
is RoomGroupingMethod.BySpace -> {
val selectedSpace = appStateHandler.safeActiveSpaceId()
val inviteCount = if (autoAcceptInvites.hideInvites) {
0
} else {
session.getRoomSummaries(
roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
).size
}
val spaceInviteCount = if (autoAcceptInvites.hideInvites) {
0
} else {
session.getRoomSummaries(
spaceSummaryQueryParams {
this.memberships = listOf(Membership.INVITE)
}
).size
}
val totalCount = session.getNotificationCountForRooms(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
!vectorPreferences.prefSpacesShowAllRoomInHome()
} ?: ActiveSpaceFilter.None
}
)
val counts = RoomAggregateNotificationCount(
totalCount.notificationCount + inviteCount,
totalCount.highlightCount + inviteCount
)
val rootCounts = session.spaceService().getRootSpaceSummaries()
.filter {
// filter out current selection
it.roomId != selectedSpace
}
CountInfo(
homeCount = counts,
otherCount = RoomAggregateNotificationCount(
notificationCount = rootCounts.fold(0, { acc, rs -> acc + rs.notificationCount }) +
(counts.notificationCount.takeIf { selectedSpace != null } ?: 0) +
spaceInviteCount,
highlightCount = rootCounts.fold(0, { acc, rs -> acc + rs.highlightCount }) +
(counts.highlightCount.takeIf { selectedSpace != null } ?: 0) +
spaceInviteCount
)
)
}
null -> {
CountInfo(
RoomAggregateNotificationCount(0, 0),
RoomAggregateNotificationCount(0, 0)
)
}
}
}
.flowOn(Dispatchers.Default)
.execute {
copy(
homeSpaceUnread = it.invoke()?.homeCount ?: RoomAggregateNotificationCount(0, 0),
otherSpacesUnread = it.invoke()?.otherCount ?: RoomAggregateNotificationCount(0, 0)
)
}
}
}

View File

@ -24,6 +24,7 @@ import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar
@ -40,6 +41,8 @@ import im.vector.app.features.navigation.Navigator
import im.vector.app.features.room.RequireActiveMembershipAction
import im.vector.app.features.room.RequireActiveMembershipViewEvents
import im.vector.app.features.room.RequireActiveMembershipViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@AndroidEntryPoint
class RoomDetailActivity :
@ -97,13 +100,13 @@ class RoomDetailActivity :
sharedActionViewModel = viewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
is RoomDetailSharedAction.SwitchToRoom -> switchToRoom(sharedAction)
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
requireActiveMembershipViewModel.observeViewEvents {
when (it) {

View File

@ -184,6 +184,8 @@ import im.vector.app.features.widgets.WidgetActivity
import im.vector.app.features.widgets.WidgetArgs
import im.vector.app.features.widgets.WidgetKind
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import nl.dionsegijn.konfetti.models.Shape
@ -365,11 +367,11 @@ class RoomDetailFragment @Inject constructor(
}
sharedActionViewModel
.observe()
.subscribe {
.stream()
.onEach {
handleActions(it)
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
knownCallsViewModel
.liveKnownCalls

View File

@ -27,7 +27,6 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -37,6 +36,7 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.mvrx.runCatchingToAsync
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.attachments.toContentAttachmentData
import im.vector.app.features.call.conference.ConferenceEvent
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
@ -56,7 +56,6 @@ import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.voice.VoicePlayerHelper
import io.reactivex.rxkotlin.subscribeBy
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect
@ -123,8 +122,8 @@ class RoomDetailViewModel @AssistedInject constructor(
private val room = session.getRoom(initialState.roomId)!!
private val eventId = initialState.eventId
private val invisibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsInvisible>()
private val visibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsVisible>()
private val invisibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsInvisible>()
private val visibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsVisible>()
private var timelineEvents = MutableSharedFlow<List<TimelineEvent>>(0)
val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId)
@ -562,7 +561,7 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleEventInvisible(action: RoomDetailAction.TimelineEventTurnsInvisible) {
invisibleEventsObservable.accept(action)
invisibleEventsSource.post(action)
}
fun getMember(userId: String): RoomMemberSummary? {
@ -711,12 +710,12 @@ class RoomDetailViewModel @AssistedInject constructor(
private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) {
viewModelScope.launch(Dispatchers.Default) {
if (action.event.root.sendState.isSent()) { // ignore pending/local events
visibleEventsObservable.accept(action)
visibleEventsSource.post(action)
}
// We need to update this with the related m.replace also (to move read receipt)
action.event.annotations?.editSummary?.sourceEvents?.forEach {
room.getTimeLineEvent(it)?.let { event ->
visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event))
visibleEventsSource.post(RoomDetailAction.TimelineEventTurnsVisible(event))
}
}
@ -864,7 +863,9 @@ class RoomDetailViewModel @AssistedInject constructor(
private fun observeEventDisplayedActions() {
// We are buffering scroll events for one second
// and keep the most recent one to set the read receipt on.
visibleEventsObservable
/*
visibleEventsSource
.stream()
.buffer(1, TimeUnit.SECONDS)
.filter { it.isNotEmpty() }
.subscribeBy(onNext = { actions ->
@ -884,6 +885,8 @@ class RoomDetailViewModel @AssistedInject constructor(
}
})
.disposeOnClear()
*/
}
private fun handleMarkAllAsRead() {

View File

@ -104,7 +104,7 @@ class TextComposerViewModel @AssistedInject constructor(
}
private fun subscribeToStateInternal() {
selectSubscribe(TextComposerViewState::sendMode, TextComposerViewState::canSendMessage, TextComposerViewState::isVoiceRecording) { _, _, _ ->
onEach(TextComposerViewState::sendMode, TextComposerViewState::canSendMessage, TextComposerViewState::isVoiceRecording) { _, _, _ ->
updateIsSendButtonVisibility(false)
}
}

View File

@ -32,17 +32,17 @@ import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import io.reactivex.Observable
import io.reactivex.Single
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary
import org.matrix.android.sdk.rx.RxRoom
import org.matrix.android.sdk.rx.unwrap
import org.matrix.android.sdk.flow.FlowRoom
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
data class DisplayReactionsViewState(
val eventId: String,
val roomId: String,
val mapReactionKeyToMemberList: Async<List<ReactionInfo>> = Uninitialized) :
MavericksState {
MavericksState {
constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId)
}
@ -81,39 +81,31 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted
}
private fun observeEventAnnotationSummaries() {
RxRoom(room)
room.flow()
.liveAnnotationSummary(eventId)
.unwrap()
.flatMapSingle { summaries ->
Observable
.fromIterable(summaries.reactionsSummary)
// .filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
.toReactionInfoList()
.map { annotationsSummary ->
annotationsSummary.reactionsSummary
.flatMap { reactionsSummary ->
reactionsSummary.sourceEvents.map {
val event = room.getTimeLineEvent(it)
?: throw RuntimeException("Your eventId is not valid")
ReactionInfo(
event.root.eventId!!,
reactionsSummary.key,
event.root.senderId ?: "",
event.senderInfo.disambiguatedDisplayName,
dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME)
)
}
}
}
.execute {
copy(mapReactionKeyToMemberList = it)
}
}
private fun Observable<ReactionAggregatedSummary>.toReactionInfoList(): Single<List<ReactionInfo>> {
return flatMap { summary ->
Observable
.fromIterable(summary.sourceEvents)
.map {
val event = room.getTimeLineEvent(it)
?: throw RuntimeException("Your eventId is not valid")
ReactionInfo(
event.root.eventId!!,
summary.key,
event.root.senderId ?: "",
event.senderInfo.disambiguatedDisplayName,
dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME)
)
}
}.toList()
}
override fun handle(action: EmptyAction) {
// No op
}

View File

@ -23,6 +23,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -49,6 +50,8 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
import im.vector.app.features.notifications.NotificationDrawerManager
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.extensions.orTrue
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@ -118,9 +121,9 @@ class RoomListFragment @Inject constructor(
views.createChatFabMenu.listener = this
sharedActionViewModel
.observe()
.subscribe { handleQuickActions(it) }
.disposeOnDestroyView()
.stream()
.onEach { handleQuickActions(it) }
.launchIn(viewLifecycleOwner.lifecycleScope)
roomListViewModel.onEach(RoomListViewState::roomMembershipChanges) { ms ->
// it's for invites local echo

View File

@ -20,6 +20,4 @@ import im.vector.app.features.home.RoomListDisplayMode
interface RoomListSectionBuilder {
fun buildSections(mode: RoomListDisplayMode): List<RoomsSection>
fun dispose()
}

View File

@ -17,6 +17,7 @@
package im.vector.app.features.home.room.list
import androidx.annotation.StringRes
import androidx.lifecycle.asFlow
import im.vector.app.AppStateHandler
import im.vector.app.R
import im.vector.app.RoomGroupingMethod
@ -24,17 +25,21 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.showInvites
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.rx.asObservable
class RoomListSectionBuilderGroup(
private val coroutineScope: CoroutineScope,
private val session: Session,
private val stringProvider: StringProvider,
private val appStateHandler: AppStateHandler,
@ -42,8 +47,6 @@ class RoomListSectionBuilderGroup(
private val onUpdatable: (UpdatableLivePageResult) -> Unit
) : RoomListSectionBuilder {
private val disposables = CompositeDisposable()
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
val sections = mutableListOf<RoomsSection>()
@ -103,16 +106,14 @@ class RoomListSectionBuilderGroup(
appStateHandler.selectedRoomGroupingObservable
.distinctUntilChanged()
.subscribe { groupingMethod ->
.onEach { groupingMethod ->
val selectedGroupId = (groupingMethod.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
activeGroupAwareQueries.onEach { updater ->
updater.updateQuery { query ->
query.copy(activeGroupId = selectedGroupId)
}
}
}.also {
disposables.add(it)
}
}.launchIn(coroutineScope)
return sections
}
@ -251,15 +252,14 @@ class RoomListSectionBuilderGroup(
}.livePagedList
.let { livePagedList ->
// use it also as a source to update count
livePagedList.asObservable()
.observeOn(Schedulers.computation())
.subscribe {
livePagedList.asFlow()
.onEach {
sections.find { it.sectionName == name }
?.notificationCount
?.postValue(session.getNotificationCountForRooms(roomQueryParams))
}.also {
disposables.add(it)
}
.flowOn(Dispatchers.Default)
.launchIn(coroutineScope)
sections.add(
RoomsSection(
@ -280,8 +280,4 @@ class RoomListSectionBuilderGroup(
.build()
.let { block(it) }
}
override fun dispose() {
disposables.dispose()
}
}

View File

@ -19,6 +19,7 @@ package im.vector.app.features.home.room.list
import androidx.annotation.StringRes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asFlow
import androidx.lifecycle.liveData
import androidx.paging.PagedList
import com.airbnb.mvrx.Async
@ -31,10 +32,17 @@ import im.vector.app.features.invite.showInvites
import im.vector.app.space
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter
@ -45,6 +53,7 @@ import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
import org.matrix.android.sdk.rx.asObservable
import timber.log.Timber
class RoomListSectionBuilderSpace(
private val session: Session,
@ -57,8 +66,6 @@ class RoomListSectionBuilderSpace(
private val onlyOrphansInHome: Boolean = false
) : RoomListSectionBuilder {
private val disposables = CompositeDisposable()
private val pagedListConfig = PagedList.Config.Builder()
.setPageSize(10)
.setInitialLoadSizeHint(20)
@ -132,14 +139,12 @@ class RoomListSectionBuilderSpace(
appStateHandler.selectedRoomGroupingObservable
.distinctUntilChanged()
.subscribe { groupingMethod ->
.onEach { groupingMethod ->
val selectedSpace = groupingMethod.orNull()?.space()
activeSpaceAwareQueries.onEach { updater ->
updater.updateForSpaceId(selectedSpace?.roomId)
}
}.also {
disposables.add(it)
}
}.launchIn(viewModelScope)
return sections
}
@ -221,13 +226,13 @@ class RoomListSectionBuilderSpace(
}
// add suggested rooms
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>()
appStateHandler.selectedRoomGroupingObservable
.distinctUntilChanged()
.switchMap { groupingMethod ->
.flatMapLatest { groupingMethod ->
val selectedSpace = groupingMethod.orNull()?.space()
if (selectedSpace == null) {
Observable.just(emptyList())
flowOf(emptyList())
} else {
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
val spaceSum = tryOrNull {
@ -240,24 +245,23 @@ class RoomListSectionBuilderSpace(
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
}
emit(filtered)
}.asObservable()
}.asFlow()
}
}
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
Observables.combineLatest(
suggestedRoomsObservable,
suggestedRoomJoiningState.asObservable()
combine(
suggestedRoomsFlow,
suggestedRoomJoiningState.asFlow()
) { rooms, joinStates ->
SuggestedRoomInfo(
rooms,
joinStates
)
}.subscribe {
}.onEach {
liveSuggestedRooms.postValue(it)
}.also {
disposables.add(it)
}
}.launchIn(viewModelScope)
sections.add(
RoomsSection(
sectionName = stringProvider.getString(R.string.suggested_header),
@ -373,9 +377,9 @@ class RoomListSectionBuilderSpace(
}.livePagedList
.let { livePagedList ->
// use it also as a source to update count
livePagedList.asObservable()
.observeOn(Schedulers.computation())
.subscribe {
livePagedList.asFlow()
.onEach {
Timber.v("Thread space list: ${Thread.currentThread()}")
sections.find { it.sectionName == name }
?.notificationCount
?.postValue(
@ -387,9 +391,9 @@ class RoomListSectionBuilderSpace(
)
}
)
}.also {
disposables.add(it)
}
.flowOn(Dispatchers.Default)
.launchIn(viewModelScope)
sections.add(
RoomsSection(
@ -432,8 +436,4 @@ class RoomListSectionBuilderSpace(
RoomListViewModel.SpaceFilterStrategy.NONE -> this
}
}
override fun dispose() {
disposables.dispose()
}
}

View File

@ -135,6 +135,7 @@ class RoomListViewModel @AssistedInject constructor(
)
} else {
RoomListSectionBuilderGroup(
viewModelScope,
session,
stringProvider,
appStateHandler,
@ -336,8 +337,4 @@ class RoomListViewModel @AssistedInject constructor(
}
}
override fun onCleared() {
super.onCleared()
roomListSectionBuilder.dispose()
}
}

View File

@ -21,6 +21,7 @@ import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -41,6 +42,8 @@ import im.vector.app.features.userdirectory.UserListFragment
import im.vector.app.features.userdirectory.UserListFragmentArgs
import im.vector.app.features.userdirectory.UserListSharedAction
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.failure.Failure
import java.net.HttpURLConnection
@ -63,8 +66,8 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() {
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
UserListSharedAction.Close -> finish()
UserListSharedAction.GoBack -> onBackPressed()
@ -75,7 +78,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() {
}
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
if (isFirstCreation()) {
addFragment(
R.id.container,

View File

@ -19,10 +19,14 @@ package im.vector.app.features.invite
import im.vector.app.ActiveSessionDataSource
import im.vector.app.features.session.coroutineScope
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -51,7 +55,8 @@ class InvitesAcceptor @Inject constructor(
private val autoAcceptInvites: AutoAcceptInvites
) : Session.Listener {
private lateinit var activeSessionDisposable: Disposable
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val shouldRejectRoomIds = mutableSetOf<String>()
private val activeSessionIds = mutableSetOf<String>()
private val semaphore = Semaphore(1)
@ -61,13 +66,14 @@ class InvitesAcceptor @Inject constructor(
}
private fun observeActiveSession() {
activeSessionDisposable = sessionDataSource.observe()
sessionDataSource.stream()
.distinctUntilChanged()
.subscribe {
.onEach {
it.orNull()?.let { session ->
onSessionActive(session)
}
}
.launchIn(coroutineScope)
}
private fun onSessionActive(session: Session) {

View File

@ -85,10 +85,9 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
addFirstFragment()
}
loginViewModel
.subscribe(this) {
updateWithState(it)
}
loginViewModel.onEach {
updateWithState(it)
}
loginViewModel.observeViewEvents { handleLoginViewEvents(it) }

View File

@ -92,10 +92,9 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
addFirstFragment()
}
loginViewModel
.subscribe(this) {
updateWithState(it)
}
loginViewModel.onEach {
updateWithState(it)
}
loginViewModel.observeViewEvents { handleLoginViewEvents(it) }
@ -201,19 +200,19 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
// Go back to the login fragment
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
}
is LoginViewEvents2.OnSendEmailSuccess ->
is LoginViewEvents2.OnSendEmailSuccess ->
addFragmentToBackstack(R.id.loginFragmentContainer,
LoginWaitForEmailFragment2::class.java,
LoginWaitForEmailFragmentArgument(event.email),
tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption)
is LoginViewEvents2.OpenSigninPasswordScreen -> {
is LoginViewEvents2.OpenSigninPasswordScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer,
LoginFragmentSigninPassword2::class.java,
tag = FRAGMENT_LOGIN_TAG,
option = commonOption)
}
is LoginViewEvents2.OpenSignupPasswordScreen -> {
is LoginViewEvents2.OpenSignupPasswordScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer,
LoginFragmentSignupPassword2::class.java,
tag = FRAGMENT_REGISTRATION_STAGE_TAG,

View File

@ -33,8 +33,8 @@ class PowerLevelsFlowFactory(private val room: Room) {
fun createFlow(): Flow<PowerLevelsContent> {
return room.flow()
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
.flowOn(Dispatchers.Default)
.mapOptional { it.content.toModel<PowerLevelsContent>() }
.flowOn(Dispatchers.Default)
.unwrap()
}
}

View File

@ -77,8 +77,8 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
room.flow()
.liveRoomSummary()
.unwrap()
.flowOn(Dispatchers.Default)
.map { mapToLeftViewEvent(room, it) }
.flowOn(Dispatchers.Default)
}
.unwrap()
.onEach { event ->

View File

@ -19,6 +19,7 @@ package im.vector.app.features.roomdirectory
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.viewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
@ -31,6 +32,8 @@ import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@AndroidEntryPoint
@ -53,8 +56,8 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
}
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
is RoomDirectorySharedAction.Back -> popBackstack()
is RoomDirectorySharedAction.CreateRoom -> {
@ -72,7 +75,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
is RoomDirectorySharedAction.Close -> finish()
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
}
override fun initUiAndData() {

View File

@ -19,6 +19,7 @@ package im.vector.app.features.roomdirectory.createroom
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
@ -28,6 +29,8 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
/**
* Simple container for [CreateRoomFragment]
@ -62,14 +65,14 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
super.onCreate(savedInstanceState)
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
is RoomDirectorySharedAction.Back,
is RoomDirectorySharedAction.Close -> finish()
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
}
companion object {

View File

@ -23,6 +23,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
@ -44,6 +45,8 @@ import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
import im.vector.app.features.roomprofile.settings.joinrule.toOption
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
@ -103,11 +106,11 @@ class CreateRoomFragment @Inject constructor(
private fun setupRoomJoinRuleSharedActionViewModel() {
roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
roomJoinRuleSharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
viewModel.handle(CreateRoomAction.SetVisibility(action.roomJoinRule))
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
override fun showFailure(throwable: Throwable) {

View File

@ -20,6 +20,7 @@ package im.vector.app.features.roomprofile
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar
@ -41,6 +42,8 @@ import im.vector.app.features.roomprofile.notifications.RoomNotificationSettings
import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@AndroidEntryPoint
@ -93,8 +96,8 @@ class RoomProfileActivity :
}
}
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers()
RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings()
@ -105,7 +108,7 @@ class RoomProfileActivity :
RoomProfileSharedAction.OpenRoomNotificationSettings -> openRoomNotificationSettings()
}.exhaustive
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
requireActiveMembershipViewModel.observeViewEvents {
when (it) {

View File

@ -26,6 +26,7 @@ import android.view.ViewGroup
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.view.isVisible
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -52,6 +53,8 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.api.util.toMatrixItem
@ -124,9 +127,9 @@ class RoomProfileFragment @Inject constructor(
}.exhaustive
}
roomListQuickActionsSharedActionViewModel
.observe()
.subscribe { handleQuickActions(it) }
.disposeOnDestroyView()
.stream()
.onEach { handleQuickActions(it) }
.launchIn(viewLifecycleOwner.lifecycleScope)
setupClicks()
setupLongClicks()
}

View File

@ -21,6 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -38,6 +39,8 @@ import im.vector.app.features.roomprofile.RoomProfileArgs
import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheet
import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedAction
import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.util.toMatrixItem
@ -77,9 +80,9 @@ class RoomAliasFragment @Inject constructor(
}
sharedActionViewModel
.observe()
.subscribe { handleAliasAction(it) }
.disposeOnDestroyView()
.stream()
.onEach { handleAliasAction(it) }
.launchIn(viewLifecycleOwner.lifecycleScope)
}
private fun handleAliasAction(action: RoomAliasBottomSheetSharedAction?) {

View File

@ -95,7 +95,6 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
if (room.isEncrypted()) {
room.flow().liveRoomMembers(roomMemberQueryParams)
.flowOn(Dispatchers.Main)
.flatMapLatest { membersSummary ->
session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId })
.asFlow()

View File

@ -24,6 +24,7 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -46,6 +47,8 @@ import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistory
import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilitySharedActionViewModel
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.util.toMatrixItem
import java.util.UUID
@ -101,21 +104,21 @@ class RoomSettingsFragment @Inject constructor(
private fun setupRoomJoinRuleSharedActionViewModel() {
roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
roomJoinRuleSharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
viewModel.handle(RoomSettingsAction.SetRoomJoinRule(action.roomJoinRule))
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
private fun setupRoomHistoryVisibilitySharedActionViewModel() {
roomHistoryVisibilitySharedActionViewModel = activityViewModelProvider.get(RoomHistoryVisibilitySharedActionViewModel::class.java)
roomHistoryVisibilitySharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
viewModel.handle(RoomSettingsAction.SetRoomHistoryVisibility(action.roomHistoryVisibility))
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
private fun showSuccess() {

View File

@ -149,11 +149,11 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
refreshMyDevice()
refreshXSigningStatus()
session.liveSecretSynchronisationInfo()
.flowOn(Dispatchers.Main)
.onEach {
refresh4SSection(it)
refreshXSigningStatus()
}.launchIn(viewLifecycleOwner.lifecycleScope)
}
.launchIn(viewLifecycleOwner.lifecycleScope)
lifecycleScope.launchWhenResumed {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =

View File

@ -31,6 +31,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.PublishDataSource
import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper
import io.reactivex.subjects.PublishSubject
@ -66,6 +67,7 @@ import org.matrix.android.sdk.internal.util.awaitCallback
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.net.ssl.HttpsURLConnection
import javax.sql.DataSource
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@ -103,7 +105,7 @@ class DevicesViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<DevicesViewModel, DevicesViewState> by hiltMavericksViewModelFactory()
private val refreshPublisher: PublishSubject<Unit> = PublishSubject.create()
private val refreshSource= PublishDataSource<Unit>()
init {
@ -166,12 +168,12 @@ class DevicesViewModel @AssistedInject constructor(
// )
// }
refreshPublisher.throttleFirst(4_000, TimeUnit.MILLISECONDS)
.subscribe {
refreshSource.stream().sample(4_000)
.onEach {
session.cryptoService().fetchDevicesList(NoOpMatrixCallback())
session.cryptoService().downloadKeys(listOf(session.myUserId), true, NoOpMatrixCallback())
}
.disposeOnClear()
.launchIn(viewModelScope)
// then force download
queryRefreshDevicesList()
}
@ -193,7 +195,7 @@ class DevicesViewModel @AssistedInject constructor(
* It can be any mobile devices, and any browsers.
*/
private fun queryRefreshDevicesList() {
refreshPublisher.onNext(Unit)
refreshSource.post(Unit)
}
override fun handle(action: DevicesAction) {

View File

@ -50,7 +50,7 @@ class SoftLogoutActivity : LoginActivity() {
override fun initUiAndData() {
super.initUiAndData()
softLogoutViewModel.subscribe(this) {
softLogoutViewModel.onEach {
updateWithState(it)
}

View File

@ -52,7 +52,7 @@ class SoftLogoutActivity2 : LoginActivity2() {
override fun initUiAndData() {
super.initUiAndData()
softLogoutViewModel.subscribe(this) {
softLogoutViewModel.onEach {
updateWithState(it)
}

View File

@ -55,7 +55,7 @@ class SoftLogoutFragment @Inject constructor(
setupRecyclerView()
softLogoutViewModel.subscribe(this) { softLogoutViewState ->
softLogoutViewModel.onEach { softLogoutViewState ->
softLogoutController.update(softLogoutViewState)
when (val mode = softLogoutViewState.asyncHomeServerLoginFlowRequest.invoke()) {
is LoginMode.SsoAndPassword -> {

View File

@ -71,7 +71,7 @@ class SpaceCreationActivity : SimpleFragmentActivity() {
override fun initUiAndData() {
super.initUiAndData()
viewModel.subscribe(this) {
viewModel.onEach {
renderState(it)
}

View File

@ -35,6 +35,7 @@ import im.vector.app.group
import im.vector.app.space
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@ -89,14 +90,11 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
// observeSelectionState()
appStateHandler.selectedRoomGroupingObservable
.distinctUntilChanged()
.subscribe {
setState {
copy(
selectedGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
)
}
.setOnEach {
copy(
selectedGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
)
}
.disposeOnClear()
session.getGroupSummariesLive(groupSummaryQueryParams {})
.asFlow()
@ -114,7 +112,6 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
}, sortOrder = RoomSortOrder.NONE
).asFlow()
.sample(300)
.flowOn(Dispatchers.Default)
.onEach {
val inviteCount = if (autoAcceptInvites.hideInvites) {
0
@ -140,7 +137,9 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
homeAggregateCount = counts
)
}
}.launchIn(viewModelScope)
}
.flowOn(Dispatchers.Default)
.launchIn(viewModelScope)
}
override fun handle(action: SpaceListAction) {

View File

@ -19,6 +19,7 @@ package im.vector.app.features.spaces
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import im.vector.app.R
import im.vector.app.core.extensions.commitTransaction
@ -26,6 +27,8 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.spaces.preview.SpacePreviewArgs
import im.vector.app.features.spaces.preview.SpacePreviewFragment
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
@ -37,8 +40,8 @@ class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
super.onCreate(savedInstanceState)
sharedActionViewModel = viewModelProvider.get(SpacePreviewSharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
when (action) {
SpacePreviewSharedAction.DismissAction -> finish()
SpacePreviewSharedAction.ShowModalLoading -> showWaitingView()
@ -46,7 +49,7 @@ class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
is SpacePreviewSharedAction.ShowErrorMessage -> action.error?.let { showSnackbar(it) }
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
if (isFirstCreation()) {
val simpleName = SpacePreviewFragment::class.java.simpleName

View File

@ -50,7 +50,7 @@ class CreateSpaceAdd3pidInvitesFragment @Inject constructor(
views.recyclerView.configureWith(epoxyController)
epoxyController.listener = this
sharedViewModel.subscribe(this) {
sharedViewModel.onEach {
invalidateState(it)
}

View File

@ -46,7 +46,7 @@ class CreateSpaceDefaultRoomsFragment @Inject constructor(
views.recyclerView.configureWith(epoxyController)
epoxyController.listener = this
sharedViewModel.subscribe(this) {
sharedViewModel.onEach {
epoxyController.setData(it)
}

View File

@ -50,7 +50,7 @@ class CreateSpaceDetailsFragment @Inject constructor(
views.recyclerView.configureWith(epoxyController)
epoxyController.listener = this
sharedViewModel.subscribe(this) {
sharedViewModel.onEach {
epoxyController.setData(it)
}

View File

@ -86,7 +86,7 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity<ActivitySimpleLoadingBindi
override fun initUiAndData() {
super.initUiAndData()
waitingView = views.waitingView.waitingView
leaveViewModel.subscribe(this) { state ->
leaveViewModel.onEach { state ->
when (state.leaveState) {
is Loading -> {
showWaitingView()

View File

@ -22,6 +22,7 @@ import android.os.Bundle
import android.os.Parcelable
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import com.airbnb.mvrx.withState
@ -41,6 +42,8 @@ import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
import im.vector.app.features.roomprofile.RoomProfileArgs
import im.vector.app.features.roomprofile.alias.RoomAliasFragment
import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
@Parcelize
@ -80,14 +83,14 @@ class SpaceManageActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
sharedDirectoryActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
sharedDirectoryActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
is RoomDirectorySharedAction.Back,
is RoomDirectorySharedAction.Close -> finish()
}
}
.disposeOnDestroy()
.launchIn(lifecycleScope)
val args = intent?.getParcelableExtra<SpaceManageArgs>(Mavericks.KEY_ARG)
if (isFirstCreation()) {

View File

@ -24,6 +24,7 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
@ -49,6 +50,8 @@ import im.vector.app.features.roomprofile.settings.RoomSettingsViewModel
import im.vector.app.features.roomprofile.settings.RoomSettingsViewState
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity
import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
@ -142,11 +145,11 @@ class SpaceSettingsFragment @Inject constructor(
private fun setupRoomJoinRuleSharedActionViewModel() {
roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
roomJoinRuleSharedActionViewModel
.observe()
.subscribe { action ->
.stream()
.onEach { action ->
viewModel.handle(RoomSettingsAction.SetRoomJoinRule(action.roomJoinRule))
}
.disposeOnDestroyView()
.launchIn(viewLifecycleOwner.lifecycleScope)
}
private var ignoreChanges = false

View File

@ -21,6 +21,7 @@ import android.content.Intent
import android.os.Bundle
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import im.vector.app.R
import im.vector.app.core.extensions.commitTransaction
@ -29,6 +30,8 @@ import im.vector.app.core.platform.GenericIdArgs
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleLoadingBinding
import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
@ -73,8 +76,8 @@ class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
sharedActionViewModel = viewModelProvider.get(SpacePeopleSharedActionViewModel::class.java)
sharedActionViewModel
.observe()
.subscribe { sharedAction ->
.stream()
.onEach { sharedAction ->
when (sharedAction) {
SpacePeopleSharedAction.Dismiss -> finish()
is SpacePeopleSharedAction.NavigateToRoom -> navigateToRooms(sharedAction)
@ -86,7 +89,7 @@ class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
ShareSpaceBottomSheet.show(supportFragmentManager, sharedAction.spaceId)
}
}
}.disposeOnDestroy()
}.launchIn(lifecycleScope)
}
private fun navigateToRooms(action: SpacePeopleSharedAction.NavigateToRoom) {

View File

@ -91,7 +91,7 @@ class SpacePeopleFragment @Inject constructor(
handleViewEvents(it)
}
viewModel.subscribe(this) {
viewModel.onEach {
when (it.createAndInviteState) {
is Loading -> sharedActionViewModel.post(SpacePeopleSharedAction.ShowModalLoading)
Uninitialized,

View File

@ -160,10 +160,10 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
knownUsersSearch
.sample(300)
.flowOn(Dispatchers.Main)
.flatMapLatest { search ->
session.getPagedUsersLive(search, state.excludedUserIds).asFlow()
}.execute {
}
.execute {
copy(knownUsers = it)
}

View File

@ -27,17 +27,17 @@ fun String.trimIndentOneLine() = trimIndent().replace("\n", "")
fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(): ViewModelTest<S, VE> {
val state = { com.airbnb.mvrx.withState(this) { it } }
val viewEvents = viewEvents.observe().test()
return ViewModelTest(state, viewEvents)
//val viewEvents = viewEvents.stream().test()
return ViewModelTest(state)
}
class ViewModelTest<S, VE>(
val state: () -> S,
val viewEvents: TestObserver<VE>
//val viewEvents: TestObserver<VE>
) {
fun assertEvents(vararg expected: VE) {
viewEvents.assertValues(*expected)
//viewEvents.assertValues(*expected)
}
fun assertState(expected: S) {