Mavericks 2: continue replacing Rx

This commit is contained in:
ganfra 2021-10-04 14:09:21 +02:00
parent 0e01c64f69
commit f72a34ed08
20 changed files with 236 additions and 243 deletions

View File

@ -16,7 +16,6 @@
package im.vector.app.features.home package im.vector.app.features.home
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
@ -47,6 +46,7 @@ import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.asObservable import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
@ -95,7 +95,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
updateShowDialPadTab() updateShowDialPadTab()
observeDataStore() observeDataStore()
callManager.addProtocolsCheckerListener(this) callManager.addProtocolsCheckerListener(this)
session.rx().liveUser(session.myUserId).execute { session.flow().liveUser(session.myUserId).execute {
copy( copy(
myMatrixItem = it.invoke()?.getOrNull()?.toMatrixItem() myMatrixItem = it.invoke()?.getOrNull()?.toMatrixItem()
) )

View File

@ -25,25 +25,25 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit
data class UnknownDevicesState( data class UnknownDevicesState(
val myMatrixItem: MatrixItem.UserItem? = null, val myMatrixItem: MatrixItem.UserItem? = null,
@ -98,31 +98,31 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
} }
) )
Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, Optional<PrivateKeysInfo>, List<DeviceDetectionInfo>>( combine(
session.rx().liveUserCryptoDevices(session.myUserId), session.flow().liveUserCryptoDevices(session.myUserId),
session.rx().liveMyDevicesInfo(), session.flow().liveMyDevicesInfo(),
session.rx().liveCrossSigningPrivateKeys(), session.flow().liveCrossSigningPrivateKeys()
{ cryptoList, infoList, pInfo ->
// Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}")
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
infoList
.filter { info ->
// filter verified session, by checking the crypto device info
cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse()
}
// filter out ignored devices
.filter { !ignoredDeviceList.contains(it.deviceId) }
.sortedByDescending { it.lastSeenTs }
.map { deviceInfo ->
val deviceKnownSince = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }?.firstTimeSeenLocalTs ?: 0
DeviceDetectionInfo(
deviceInfo,
deviceKnownSince > currentSessionTs + 60_000, // short window to avoid false positive,
pInfo.getOrNull()?.selfSigned != null // adding this to pass distinct when cross sign change
)
}
}
) )
{ cryptoList, infoList, pInfo ->
// Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}")
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
infoList
.filter { info ->
// filter verified session, by checking the crypto device info
cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse()
}
// filter out ignored devices
.filter { !ignoredDeviceList.contains(it.deviceId) }
.sortedByDescending { it.lastSeenTs }
.map { deviceInfo ->
val deviceKnownSince = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }?.firstTimeSeenLocalTs ?: 0
DeviceDetectionInfo(
deviceInfo,
deviceKnownSince > currentSessionTs + 60_000, // short window to avoid false positive,
pInfo.getOrNull()?.selfSigned != null // adding this to pass distinct when cross sign change
)
}
}
.distinctUntilChanged() .distinctUntilChanged()
.execute { async -> .execute { async ->
// Timber.v("## Detector trigger passed distinct") // Timber.v("## Detector trigger passed distinct")
@ -132,14 +132,14 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
) )
} }
session.rx().liveUserCryptoDevices(session.myUserId) session.flow().liveUserCryptoDevices(session.myUserId)
.distinctUntilChanged() .distinctUntilChanged()
.throttleLast(5_000, TimeUnit.MILLISECONDS) .sample(5_000)
.subscribe { .onEach {
// If we have a new crypto device change, we might want to trigger refresh of device info // If we have a new crypto device change, we might want to trigger refresh of device info
session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) session.cryptoService().fetchDevicesList(NoOpMatrixCallback())
} }
.disposeOnClear() .launchIn(viewModelScope)
// trigger a refresh of lastSeen / last Ip // trigger a refresh of lastSeen / last Ip
session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) session.cryptoService().fetchDevicesList(NoOpMatrixCallback())

View File

@ -28,7 +28,6 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
@ -60,11 +59,11 @@ import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.voice.VoicePlayerHelper import im.vector.app.features.voice.VoicePlayerHelper
import io.reactivex.Observable
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -112,8 +111,6 @@ import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@ -143,7 +140,7 @@ class RoomDetailViewModel @AssistedInject constructor(
private val eventId = initialState.eventId private val eventId = initialState.eventId
private val invisibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsInvisible>() private val invisibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsInvisible>()
private val visibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsVisible>() private val visibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsVisible>()
private var timelineEvents = PublishRelay.create<List<TimelineEvent>>() private var timelineEvents = MutableSharedFlow<List<TimelineEvent>>(0)
val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId) val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId)
// Same lifecycle than the ViewModel (survive to screen rotation) // Same lifecycle than the ViewModel (survive to screen rotation)
@ -1533,14 +1530,12 @@ class RoomDetailViewModel @AssistedInject constructor(
} }
private fun getUnreadState() { private fun getUnreadState() {
Observable combine(
.combineLatest<List<TimelineEvent>, RoomSummary, UnreadState>( timelineEvents,
timelineEvents.observeOn(Schedulers.computation()), room.flow().liveRoomSummary().unwrap()
room.rx().liveRoomSummary().unwrap(), ) { timelineEvents, roomSummary ->
{ timelineEvents, roomSummary -> computeUnreadState(timelineEvents, roomSummary)
computeUnreadState(timelineEvents, roomSummary) }
}
)
// We don't want live update of unread so we skip when we already had a HasUnread or HasNoUnread // We don't want live update of unread so we skip when we already had a HasUnread or HasNoUnread
.distinctUntilChanged { previous, current -> .distinctUntilChanged { previous, current ->
when { when {
@ -1549,10 +1544,9 @@ class RoomDetailViewModel @AssistedInject constructor(
else -> false else -> false
} }
} }
.subscribe { .setOnEach {
setState { copy(unreadState = it) } copy(unreadState = it)
} }
.disposeOnClear()
} }
private fun computeUnreadState(events: List<TimelineEvent>, roomSummary: RoomSummary): UnreadState { private fun computeUnreadState(events: List<TimelineEvent>, roomSummary: RoomSummary): UnreadState {
@ -1619,7 +1613,7 @@ class RoomDetailViewModel @AssistedInject constructor(
} }
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) { override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
timelineEvents.accept(snapshot) timelineEvents.tryEmit(snapshot)
// PreviewUrl // PreviewUrl
if (vectorPreferences.showUrlPreviews()) { if (vectorPreferences.showUrlPreviews()) {

View File

@ -25,20 +25,17 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.mvrx.runCatchingToAsync
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineLatest
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -50,8 +47,6 @@ import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.session.room.powerlevels.Role
@ -60,8 +55,6 @@ import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState, class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
@ -114,7 +107,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
} }
} }
session.rx().liveUserCryptoDevices(initialState.userId) session.flow().liveUserCryptoDevices(initialState.userId)
.map { .map {
Pair( Pair(
it.fold(true, { prev, dev -> prev && dev.isVerified }), it.fold(true, { prev, dev -> prev && dev.isVerified }),
@ -128,14 +121,14 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
) )
} }
session.rx().liveCrossSigningInfo(initialState.userId) session.flow().liveCrossSigningInfo(initialState.userId)
.execute { .execute {
copy(userMXCrossSigningInfo = it.invoke()?.getOrNull()) copy(userMXCrossSigningInfo = it.invoke()?.getOrNull())
} }
} }
private fun observeIgnoredState() { private fun observeIgnoredState() {
session.rx().liveIgnoredUsers() session.flow().liveIgnoredUsers()
.map { ignored -> .map { ignored ->
ignored.find { ignored.find {
it.userId == initialState.userId it.userId == initialState.userId
@ -252,7 +245,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
val queryParams = roomMemberQueryParams { val queryParams = roomMemberQueryParams {
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE) this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
} }
room.rx().liveRoomMembers(queryParams) room.flow().liveRoomMembers(queryParams)
.map { it.firstOrNull().toOptional() } .map { it.firstOrNull().toOptional() }
.unwrap() .unwrap()
.execute { .execute {
@ -312,7 +305,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
roomSummaryLive.execute { roomSummaryLive.execute {
copy(isRoomEncrypted = it.invoke()?.isEncrypted == true) copy(isRoomEncrypted = it.invoke()?.isEncrypted == true)
} }
roomSummaryLive.combine(powerLevelsContentLive){roomSummary, powerLevelsContent -> roomSummaryLive.combine(powerLevelsContentLive) { roomSummary, powerLevelsContent ->
val roomName = roomSummary.toMatrixItem().getBestName() val roomName = roomSummary.toMatrixItem().getBestName()
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent) val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
when (val userPowerLevel = powerLevelsHelper.getUserRole(initialState.userId)) { when (val userPowerLevel = powerLevelsHelper.getUserRole(initialState.userId)) {

View File

@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
@ -55,14 +56,14 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva
} }
init { init {
session.rx().liveUserCryptoDevices(args.userId) session.flow().liveUserCryptoDevices(args.userId)
.execute { .execute {
copy(cryptoDevices = it).also { copy(cryptoDevices = it).also {
refreshSelectedId() refreshSelectedId()
} }
} }
session.rx().liveCrossSigningInfo(args.userId) session.flow().liveCrossSigningInfo(args.userId)
.execute { .execute {
copy(memberCrossSigningKey = it.invoke()?.getOrNull()) copy(memberCrossSigningKey = it.invoke()?.getOrNull())
} }

View File

@ -131,7 +131,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo
} }
private fun observeRoomSummary() { private fun observeRoomSummary() {
room.rx().liveRoomSummary() room.flow().liveRoomSummary()
.unwrap() .unwrap()
.execute { async -> .execute { async ->
copy( copy(

View File

@ -38,6 +38,8 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap import org.matrix.android.sdk.rx.unwrap
@ -54,15 +56,14 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia
private val room = session.getRoom(initialState.roomId)!! private val room = session.getRoom(initialState.roomId)!!
init { init {
val rxRoom = room.rx()
room.rx().liveRoomSummary() room.flow().liveRoomSummary()
.unwrap() .unwrap()
.execute { async -> .execute { async ->
copy(roomSummary = async) copy(roomSummary = async)
} }
rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) }) room.flow().liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
.execute { .execute {
copy( copy(
bannedMemberSummaries = it bannedMemberSummaries = it

View File

@ -16,6 +16,7 @@
package im.vector.app.features.roomprofile.members package im.vector.app.features.roomprofile.members
import androidx.lifecycle.asFlow
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
@ -27,10 +28,16 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.switchMap
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
@ -44,10 +51,9 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.rx.asObservable import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.mapOptional import org.matrix.android.sdk.flow.mapOptional
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.rx.unwrap
import timber.log.Timber import timber.log.Timber
class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberListViewState, class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberListViewState,
@ -87,28 +93,28 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
memberships = Membership.activeMemberships() memberships = Membership.activeMemberships()
} }
Observable combine(
.combineLatest<List<RoomMemberSummary>, PowerLevelsContent, RoomMemberSummaries>( room.flow().liveRoomMembers(roomMemberQueryParams),
room.rx().liveRoomMembers(roomMemberQueryParams), room.flow()
room.rx() .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) .mapOptional { it.content.toModel<PowerLevelsContent>() }
.mapOptional { it.content.toModel<PowerLevelsContent>() } .unwrap()
.unwrap(), )
{ roomMembers, powerLevelsContent -> { roomMembers, powerLevelsContent ->
buildRoomMemberSummaries(powerLevelsContent, roomMembers) buildRoomMemberSummaries(powerLevelsContent, roomMembers)
} }
)
.execute { async -> .execute { async ->
copy(roomMemberSummaries = async) copy(roomMemberSummaries = async)
} }
if (room.isEncrypted()) { if (room.isEncrypted()) {
room.rx().liveRoomMembers(roomMemberQueryParams) room.flow().liveRoomMembers(roomMemberQueryParams)
.observeOn(AndroidSchedulers.mainThread()) .flowOn(Dispatchers.Main)
.switchMap { membersSummary -> .flatMapLatest { membersSummary ->
session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId }) session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId })
.asObservable() .asFlow()
.doOnError { Timber.e(it) } .catch { Timber.e(it) }
.map { deviceList -> .map { deviceList ->
// If any key change, emit the userIds list // If any key change, emit the userIds list
deviceList.groupBy { it.userId }.mapValues { deviceList.groupBy { it.userId }.mapValues {
@ -147,7 +153,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
} }
private fun observeRoomSummary() { private fun observeRoomSummary() {
room.rx().liveRoomSummary() room.flow().liveRoomSummary()
.unwrap() .unwrap()
.execute { async -> .execute { async ->
copy(roomSummary = async) copy(roomSummary = async)
@ -155,7 +161,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
} }
private fun observeThirdPartyInvites() { private fun observeThirdPartyInvites() {
room.rx().liveStateEvents(setOf(EventType.STATE_ROOM_THIRD_PARTY_INVITE)) room.flow().liveStateEvents(setOf(EventType.STATE_ROOM_THIRD_PARTY_INVITE))
.execute { async -> .execute { async ->
copy(threePidInvites = async) copy(threePidInvites = async)
} }

View File

@ -28,6 +28,8 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap import org.matrix.android.sdk.rx.unwrap
@ -64,7 +66,7 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor(
} }
private fun observeSummary() { private fun observeSummary() {
room.rx().liveRoomSummary() room.flow().liveRoomSummary()
.unwrap() .unwrap()
.execute { async -> .execute { async ->
copy(roomSummary = async) copy(roomSummary = async)

View File

@ -16,7 +16,6 @@
package im.vector.app.features.roomprofile.uploads package im.vector.app.features.roomprofile.uploads
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -25,15 +24,15 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.unwrap import org.matrix.android.sdk.flow.unwrap
class RoomUploadsViewModel @AssistedInject constructor( class RoomUploadsViewModel @AssistedInject constructor(
@Assisted initialState: RoomUploadsViewState, @Assisted initialState: RoomUploadsViewState,
@ -66,7 +65,7 @@ class RoomUploadsViewModel @AssistedInject constructor(
} }
private fun observeRoomSummary() { private fun observeRoomSummary() {
room.rx().liveRoomSummary() room.flow().liveRoomSummary()
.unwrap() .unwrap()
.execute { async -> .execute { async ->
copy(roomSummary = async) copy(roomSummary = async)

View File

@ -15,7 +15,6 @@
*/ */
package im.vector.app.features.settings.crosssigning package im.vector.app.features.settings.crosssigning
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
@ -28,8 +27,8 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
@ -38,14 +37,11 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
@ -59,26 +55,26 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
) : VectorViewModel<CrossSigningSettingsViewState, CrossSigningSettingsAction, CrossSigningSettingsViewEvents>(initialState) { ) : VectorViewModel<CrossSigningSettingsViewState, CrossSigningSettingsAction, CrossSigningSettingsViewEvents>(initialState) {
init { init {
Observable.combineLatest<List<DeviceInfo>, Optional<MXCrossSigningInfo>, Pair<List<DeviceInfo>, Optional<MXCrossSigningInfo>>>( combine(
session.rx().liveMyDevicesInfo(), session.flow().liveMyDevicesInfo(),
session.rx().liveCrossSigningInfo(session.myUserId), session.flow().liveCrossSigningInfo(session.myUserId)
{ myDevicesInfo, mxCrossSigningInfo ->
myDevicesInfo to mxCrossSigningInfo
}
) )
.execute { data -> { myDevicesInfo, mxCrossSigningInfo ->
val crossSigningKeys = data.invoke()?.second?.getOrNull() myDevicesInfo to mxCrossSigningInfo
val xSigningIsEnableInAccount = crossSigningKeys != null }
val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified() .execute { data ->
val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign() val crossSigningKeys = data.invoke()?.second?.getOrNull()
val xSigningIsEnableInAccount = crossSigningKeys != null
val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified()
val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign()
copy( copy(
crossSigningInfo = crossSigningKeys, crossSigningInfo = crossSigningKeys,
xSigningIsEnableInAccount = xSigningIsEnableInAccount, xSigningIsEnableInAccount = xSigningIsEnableInAccount,
xSigningKeysAreTrusted = xSigningKeysAreTrusted, xSigningKeysAreTrusted = xSigningKeysAreTrusted,
xSigningKeyCanSign = xSigningKeyCanSign xSigningKeyCanSign = xSigningKeyCanSign
) )
} }
} }
var uiaContinuation: Continuation<UIABaseAuth>? = null var uiaContinuation: Continuation<UIABaseAuth>? = null
@ -126,7 +122,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
} }
Unit Unit
} }
is CrossSigningSettingsAction.SsoAuthDone -> { is CrossSigningSettingsAction.SsoAuthDone -> {
Timber.d("## UIA - FallBack success") Timber.d("## UIA - FallBack success")
if (pendingAuth != null) { if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!) uiaContinuation?.resume(pendingAuth!!)
@ -134,7 +130,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
uiaContinuation?.resumeWithException(IllegalArgumentException()) uiaContinuation?.resumeWithException(IllegalArgumentException())
} }
} }
is CrossSigningSettingsAction.PasswordAuthDone -> { is CrossSigningSettingsAction.PasswordAuthDone -> {
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
uiaContinuation?.resume( uiaContinuation?.resume(
UserPasswordAuth( UserPasswordAuth(
@ -144,7 +140,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
) )
) )
} }
CrossSigningSettingsAction.ReAuthCancelled -> { CrossSigningSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled") Timber.d("## UIA - Reauth cancelled")
_viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView) _viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView)
uiaContinuation?.resumeWithException(Exception()) uiaContinuation?.resumeWithException(Exception())

View File

@ -25,7 +25,9 @@ import dagger.assisted.AssistedFactory
import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
@ -48,7 +50,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
isRecoverySetup = session.sharedSecretStorageService.isRecoverySetup() isRecoverySetup = session.sharedSecretStorageService.isRecoverySetup()
) )
} }
session.rx().liveCrossSigningInfo(session.myUserId) session.flow().liveCrossSigningInfo(session.myUserId)
.execute { .execute {
copy( copy(
hasAccountCrossSigning = it.invoke()?.getOrNull() != null, hasAccountCrossSigning = it.invoke()?.getOrNull() != null,
@ -56,7 +58,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
) )
} }
session.rx().liveUserCryptoDevices(session.myUserId) session.flow().liveUserCryptoDevices(session.myUserId)
.map { list -> .map { list ->
list.firstOrNull { it.deviceId == deviceId } list.firstOrNull { it.deviceId == deviceId }
} }
@ -67,7 +69,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
) )
} }
session.rx().liveUserCryptoDevices(session.myUserId) session.flow().liveUserCryptoDevices(session.myUserId)
.map { it.size } .map { it.size }
.execute { .execute {
copy( copy(
@ -79,7 +81,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
copy(deviceInfo = Loading()) copy(deviceInfo = Loading())
} }
session.rx().liveMyDevicesInfo() session.flow().liveMyDevicesInfo()
.map { devices -> .map { devices ->
devices.firstOrNull { it.deviceId == deviceId } ?: DeviceInfo(deviceId = deviceId) devices.firstOrNull { it.deviceId == deviceId } ?: DeviceInfo(deviceId = deviceId)
} }

View File

@ -16,7 +16,6 @@
package im.vector.app.features.settings.devices package im.vector.app.features.settings.devices
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -34,31 +33,36 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
@ -118,18 +122,18 @@ class DevicesViewModel @AssistedInject constructor(
) )
} }
Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, List<DeviceFullInfo>>( combine(
session.rx().liveUserCryptoDevices(session.myUserId), session.flow().liveUserCryptoDevices(session.myUserId),
session.rx().liveMyDevicesInfo(), session.flow().liveMyDevicesInfo()
{ cryptoList, infoList ->
infoList
.sortedByDescending { it.lastSeenTs }
.map { deviceInfo ->
val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }
DeviceFullInfo(deviceInfo, cryptoDeviceInfo)
}
}
) )
{ cryptoList, infoList ->
infoList
.sortedByDescending { it.lastSeenTs }
.map { deviceInfo ->
val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }
DeviceFullInfo(deviceInfo, cryptoDeviceInfo)
}
}
.distinctUntilChanged() .distinctUntilChanged()
.execute { async -> .execute { async ->
copy( copy(
@ -137,7 +141,7 @@ class DevicesViewModel @AssistedInject constructor(
) )
} }
session.rx().liveCrossSigningInfo(session.myUserId) session.flow().liveCrossSigningInfo(session.myUserId)
.execute { .execute {
copy( copy(
hasAccountCrossSigning = it.invoke()?.getOrNull() != null, hasAccountCrossSigning = it.invoke()?.getOrNull() != null,
@ -146,24 +150,24 @@ class DevicesViewModel @AssistedInject constructor(
} }
session.cryptoService().verificationService().addListener(this) session.cryptoService().verificationService().addListener(this)
// session.rx().liveMyDeviceInfo() // session.flow().liveMyDeviceInfo()
// .execute { // .execute {
// copy( // copy(
// devices = it // devices = it
// ) // )
// } // }
session.rx().liveUserCryptoDevices(session.myUserId) session.flow().liveUserCryptoDevices(session.myUserId)
.map { it.size } .map { it.size }
.distinctUntilChanged() .distinctUntilChanged()
.throttleLast(5_000, TimeUnit.MILLISECONDS) .sample(5_000)
.subscribe { .onEach {
// If we have a new crypto device change, we might want to trigger refresh of device info // If we have a new crypto device change, we might want to trigger refresh of device info
session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) session.cryptoService().fetchDevicesList(NoOpMatrixCallback())
} }
.disposeOnClear() .launchIn(viewModelScope)
// session.rx().liveUserCryptoDevices(session.myUserId) // session.flow().liveUserCryptoDevices(session.myUserId)
// .execute { // .execute {
// copy( // copy(
// cryptoDevices = it // cryptoDevices = it

View File

@ -16,7 +16,6 @@
package im.vector.app.features.settings.threepids package im.vector.app.features.settings.threepids
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -33,15 +32,15 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.ReadOnceTrue import im.vector.app.core.utils.ReadOnceTrue
import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.auth.ReAuthActivity
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
@ -102,7 +101,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
} }
private fun observeThreePids() { private fun observeThreePids() {
session.rx() session.flow()
.liveThreePIds(true) .liveThreePIds(true)
.execute { .execute {
copy( copy(
@ -112,7 +111,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
} }
private fun observePendingThreePids() { private fun observePendingThreePids() {
session.rx() session.flow()
.livePendingThreePIds() .livePendingThreePIds()
.execute { .execute {
copy( copy(
@ -131,13 +130,13 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
override fun handle(action: ThreePidsSettingsAction) { override fun handle(action: ThreePidsSettingsAction) {
when (action) { when (action) {
is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action) is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action)
is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action) is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action)
is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action) is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action)
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action) is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action) is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action) is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action)
ThreePidsSettingsAction.SsoAuthDone -> { ThreePidsSettingsAction.SsoAuthDone -> {
Timber.d("## UIA - FallBack success") Timber.d("## UIA - FallBack success")
if (pendingAuth != null) { if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!) uiaContinuation?.resume(pendingAuth!!)
@ -155,7 +154,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
) )
) )
} }
ThreePidsSettingsAction.ReAuthCancelled -> { ThreePidsSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled") Timber.d("## UIA - Reauth cancelled")
uiaContinuation?.resumeWithException(Exception()) uiaContinuation?.resumeWithException(Exception())
uiaContinuation = null uiaContinuation = null

View File

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -68,7 +69,7 @@ class IncomingShareViewModel @AssistedInject constructor(
memberships = listOf(Membership.JOIN) memberships = listOf(Membership.JOIN)
} }
session session
.rx().liveRoomSummaries(queryParams) .flow().liveRoomSummaries(queryParams)
.execute { .execute {
copy(roomSummaries = it) copy(roomSummaries = it)
} }

View File

@ -42,6 +42,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
@ -77,7 +78,7 @@ class SpaceMenuViewModel @AssistedInject constructor(
session.getRoom(initialState.spaceId)?.let { room -> session.getRoom(initialState.spaceId)?.let { room ->
room.rx().liveRoomSummary().subscribe { room.flow().liveRoomSummary().onEach {
it.getOrNull()?.let { it.getOrNull()?.let {
if (it.membership == Membership.LEAVE) { if (it.membership == Membership.LEAVE) {
setState { copy(leavingState = Success(Unit)) } setState { copy(leavingState = Success(Unit)) }
@ -87,7 +88,7 @@ class SpaceMenuViewModel @AssistedInject constructor(
} }
} }
} }
}.disposeOnClear() }.launchIn(viewModelScope)
PowerLevelsFlowFactory(room) PowerLevelsFlowFactory(room)
.createFlow() .createFlow()

View File

@ -16,7 +16,6 @@
package im.vector.app.features.spaces.leave package im.vector.app.features.spaces.leave
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -31,6 +30,8 @@ import dagger.assisted.AssistedInject
import im.vector.app.AppStateHandler import im.vector.app.AppStateHandler
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.internal.toImmutableList import okhttp3.internal.toImmutableList
import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.ActiveSpaceFilter
@ -38,7 +39,8 @@ import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
import timber.log.Timber import timber.log.Timber
class SpaceLeaveAdvancedViewModel @AssistedInject constructor( class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
@ -95,17 +97,17 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
val spaceSummary = session.getRoomSummary(initialState.spaceId) val spaceSummary = session.getRoomSummary(initialState.spaceId)
setState { copy(spaceSummary = spaceSummary) } setState { copy(spaceSummary = spaceSummary) }
session.getRoom(initialState.spaceId)?.let { room -> session.getRoom(initialState.spaceId)?.let { room ->
room.rx().liveRoomSummary().subscribe { room.flow().liveRoomSummary()
it.getOrNull()?.let { .unwrap()
if (it.membership == Membership.LEAVE) { .onEach {
setState { copy(leaveState = Success(Unit)) } if (it.membership == Membership.LEAVE) {
if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) { setState { copy(leaveState = Success(Unit)) }
// switch to home? if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) {
appStateHandler.setCurrentSpace(null, session) // switch to home?
appStateHandler.setCurrentSpace(null, session)
}
} }
} }.launchIn(viewModelScope)
}
}
} }
viewModelScope.launch { viewModelScope.launch {

View File

@ -17,7 +17,6 @@
package im.vector.app.features.widgets package im.vector.app.features.widgets
import android.net.Uri import android.net.Uri
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -26,11 +25,12 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.widgets.permissions.WidgetPermissionsHelper import im.vector.app.features.widgets.permissions.WidgetPermissionsHelper
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -41,9 +41,10 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerS
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure
import org.matrix.android.sdk.rx.mapOptional import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.mapOptional
import org.matrix.android.sdk.flow.unwrap
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap
import timber.log.Timber import timber.log.Timber
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
@ -118,16 +119,15 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
if (room == null) { if (room == null) {
return return
} }
room.rx().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) room.flow().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
.mapOptional { it.content.toModel<PowerLevelsContent>() } .mapOptional { it.content.toModel<PowerLevelsContent>() }
.unwrap() .unwrap()
.map { .map {
PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, null) PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, null)
} }
.subscribe { .setOnEach {
setState { copy(canManageWidgets = it) } copy(canManageWidgets = it)
} }
.disposeOnClear()
} }
private fun observeWidgetIfNeeded() { private fun observeWidgetIfNeeded() {

View File

@ -25,27 +25,23 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import io.reactivex.Observable import kotlinx.coroutines.flow.MutableSharedFlow
import io.reactivex.functions.Function4 import kotlinx.coroutines.flow.combine
import io.reactivex.subjects.PublishSubject import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.sample
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.rx.rx
import java.util.concurrent.TimeUnit
data class ServerBackupStatusViewState( data class ServerBackupStatusViewState(
val bannerState: Async<BannerState> = Uninitialized val bannerState: Async<BannerState> = Uninitialized
@ -91,43 +87,38 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
val keysExportedToFile = MutableLiveData<Boolean>() val keysExportedToFile = MutableLiveData<Boolean>()
val keysBackupState = MutableLiveData<KeysBackupState>() val keysBackupState = MutableLiveData<KeysBackupState>()
private val keyBackupPublishSubject: PublishSubject<KeysBackupState> = PublishSubject.create() private val keyBackupFlow = MutableSharedFlow<KeysBackupState>(0)
init { init {
session.cryptoService().keysBackupService().addListener(this) session.cryptoService().keysBackupService().addListener(this)
keysBackupState.value = session.cryptoService().keysBackupService().state keysBackupState.value = session.cryptoService().keysBackupService().state
val liveUserAccountData = session.flow().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME))
Observable.combineLatest<List<UserAccountDataEvent>, Optional<MXCrossSigningInfo>, KeysBackupState, Optional<PrivateKeysInfo>, BannerState>( val liveCrossSigningInfo = session.flow().liveCrossSigningInfo(session.myUserId)
session.rx().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)), val liveCrossSigningPrivateKeys = session.flow().liveCrossSigningPrivateKeys()
session.rx().liveCrossSigningInfo(session.myUserId), combine(liveUserAccountData, liveCrossSigningInfo, keyBackupFlow, liveCrossSigningPrivateKeys) { _, crossSigningInfo, keyBackupState, pInfo ->
keyBackupPublishSubject, // first check if 4S is already setup
session.rx().liveCrossSigningPrivateKeys(), if (session.sharedSecretStorageService.isRecoverySetup()) {
Function4 { _, crossSigningInfo, keyBackupState, pInfo -> // 4S is already setup sp we should not display anything
// first check if 4S is already setup return@combine when (keyBackupState) {
if (session.sharedSecretStorageService.isRecoverySetup()) { KeysBackupState.BackingUp -> BannerState.BackingUp
// 4S is already setup sp we should not display anything else -> BannerState.Hidden
return@Function4 when (keyBackupState) {
KeysBackupState.BackingUp -> BannerState.BackingUp
else -> BannerState.Hidden
}
}
// So recovery is not setup
// Check if cross signing is enabled and local secrets known
if (
crossSigningInfo.getOrNull() == null
|| (crossSigningInfo.getOrNull()?.isTrusted() == true
&& pInfo.getOrNull()?.allKnown().orFalse())
) {
// So 4S is not setup and we have local secrets,
return@Function4 BannerState.Setup(numberOfKeys = getNumberOfKeysToBackup())
}
BannerState.Hidden
} }
) }
.throttleLast(1000, TimeUnit.MILLISECONDS) // we don't want to flicker or catch transient states
// So recovery is not setup
// Check if cross signing is enabled and local secrets known
if (
crossSigningInfo.getOrNull() == null
|| (crossSigningInfo.getOrNull()?.isTrusted() == true
&& pInfo.getOrNull()?.allKnown().orFalse())
) {
// So 4S is not setup and we have local secrets,
return@combine BannerState.Setup(numberOfKeys = getNumberOfKeysToBackup())
}
BannerState.Hidden
}
.sample(1000) // we don't want to flicker or catch transient states
.distinctUntilChanged() .distinctUntilChanged()
.execute { async -> .execute { async ->
copy( copy(
@ -135,7 +126,7 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
) )
} }
keyBackupPublishSubject.onNext(session.cryptoService().keysBackupService().state) keyBackupFlow.tryEmit(session.cryptoService().keysBackupService().state)
} }
/** /**
@ -165,7 +156,7 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
} }
override fun onStateChange(newState: KeysBackupState) { override fun onStateChange(newState: KeysBackupState) {
keyBackupPublishSubject.onNext(session.cryptoService().keysBackupService().state) keyBackupFlow.tryEmit(session.cryptoService().keysBackupService().state)
keysBackupState.value = newState keysBackupState.value = newState
} }

View File

@ -17,7 +17,6 @@
package im.vector.app.features.workers.signout package im.vector.app.features.workers.signout
import android.net.Uri import android.net.Uri
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -35,6 +34,8 @@ import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.crypto.keys.KeysExporter import im.vector.app.features.crypto.keys.KeysExporter
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
@ -42,7 +43,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_S
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
data class SignoutCheckViewState( data class SignoutCheckViewState(
@ -97,7 +98,7 @@ class SignoutCheckViewModel @AssistedInject constructor(
) )
} }
session.rx().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)) session.flow().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME))
.map { .map {
session.sharedSecretStorageService.isRecoverySetup() session.sharedSecretStorageService.isRecoverySetup()
} }