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
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MavericksViewModelFactory
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.roomSummaryQueryParams
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.rx
import timber.log.Timber
@ -95,7 +95,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
updateShowDialPadTab()
observeDataStore()
callManager.addProtocolsCheckerListener(this)
session.rx().liveUser(session.myUserId).execute {
session.flow().liveUser(session.myUserId).execute {
copy(
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.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction
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.extensions.orFalse
import org.matrix.android.sdk.api.session.Session
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.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.store.PrivateKeysInfo
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import java.util.concurrent.TimeUnit
data class UnknownDevicesState(
val myMatrixItem: MatrixItem.UserItem? = null,
@ -98,31 +98,31 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
}
)
Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, Optional<PrivateKeysInfo>, List<DeviceDetectionInfo>>(
session.rx().liveUserCryptoDevices(session.myUserId),
session.rx().liveMyDevicesInfo(),
session.rx().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
)
}
}
combine(
session.flow().liveUserCryptoDevices(session.myUserId),
session.flow().liveMyDevicesInfo(),
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
)
}
}
.distinctUntilChanged()
.execute { async ->
// 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()
.throttleLast(5_000, TimeUnit.MILLISECONDS)
.subscribe {
.sample(5_000)
.onEach {
// If we have a new crypto device change, we might want to trigger refresh of device info
session.cryptoService().fetchDevicesList(NoOpMatrixCallback())
}
.disposeOnClear()
.launchIn(viewModelScope)
// trigger a refresh of lastSeen / last Ip
session.cryptoService().fetchDevicesList(NoOpMatrixCallback())

View File

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

View File

@ -25,20 +25,17 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.R
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.features.powerlevel.PowerLevelsFlowFactory
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
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.members.roomMemberQueryParams
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.powerlevels.PowerLevelsHelper
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.flow.flow
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,
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 {
Pair(
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 {
copy(userMXCrossSigningInfo = it.invoke()?.getOrNull())
}
}
private fun observeIgnoredState() {
session.rx().liveIgnoredUsers()
session.flow().liveIgnoredUsers()
.map { ignored ->
ignored.find {
it.userId == initialState.userId
@ -252,7 +245,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
val queryParams = roomMemberQueryParams {
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
}
room.rx().liveRoomMembers(queryParams)
room.flow().liveRoomMembers(queryParams)
.map { it.firstOrNull().toOptional() }
.unwrap()
.execute {
@ -312,7 +305,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
roomSummaryLive.execute {
copy(isRoomEncrypted = it.invoke()?.isEncrypted == true)
}
roomSummaryLive.combine(powerLevelsContentLive){roomSummary, powerLevelsContent ->
roomSummaryLive.combine(powerLevelsContentLive) { roomSummary, powerLevelsContent ->
val roomName = roomSummary.toMatrixItem().getBestName()
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
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.util.MatrixItem
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.rx.rx
@ -55,14 +56,14 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva
}
init {
session.rx().liveUserCryptoDevices(args.userId)
session.flow().liveUserCryptoDevices(args.userId)
.execute {
copy(cryptoDevices = it).also {
refreshSelectedId()
}
}
session.rx().liveCrossSigningInfo(args.userId)
session.flow().liveCrossSigningInfo(args.userId)
.execute {
copy(memberCrossSigningKey = it.invoke()?.getOrNull())
}

View File

@ -131,7 +131,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo
}
private fun observeRoomSummary() {
room.rx().liveRoomSummary()
room.flow().liveRoomSummary()
.unwrap()
.execute { async ->
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.RoomMemberSummary
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.unwrap
@ -54,15 +56,14 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia
private val room = session.getRoom(initialState.roomId)!!
init {
val rxRoom = room.rx()
room.rx().liveRoomSummary()
room.flow().liveRoomSummary()
.unwrap()
.execute { async ->
copy(roomSummary = async)
}
rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
room.flow().liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
.execute {
copy(
bannedMemberSummaries = it

View File

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

View File

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

View File

@ -15,7 +15,6 @@
*/
package im.vector.app.features.settings.crosssigning
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MavericksViewModelFactory
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.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth
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.nextUncompletedStage
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.flow.flow
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.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.rx.rx
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
@ -59,26 +55,26 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
) : VectorViewModel<CrossSigningSettingsViewState, CrossSigningSettingsAction, CrossSigningSettingsViewEvents>(initialState) {
init {
Observable.combineLatest<List<DeviceInfo>, Optional<MXCrossSigningInfo>, Pair<List<DeviceInfo>, Optional<MXCrossSigningInfo>>>(
session.rx().liveMyDevicesInfo(),
session.rx().liveCrossSigningInfo(session.myUserId),
{ myDevicesInfo, mxCrossSigningInfo ->
myDevicesInfo to mxCrossSigningInfo
}
combine(
session.flow().liveMyDevicesInfo(),
session.flow().liveCrossSigningInfo(session.myUserId)
)
.execute { data ->
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()
{ myDevicesInfo, mxCrossSigningInfo ->
myDevicesInfo to mxCrossSigningInfo
}
.execute { data ->
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(
crossSigningInfo = crossSigningKeys,
xSigningIsEnableInAccount = xSigningIsEnableInAccount,
xSigningKeysAreTrusted = xSigningKeysAreTrusted,
xSigningKeyCanSign = xSigningKeyCanSign
)
}
copy(
crossSigningInfo = crossSigningKeys,
xSigningIsEnableInAccount = xSigningIsEnableInAccount,
xSigningKeysAreTrusted = xSigningKeysAreTrusted,
xSigningKeyCanSign = xSigningKeyCanSign
)
}
}
var uiaContinuation: Continuation<UIABaseAuth>? = null
@ -126,7 +122,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
}
Unit
}
is CrossSigningSettingsAction.SsoAuthDone -> {
is CrossSigningSettingsAction.SsoAuthDone -> {
Timber.d("## UIA - FallBack success")
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
@ -134,7 +130,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
uiaContinuation?.resumeWithException(IllegalArgumentException())
}
}
is CrossSigningSettingsAction.PasswordAuthDone -> {
is CrossSigningSettingsAction.PasswordAuthDone -> {
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
uiaContinuation?.resume(
UserPasswordAuth(
@ -144,7 +140,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
)
)
}
CrossSigningSettingsAction.ReAuthCancelled -> {
CrossSigningSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
_viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView)
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.EmptyViewEvents
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.flow.flow
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.rx.rx
@ -48,7 +50,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
isRecoverySetup = session.sharedSecretStorageService.isRecoverySetup()
)
}
session.rx().liveCrossSigningInfo(session.myUserId)
session.flow().liveCrossSigningInfo(session.myUserId)
.execute {
copy(
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 ->
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 }
.execute {
copy(
@ -79,7 +81,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
copy(deviceInfo = Loading())
}
session.rx().liveMyDevicesInfo()
session.flow().liveMyDevicesInfo()
.map { devices ->
devices.firstOrNull { it.deviceId == deviceId } ?: DeviceInfo(deviceId = deviceId)
}

View File

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

View File

@ -16,7 +16,6 @@
package im.vector.app.features.settings.threepids
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail
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.features.auth.ReAuthActivity
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.UserPasswordAuth
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.session.Session
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.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 kotlin.coroutines.Continuation
import kotlin.coroutines.resume
@ -102,7 +101,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
}
private fun observeThreePids() {
session.rx()
session.flow()
.liveThreePIds(true)
.execute {
copy(
@ -112,7 +111,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
}
private fun observePendingThreePids() {
session.rx()
session.flow()
.livePendingThreePIds()
.execute {
copy(
@ -131,13 +130,13 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
override fun handle(action: ThreePidsSettingsAction) {
when (action) {
is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action)
is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action)
is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action)
is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action)
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action)
ThreePidsSettingsAction.SsoAuthDone -> {
is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action)
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action)
ThreePidsSettingsAction.SsoAuthDone -> {
Timber.d("## UIA - FallBack success")
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
@ -155,7 +154,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
)
)
}
ThreePidsSettingsAction.ReAuthCancelled -> {
ThreePidsSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
uiaContinuation?.resumeWithException(Exception())
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.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.rx
import java.util.concurrent.TimeUnit
@ -68,7 +69,7 @@ class IncomingShareViewModel @AssistedInject constructor(
memberships = listOf(Membership.JOIN)
}
session
.rx().liveRoomSummaries(queryParams)
.flow().liveRoomSummaries(queryParams)
.execute {
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.Role
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
@ -77,7 +78,7 @@ class SpaceMenuViewModel @AssistedInject constructor(
session.getRoom(initialState.spaceId)?.let { room ->
room.rx().liveRoomSummary().subscribe {
room.flow().liveRoomSummary().onEach {
it.getOrNull()?.let {
if (it.membership == Membership.LEAVE) {
setState { copy(leavingState = Success(Unit)) }
@ -87,7 +88,7 @@ class SpaceMenuViewModel @AssistedInject constructor(
}
}
}
}.disposeOnClear()
}.launchIn(viewModelScope)
PowerLevelsFlowFactory(room)
.createFlow()

View File

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

View File

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

View File

@ -25,27 +25,23 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import io.reactivex.Observable
import io.reactivex.functions.Function4
import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.sample
import org.matrix.android.sdk.api.extensions.orFalse
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.MXCrossSigningInfo
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.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.rx.rx
import java.util.concurrent.TimeUnit
import org.matrix.android.sdk.flow.flow
data class ServerBackupStatusViewState(
val bannerState: Async<BannerState> = Uninitialized
@ -91,43 +87,38 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
val keysExportedToFile = MutableLiveData<Boolean>()
val keysBackupState = MutableLiveData<KeysBackupState>()
private val keyBackupPublishSubject: PublishSubject<KeysBackupState> = PublishSubject.create()
private val keyBackupFlow = MutableSharedFlow<KeysBackupState>(0)
init {
session.cryptoService().keysBackupService().addListener(this)
keysBackupState.value = session.cryptoService().keysBackupService().state
Observable.combineLatest<List<UserAccountDataEvent>, Optional<MXCrossSigningInfo>, KeysBackupState, Optional<PrivateKeysInfo>, BannerState>(
session.rx().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)),
session.rx().liveCrossSigningInfo(session.myUserId),
keyBackupPublishSubject,
session.rx().liveCrossSigningPrivateKeys(),
Function4 { _, crossSigningInfo, keyBackupState, pInfo ->
// first check if 4S is already setup
if (session.sharedSecretStorageService.isRecoverySetup()) {
// 4S is already setup sp we should not display anything
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
val liveUserAccountData = session.flow().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME))
val liveCrossSigningInfo = session.flow().liveCrossSigningInfo(session.myUserId)
val liveCrossSigningPrivateKeys = session.flow().liveCrossSigningPrivateKeys()
combine(liveUserAccountData, liveCrossSigningInfo, keyBackupFlow, liveCrossSigningPrivateKeys) { _, crossSigningInfo, keyBackupState, pInfo ->
// first check if 4S is already setup
if (session.sharedSecretStorageService.isRecoverySetup()) {
// 4S is already setup sp we should not display anything
return@combine when (keyBackupState) {
KeysBackupState.BackingUp -> BannerState.BackingUp
else -> 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()
.execute { async ->
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) {
keyBackupPublishSubject.onNext(session.cryptoService().keysBackupService().state)
keyBackupFlow.tryEmit(session.cryptoService().keysBackupService().state)
keysBackupState.value = newState
}

View File

@ -17,7 +17,6 @@
package im.vector.app.features.workers.signout
import android.net.Uri
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Async
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.VectorViewModelAction
import im.vector.app.features.crypto.keys.KeysExporter
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
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.keysbackup.KeysBackupState
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
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 {
session.sharedSecretStorageService.isRecoverySetup()
}