mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Mavericks 2: continue replacing Rx
This commit is contained in:
parent
f72a34ed08
commit
fadbb60f90
24 changed files with 417 additions and 355 deletions
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package im.vector.app.features.discovery
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
|
@ -25,17 +24,19 @@ 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.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceListener
|
||||
import org.matrix.android.sdk.api.session.identity.SharedState
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
|
||||
class DiscoverySettingsViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: DiscoverySettingsState,
|
||||
|
@ -84,12 +85,12 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun observeThreePids() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveThreePIds(true)
|
||||
.subscribe {
|
||||
.onEach {
|
||||
retrieveBinding(it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
|
|
@ -27,6 +27,7 @@ import android.view.MenuItem
|
|||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.Mavericks
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
@ -72,6 +73,7 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
|||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||
|
@ -288,26 +290,23 @@ class HomeActivity :
|
|||
}
|
||||
else -> deepLink
|
||||
}
|
||||
permalinkHandler.launch(
|
||||
context = this,
|
||||
deepLink = resolvedLink,
|
||||
navigationInterceptor = this,
|
||||
buildTask = true
|
||||
)
|
||||
// .delay(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { isHandled ->
|
||||
if (!isHandled) {
|
||||
val isMatrixToLink = deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE)
|
||||
|| deepLink.startsWith(MATRIX_TO_CUSTOM_SCHEME_URL_BASE)
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.dialog_title_error)
|
||||
.setMessage(if (isMatrixToLink) R.string.permalink_malformed else R.string.universal_link_malformed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
lifecycleScope.launch {
|
||||
val isHandled = permalinkHandler.launch(
|
||||
context = this@HomeActivity,
|
||||
deepLink = resolvedLink,
|
||||
navigationInterceptor = this@HomeActivity,
|
||||
buildTask = true
|
||||
)
|
||||
if (!isHandled) {
|
||||
val isMatrixToLink = deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE)
|
||||
|| deepLink.startsWith(MATRIX_TO_CUSTOM_SCHEME_URL_BASE)
|
||||
MaterialAlertDialogBuilder(this@HomeActivity)
|
||||
.setTitle(R.string.dialog_title_error)
|
||||
.setMessage(if (isMatrixToLink) R.string.permalink_malformed else R.string.universal_link_malformed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.home
|
||||
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Mavericks
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
|
@ -31,6 +32,8 @@ import im.vector.app.features.session.coroutineScope
|
|||
import im.vector.app.features.settings.VectorPreferences
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.auth.UIABaseAuth
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
|
@ -44,6 +47,7 @@ import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
|||
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.internal.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||
|
@ -100,9 +104,9 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||
.crossSigningService().allPrivateKeysKnown()
|
||||
|
||||
safeActiveSession
|
||||
.rx()
|
||||
.flow()
|
||||
.liveCrossSigningInfo(safeActiveSession.myUserId)
|
||||
.subscribe {
|
||||
.onEach {
|
||||
val isVerified = it.getOrNull()?.isTrusted() ?: false
|
||||
if (!isVerified && onceTrusted) {
|
||||
// cross signing keys have been reset
|
||||
|
@ -116,15 +120,15 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||
}
|
||||
onceTrusted = isVerified
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun observeInitialSync() {
|
||||
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
||||
|
||||
session.getSyncStatusLive()
|
||||
.asObservable()
|
||||
.subscribe { status ->
|
||||
.asFlow()
|
||||
.onEach { status ->
|
||||
when (status) {
|
||||
is SyncStatusService.Status.Progressing -> {
|
||||
// Schedule a check of the bootstrap when the init sync will be finished
|
||||
|
@ -145,7 +149,7 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.home
|
||||
|
||||
import androidx.lifecycle.asFlow
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
|
@ -37,6 +38,7 @@ import im.vector.app.features.ui.UiStateRepository
|
|||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
|
@ -48,7 +50,6 @@ 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
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
@ -182,25 +183,18 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||
}
|
||||
|
||||
private fun observeSyncState() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveSyncState()
|
||||
.subscribe { syncState ->
|
||||
setState {
|
||||
copy(syncState = syncState)
|
||||
}
|
||||
.setOnEach { syncState ->
|
||||
copy(syncState = syncState)
|
||||
}
|
||||
.disposeOnClear()
|
||||
|
||||
session.getSyncStatusLive()
|
||||
.asObservable()
|
||||
.subscribe {
|
||||
if (it is SyncStatusService.Status.IncrementalSyncStatus) {
|
||||
setState {
|
||||
copy(incrementalSyncStatus = it)
|
||||
}
|
||||
}
|
||||
.asFlow()
|
||||
.filterIsInstance<SyncStatusService.Status.IncrementalSyncStatus>()
|
||||
.setOnEach {
|
||||
copy(incrementalSyncStatus = it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeRoomGroupingMethod() {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.query.QueryStringValue
|
|||
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.flow.flow
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
|
||||
class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: BreadcrumbsViewState,
|
||||
|
@ -61,12 +62,11 @@ class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: B
|
|||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun observeBreadcrumbs() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveBreadcrumbs(roomSummaryQueryParams {
|
||||
displayName = QueryStringValue.NoCondition
|
||||
memberships = listOf(Membership.JOIN)
|
||||
})
|
||||
.observeOn(Schedulers.computation())
|
||||
.execute { asyncBreadcrumbs ->
|
||||
copy(asyncBreadcrumbs = asyncBreadcrumbs)
|
||||
}
|
||||
|
|
|
@ -1590,57 +1590,54 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// TimelineEventController.Callback ************************************************************
|
||||
// TimelineEventController.Callback ************************************************************
|
||||
|
||||
override fun onUrlClicked(url: String, title: String): Boolean {
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
// Same room?
|
||||
if (roomId == roomDetailArgs.roomId) {
|
||||
// Navigation to same room
|
||||
if (eventId == null) {
|
||||
showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room))
|
||||
} else {
|
||||
// Highlight and scroll to this event
|
||||
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true))
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
val isManaged = permalinkHandler
|
||||
.launch(requireActivity(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
// Same room?
|
||||
if (roomId == roomDetailArgs.roomId) {
|
||||
// Navigation to same room
|
||||
if (eventId == null) {
|
||||
showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room))
|
||||
} else {
|
||||
// Highlight and scroll to this event
|
||||
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true))
|
||||
}
|
||||
return true
|
||||
}
|
||||
// Not handled
|
||||
return false
|
||||
}
|
||||
|
||||
override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean {
|
||||
openRoomMemberProfile(userId)
|
||||
return true
|
||||
}
|
||||
// Not handled
|
||||
return false
|
||||
}
|
||||
|
||||
override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean {
|
||||
openRoomMemberProfile(userId)
|
||||
return true
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { managed ->
|
||||
if (!managed) {
|
||||
if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) {
|
||||
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive)
|
||||
.setTitle(R.string.external_link_confirmation_title)
|
||||
.setMessage(
|
||||
getString(R.string.external_link_confirmation_message, title, url)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
.colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!isManaged) {
|
||||
if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) {
|
||||
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive)
|
||||
.setTitle(R.string.external_link_confirmation_title)
|
||||
.setMessage(
|
||||
getString(R.string.external_link_confirmation_message, title, url)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
.colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
}
|
||||
// In fact it is always managed
|
||||
return true
|
||||
}
|
||||
|
@ -1799,15 +1796,15 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onRoomCreateLinkClicked(url: String) {
|
||||
permalinkHandler
|
||||
.launch(requireContext(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
.subscribe()
|
||||
.disposeOnDestroyView()
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||
permalinkHandler
|
||||
.launch(requireContext(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReadReceiptsClicked(readReceipts: List<ReadReceiptData>) {
|
||||
|
|
|
@ -18,10 +18,14 @@ package im.vector.app.features.invite
|
|||
|
||||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
|
@ -31,9 +35,8 @@ import org.matrix.android.sdk.api.session.room.Room
|
|||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||
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 timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -50,7 +53,7 @@ class InvitesAcceptor @Inject constructor(
|
|||
|
||||
private lateinit var activeSessionDisposable: Disposable
|
||||
private val shouldRejectRoomIds = mutableSetOf<String>()
|
||||
private val invitedRoomDisposables = HashMap<String, Disposable>()
|
||||
private val activeSessionIds = mutableSetOf<String>()
|
||||
private val semaphore = Semaphore(1)
|
||||
|
||||
fun initialize() {
|
||||
|
@ -71,34 +74,32 @@ class InvitesAcceptor @Inject constructor(
|
|||
if (!autoAcceptInvites.isEnabled) {
|
||||
return
|
||||
}
|
||||
if (invitedRoomDisposables.containsKey(session.sessionId)) {
|
||||
if (activeSessionIds.contains(session.sessionId)) {
|
||||
return
|
||||
}
|
||||
activeSessionIds.add(session.sessionId)
|
||||
session.addListener(this)
|
||||
val roomQueryParams = roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.INVITE)
|
||||
}
|
||||
val rxSession = session.rx()
|
||||
Observable
|
||||
.combineLatest(
|
||||
rxSession.liveRoomSummaries(roomQueryParams),
|
||||
rxSession.liveRoomChangeMembershipState().debounce(1, TimeUnit.SECONDS),
|
||||
{ invitedRooms, _ -> invitedRooms.map { it.roomId } }
|
||||
)
|
||||
val flowSession = session.flow()
|
||||
combine(
|
||||
flowSession.liveRoomSummaries(roomQueryParams),
|
||||
flowSession.liveRoomChangeMembershipState().debounce(1000)
|
||||
) { invitedRooms, _ -> invitedRooms.map { it.roomId } }
|
||||
.filter { it.isNotEmpty() }
|
||||
.subscribe { invitedRoomIds ->
|
||||
session.coroutineScope.launch {
|
||||
semaphore.withPermit {
|
||||
Timber.v("Invited roomIds: $invitedRoomIds")
|
||||
for (roomId in invitedRoomIds) {
|
||||
async { session.joinRoomSafely(roomId) }.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.also {
|
||||
invitedRoomDisposables[session.sessionId] = it
|
||||
}
|
||||
.onEach { invitedRoomIds ->
|
||||
joinInvitedRooms(session, invitedRoomIds)
|
||||
}.launchIn(session.coroutineScope)
|
||||
}
|
||||
|
||||
private suspend fun joinInvitedRooms(session: Session, invitedRoomIds: List<String>) = coroutineScope {
|
||||
semaphore.withPermit {
|
||||
Timber.v("Invited roomIds: $invitedRoomIds")
|
||||
for (roomId in invitedRoomIds) {
|
||||
async { session.joinRoomSafely(roomId) }.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Session.joinRoomSafely(roomId: String) {
|
||||
|
@ -138,6 +139,6 @@ class InvitesAcceptor @Inject constructor(
|
|||
|
||||
override fun onSessionStopped(session: Session) {
|
||||
session.removeListener(this)
|
||||
invitedRoomDisposables.remove(session.sessionId)?.dispose()
|
||||
activeSessionIds.remove(session.sessionId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||
|
@ -34,80 +34,71 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermalinkHandler @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val navigator: Navigator) {
|
||||
|
||||
fun launch(
|
||||
suspend fun launch(
|
||||
context: Context,
|
||||
deepLink: String?,
|
||||
navigationInterceptor: NavigationInterceptor? = null,
|
||||
buildTask: Boolean = false
|
||||
): Single<Boolean> {
|
||||
): Boolean {
|
||||
val uri = deepLink?.let { Uri.parse(it) }
|
||||
return launch(context, uri, navigationInterceptor, buildTask)
|
||||
}
|
||||
|
||||
fun launch(
|
||||
suspend fun launch(
|
||||
context: Context,
|
||||
deepLink: Uri?,
|
||||
navigationInterceptor: NavigationInterceptor? = null,
|
||||
buildTask: Boolean = false
|
||||
): Single<Boolean> {
|
||||
): Boolean {
|
||||
if (deepLink == null || !isPermalinkSupported(context, deepLink.toString())) {
|
||||
return Single.just(false)
|
||||
return false
|
||||
}
|
||||
return Single
|
||||
.fromCallable {
|
||||
PermalinkParser.parse(deepLink)
|
||||
}
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.flatMap { permalinkData ->
|
||||
handlePermalink(permalinkData, deepLink, context, navigationInterceptor, buildTask)
|
||||
}
|
||||
.onErrorReturnItem(false)
|
||||
return tryOrNull {
|
||||
withContext(Dispatchers.Default) {
|
||||
val permalinkData = PermalinkParser.parse(deepLink)
|
||||
handlePermalink(permalinkData, deepLink, context, navigationInterceptor, buildTask)
|
||||
}
|
||||
} ?: false
|
||||
}
|
||||
|
||||
private fun handlePermalink(
|
||||
private suspend fun handlePermalink(
|
||||
permalinkData: PermalinkData,
|
||||
rawLink: Uri,
|
||||
context: Context,
|
||||
navigationInterceptor: NavigationInterceptor?,
|
||||
buildTask: Boolean
|
||||
): Single<Boolean> {
|
||||
): Boolean {
|
||||
return when (permalinkData) {
|
||||
is PermalinkData.RoomLink -> {
|
||||
permalinkData.getRoomId()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map {
|
||||
val roomId = it.getOrNull()
|
||||
if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink) != true) {
|
||||
openRoom(
|
||||
context = context,
|
||||
roomId = roomId,
|
||||
permalinkData = permalinkData,
|
||||
rawLink = rawLink,
|
||||
buildTask = buildTask
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
val roomId = permalinkData.getRoomId()
|
||||
if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink) != true) {
|
||||
openRoom(
|
||||
context = context,
|
||||
roomId = roomId,
|
||||
permalinkData = permalinkData,
|
||||
rawLink = rawLink,
|
||||
buildTask = buildTask
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
navigator.openGroupDetail(permalinkData.groupId, context, buildTask)
|
||||
Single.just(true)
|
||||
true
|
||||
}
|
||||
is PermalinkData.UserLink -> {
|
||||
if (navigationInterceptor?.navToMemberProfile(permalinkData.userId, rawLink) != true) {
|
||||
navigator.openRoomMemberProfile(userId = permalinkData.userId, roomId = null, context = context, buildTask = buildTask)
|
||||
}
|
||||
Single.just(true)
|
||||
true
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
Single.just(false)
|
||||
false
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink -> {
|
||||
val data = RoomPreviewData(
|
||||
|
@ -118,7 +109,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
|
|||
roomType = permalinkData.roomType
|
||||
)
|
||||
navigator.openRoomPreview(context, data)
|
||||
Single.just(true)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,15 +121,13 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
|
|||
}
|
||||
}
|
||||
|
||||
private fun PermalinkData.RoomLink.getRoomId(): Single<Optional<String>> {
|
||||
private suspend fun PermalinkData.RoomLink.getRoomId(): String? {
|
||||
val session = activeSessionHolder.getSafeActiveSession()
|
||||
return if (isRoomAlias && session != null) {
|
||||
session.rx()
|
||||
.getRoomIdByAlias(roomIdOrAlias, true)
|
||||
.map { it.getOrNull()?.roomId.toOptional() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
val roomIdByAlias = session.getRoomIdByAlias(roomIdOrAlias, true)
|
||||
roomIdByAlias.getOrNull()?.roomId
|
||||
} else {
|
||||
Single.just(Optional.from(roomIdOrAlias))
|
||||
roomIdOrAlias
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,16 +20,26 @@ import com.airbnb.mvrx.ActivityViewModelContext
|
|||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
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.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.subscribe
|
||||
import kotlinx.coroutines.flow.switchMap
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
|
@ -37,8 +47,8 @@ import org.matrix.android.sdk.api.session.room.Room
|
|||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
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
|
||||
|
||||
/**
|
||||
* This ViewModel observe a room summary and notify when the room is left
|
||||
|
@ -66,28 +76,31 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val roomIdObservable = BehaviorRelay.createDefault(Optional.from(initialState.roomId))
|
||||
private val roomIdFlow = MutableStateFlow(Optional.from(initialState.roomId))
|
||||
|
||||
init {
|
||||
observeRoomSummary()
|
||||
}
|
||||
|
||||
private fun observeRoomSummary() {
|
||||
roomIdObservable
|
||||
roomIdFlow
|
||||
.unwrap()
|
||||
.switchMap { roomId ->
|
||||
val room = session.getRoom(roomId) ?: return@switchMap Observable.just(Optional.empty<RequireActiveMembershipViewEvents.RoomLeft>())
|
||||
room.rx()
|
||||
.flatMapLatest { roomId ->
|
||||
val room = session.getRoom(roomId) ?: return@flatMapLatest flow{
|
||||
val emptyResult = Optional.empty<RequireActiveMembershipViewEvents.RoomLeft>()
|
||||
emit(emptyResult)
|
||||
}
|
||||
room.flow()
|
||||
.liveRoomSummary()
|
||||
.unwrap()
|
||||
.observeOn(Schedulers.computation())
|
||||
.flowOn(Dispatchers.Default)
|
||||
.map { mapToLeftViewEvent(room, it) }
|
||||
}
|
||||
.unwrap()
|
||||
.subscribe { event ->
|
||||
.onEach { event ->
|
||||
_viewEvents.post(event)
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun mapToLeftViewEvent(room: Room, roomSummary: RoomSummary): Optional<RequireActiveMembershipViewEvents.RoomLeft> {
|
||||
|
@ -128,7 +141,7 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
|
|||
setState {
|
||||
copy(roomId = action.roomId)
|
||||
}
|
||||
roomIdObservable.accept(Optional.from(action.roomId))
|
||||
roomIdFlow.tryEmit(Optional.from(action.roomId))
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.view.LayoutInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||
|
@ -37,6 +38,7 @@ import im.vector.app.databinding.FragmentPublicRoomsBinding
|
|||
import im.vector.app.features.permalink.NavigationInterceptor
|
||||
import im.vector.app.features.permalink.PermalinkHandler
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||
|
@ -125,20 +127,20 @@ class PublicRoomsFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onUnknownRoomClicked(roomIdOrAlias: String) {
|
||||
val permalink = session.permalinkService().createPermalink(roomIdOrAlias)
|
||||
permalinkHandler
|
||||
.launch(requireContext(), permalink, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
.subscribe { isSuccessful ->
|
||||
if (!isSuccessful) {
|
||||
requireContext().toast(R.string.room_error_not_found)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
val permalink = session.permalinkService().createPermalink(roomIdOrAlias)
|
||||
val isHandled = permalinkHandler
|
||||
.launch(requireContext(), permalink, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
if (!isHandled) {
|
||||
requireContext().toast(R.string.room_error_not_found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.roomdirectory
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
|
@ -31,6 +30,7 @@ import im.vector.app.core.platform.VectorViewModel
|
|||
import im.vector.app.features.settings.VectorPreferences
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -38,7 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomDirectoryViewModel @AssistedInject constructor(
|
||||
|
@ -80,28 +80,24 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
|||
memberships = listOf(Membership.JOIN)
|
||||
}
|
||||
session
|
||||
.rx()
|
||||
.flow()
|
||||
.liveRoomSummaries(queryParams)
|
||||
.subscribe { list ->
|
||||
val joinedRoomIds = list
|
||||
?.map { it.roomId }
|
||||
?.toSet()
|
||||
.orEmpty()
|
||||
|
||||
setState {
|
||||
copy(joinedRoomsIds = joinedRoomIds)
|
||||
}
|
||||
.map { roomSummaries ->
|
||||
roomSummaries
|
||||
.map { it.roomId }
|
||||
.toSet()
|
||||
}
|
||||
.setOnEach {
|
||||
copy(joinedRoomsIds = it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeMembershipChanges() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveRoomChangeMembershipState()
|
||||
.subscribe {
|
||||
setState { copy(changeMembershipStates = it) }
|
||||
.setOnEach {
|
||||
copy(changeMembershipStates = it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun handle(action: RoomDirectoryAction) {
|
||||
|
|
|
@ -30,6 +30,8 @@ import im.vector.app.core.platform.EmptyViewEvents
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.roomdirectory.JoinState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
|
@ -40,6 +42,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
|||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.peeking.PeekResult
|
||||
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
|
||||
|
||||
|
@ -165,9 +168,9 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
|
|||
excludeType = null
|
||||
}
|
||||
session
|
||||
.rx()
|
||||
.flow()
|
||||
.liveRoomSummaries(queryParams)
|
||||
.subscribe { list ->
|
||||
.onEach { list ->
|
||||
val isRoomJoined = list.any {
|
||||
it.membership == Membership.JOIN
|
||||
}
|
||||
|
@ -180,13 +183,13 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
|
|||
setState { copy(roomJoinState = JoinState.JOINED) }
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun observeMembershipChanges() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveRoomChangeMembershipState()
|
||||
.subscribe {
|
||||
.onEach {
|
||||
val changeMembership = it[initialState.roomId] ?: ChangeMembershipState.Unknown
|
||||
val joinState = when (changeMembership) {
|
||||
is ChangeMembershipState.Joining -> JoinState.JOINING
|
||||
|
@ -198,7 +201,7 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
|
|||
setState { copy(roomJoinState = joinState) }
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handle(action: RoomPreviewAction) {
|
||||
|
|
|
@ -40,10 +40,10 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.state.isPublic
|
||||
import org.matrix.android.sdk.rx.RxRoom
|
||||
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.FlowRoom
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
|
||||
class RoomProfileViewModel @AssistedInject constructor(
|
||||
@Assisted private val initialState: RoomProfileViewState,
|
||||
|
@ -69,15 +69,15 @@ class RoomProfileViewModel @AssistedInject constructor(
|
|||
private val room = session.getRoom(initialState.roomId)!!
|
||||
|
||||
init {
|
||||
val rxRoom = room.rx()
|
||||
observeRoomSummary(rxRoom)
|
||||
observeRoomCreateContent(rxRoom)
|
||||
observeBannedRoomMembers(rxRoom)
|
||||
val flowRoom = room.flow()
|
||||
observeRoomSummary(flowRoom)
|
||||
observeRoomCreateContent(flowRoom)
|
||||
observeBannedRoomMembers(flowRoom)
|
||||
observePermissions()
|
||||
}
|
||||
|
||||
private fun observeRoomCreateContent(rxRoom: RxRoom) {
|
||||
rxRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition)
|
||||
private fun observeRoomCreateContent(flowRoom: FlowRoom) {
|
||||
flowRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition)
|
||||
.mapOptional { it.content.toModel<RoomCreateContent>() }
|
||||
.unwrap()
|
||||
.execute { async ->
|
||||
|
@ -92,16 +92,16 @@ class RoomProfileViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummary(rxRoom: RxRoom) {
|
||||
rxRoom.liveRoomSummary()
|
||||
private fun observeRoomSummary(flowRoom: FlowRoom) {
|
||||
flowRoom.liveRoomSummary()
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(roomSummary = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeBannedRoomMembers(rxRoom: RxRoom) {
|
||||
rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
|
||||
private fun observeBannedRoomMembers(flowRoom: FlowRoom) {
|
||||
flowRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) })
|
||||
.execute {
|
||||
copy(bannedMembership = it)
|
||||
}
|
||||
|
|
|
@ -28,11 +28,10 @@ import im.vector.app.core.extensions.exhaustive
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Observable
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -47,7 +46,6 @@ import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
|||
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
|
||||
|
||||
class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
|
@ -259,61 +257,57 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
}
|
||||
|
||||
private fun saveSettings() = withState { state ->
|
||||
postLoading(true)
|
||||
|
||||
val operationList = mutableListOf<Completable>()
|
||||
val operationList = mutableListOf<suspend () -> Unit>()
|
||||
|
||||
val summary = state.roomSummary.invoke()
|
||||
|
||||
when (val avatarAction = state.avatarAction) {
|
||||
RoomSettingsViewState.AvatarAction.None -> Unit
|
||||
RoomSettingsViewState.AvatarAction.DeleteAvatar -> {
|
||||
operationList.add(room.rx().deleteAvatar())
|
||||
operationList.add { room.deleteAvatar() }
|
||||
}
|
||||
is RoomSettingsViewState.AvatarAction.UpdateAvatar -> {
|
||||
operationList.add(room.rx().updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName))
|
||||
operationList.add { room.updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName) }
|
||||
}
|
||||
}
|
||||
if (summary?.name != state.newName) {
|
||||
operationList.add(room.rx().updateName(state.newName ?: ""))
|
||||
operationList.add { room.updateName(state.newName ?: "") }
|
||||
}
|
||||
if (summary?.topic != state.newTopic) {
|
||||
operationList.add(room.rx().updateTopic(state.newTopic ?: ""))
|
||||
operationList.add { room.updateTopic(state.newTopic ?: "") }
|
||||
}
|
||||
|
||||
if (state.newHistoryVisibility != null) {
|
||||
operationList.add(room.rx().updateHistoryReadability(state.newHistoryVisibility))
|
||||
operationList.add { room.updateHistoryReadability(state.newHistoryVisibility) }
|
||||
}
|
||||
|
||||
if (state.newRoomJoinRules.hasChanged()) {
|
||||
operationList.add(room.rx().updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess))
|
||||
operationList.add { room.updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess) }
|
||||
}
|
||||
viewModelScope.launch {
|
||||
updateLoadingState(isLoading = true)
|
||||
try {
|
||||
for (operation in operationList) {
|
||||
operation.invoke()
|
||||
}
|
||||
setState {
|
||||
deletePendingAvatar(this)
|
||||
copy(
|
||||
avatarAction = RoomSettingsViewState.AvatarAction.None,
|
||||
newHistoryVisibility = null,
|
||||
newRoomJoinRules = RoomSettingsViewState.NewJoinRule()
|
||||
)
|
||||
}
|
||||
_viewEvents.post(RoomSettingsViewEvents.Success)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomSettingsViewEvents.Failure(failure))
|
||||
}finally {
|
||||
updateLoadingState(isLoading = false)
|
||||
}
|
||||
}
|
||||
|
||||
Observable
|
||||
.fromIterable(operationList)
|
||||
.concatMapCompletable { it }
|
||||
.subscribe(
|
||||
{
|
||||
postLoading(false)
|
||||
setState {
|
||||
deletePendingAvatar(this)
|
||||
copy(
|
||||
avatarAction = RoomSettingsViewState.AvatarAction.None,
|
||||
newHistoryVisibility = null,
|
||||
newRoomJoinRules = RoomSettingsViewState.NewJoinRule()
|
||||
)
|
||||
}
|
||||
_viewEvents.post(RoomSettingsViewEvents.Success)
|
||||
},
|
||||
{
|
||||
postLoading(false)
|
||||
_viewEvents.post(RoomSettingsViewEvents.Failure(it))
|
||||
}
|
||||
)
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun postLoading(isLoading: Boolean) {
|
||||
private fun updateLoadingState(isLoading: Boolean) {
|
||||
setState {
|
||||
copy(isLoading = isLoading)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_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.flow.flow
|
||||
import org.matrix.android.sdk.rx.SecretsSynchronisationInfo
|
||||
|
||||
data class SecretsSynchronisationInfo(
|
||||
val isBackupSetup: Boolean,
|
||||
val isCrossSigningEnabled: Boolean,
|
||||
val isCrossSigningTrusted: Boolean,
|
||||
val allPrivateKeysKnown: Boolean,
|
||||
val megolmBackupAvailable: Boolean,
|
||||
val megolmSecretKnown: Boolean,
|
||||
val isMegolmKeyIn4S: Boolean
|
||||
)
|
||||
|
||||
fun Session.liveSecretSynchronisationInfo(): Flow<SecretsSynchronisationInfo> {
|
||||
val sessionFlow = flow()
|
||||
return combine(
|
||||
sessionFlow.liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME)),
|
||||
sessionFlow.liveCrossSigningInfo(myUserId),
|
||||
sessionFlow.liveCrossSigningPrivateKeys()
|
||||
) { _, crossSigningInfo, pInfo ->
|
||||
// first check if 4S is already setup
|
||||
val is4SSetup = sharedSecretStorageService.isRecoverySetup()
|
||||
val isCrossSigningEnabled = crossSigningInfo.getOrNull() != null
|
||||
val isCrossSigningTrusted = crossSigningInfo.getOrNull()?.isTrusted() == true
|
||||
val allPrivateKeysKnown = pInfo.getOrNull()?.allKnown().orFalse()
|
||||
|
||||
val keysBackupService = cryptoService().keysBackupService()
|
||||
val currentBackupVersion = keysBackupService.currentBackupVersion
|
||||
val megolmBackupAvailable = currentBackupVersion != null
|
||||
val savedBackupKey = keysBackupService.getKeyBackupRecoveryKeyInfo()
|
||||
|
||||
val megolmKeyKnown = savedBackupKey?.version == currentBackupVersion
|
||||
SecretsSynchronisationInfo(
|
||||
isBackupSetup = is4SSetup,
|
||||
isCrossSigningEnabled = isCrossSigningEnabled,
|
||||
isCrossSigningTrusted = isCrossSigningTrusted,
|
||||
allPrivateKeysKnown = allPrivateKeysKnown,
|
||||
megolmBackupAvailable = megolmBackupAvailable,
|
||||
megolmSecretKnown = megolmKeyKnown,
|
||||
isMegolmKeyIn4S = sharedSecretStorageService.isMegolmKeyInBackup()
|
||||
)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
|
@ -60,6 +60,10 @@ import im.vector.app.features.raw.wellknown.isE2EByDefault
|
|||
import im.vector.app.features.themes.ThemeUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
|
@ -144,14 +148,12 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
// My device name may have been updated
|
||||
refreshMyDevice()
|
||||
refreshXSigningStatus()
|
||||
session.rx().liveSecretSynchronisationInfo()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
session.liveSecretSynchronisationInfo()
|
||||
.flowOn(Dispatchers.Main)
|
||||
.onEach {
|
||||
refresh4SSection(it)
|
||||
refreshXSigningStatus()
|
||||
}.also {
|
||||
disposables.add(it)
|
||||
}
|
||||
}.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
|
||||
lifecycleScope.launchWhenResumed {
|
||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.settings.ignored
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
|
@ -27,14 +26,14 @@ 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.VectorViewModel
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
|
||||
data class IgnoredUsersViewState(
|
||||
val ignoredUsers: List<User> = emptyList(),
|
||||
|
@ -68,7 +67,7 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
}
|
||||
|
||||
private fun observeIgnoredUsers() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveIgnoredUsers()
|
||||
.execute { async ->
|
||||
copy(
|
||||
|
|
|
@ -19,24 +19,25 @@ package im.vector.app.features.share
|
|||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
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.extensions.toggle
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.attachments.isPreviewable
|
||||
import im.vector.app.features.attachments.toGroupedContentAttachmentData
|
||||
import im.vector.app.features.home.room.list.BreadcrumbsRoomComparator
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.sample
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
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
|
||||
|
||||
class IncomingShareViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: IncomingShareViewState,
|
||||
|
@ -58,7 +59,7 @@ class IncomingShareViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val filterStream: BehaviorRelay<String> = BehaviorRelay.createDefault("")
|
||||
private val filterStream = MutableStateFlow("")
|
||||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
|
@ -75,7 +76,7 @@ class IncomingShareViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
filterStream
|
||||
.switchMap { filter ->
|
||||
.flatMapLatest { filter ->
|
||||
val displayNameQuery = if (filter.isEmpty()) {
|
||||
QueryStringValue.NoCondition
|
||||
} else {
|
||||
|
@ -85,9 +86,9 @@ class IncomingShareViewModel @AssistedInject constructor(
|
|||
displayName = displayNameQuery
|
||||
memberships = listOf(Membership.JOIN)
|
||||
}
|
||||
session.rx().liveRoomSummaries(filterQueryParams)
|
||||
session.flow().liveRoomSummaries(filterQueryParams)
|
||||
}
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS)
|
||||
.sample(300)
|
||||
.map { it.sortedWith(breadcrumbsRoomComparator) }
|
||||
.execute {
|
||||
copy(filteredRoomSummaries = it)
|
||||
|
@ -110,7 +111,7 @@ class IncomingShareViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleFilter(action: IncomingShareAction.FilterWith) {
|
||||
filterStream.accept(action.filter)
|
||||
filterStream.tryEmit(action.filter)
|
||||
}
|
||||
|
||||
private fun handleShareToSelectedRooms() = withState { state ->
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.app.features.spaces
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.asFlow
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
|
@ -33,8 +33,9 @@ import im.vector.app.features.session.coroutineScope
|
|||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.group
|
||||
import im.vector.app.space
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
|
@ -44,19 +45,16 @@ import org.matrix.android.sdk.api.session.events.model.toContent
|
|||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
|
||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.api.session.space.SpaceOrderUtils
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceOrderContent
|
||||
import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
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 java.util.concurrent.TimeUnit
|
||||
|
||||
class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: SpaceListViewState,
|
||||
|
@ -286,21 +284,23 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
null)
|
||||
}
|
||||
|
||||
val rxSession = session.rx()
|
||||
val flowSession = session.flow()
|
||||
|
||||
Observable.combineLatest<User?, List<RoomSummary>, List<RoomAccountDataEvent>, List<RoomSummary>>(
|
||||
rxSession
|
||||
combine(
|
||||
flowSession
|
||||
.liveUser(session.myUserId)
|
||||
.map {
|
||||
it.getOrNull()
|
||||
},
|
||||
rxSession
|
||||
flowSession
|
||||
.liveSpaceSummaries(spaceSummaryQueryParams),
|
||||
session.accountDataService().getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)).asObservable(),
|
||||
{ _, communityGroups, _ ->
|
||||
communityGroups
|
||||
}
|
||||
)
|
||||
session
|
||||
.accountDataService()
|
||||
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
||||
.asFlow()
|
||||
) { _, communityGroups, _ ->
|
||||
communityGroups
|
||||
}
|
||||
.execute { async ->
|
||||
val rootSpaces = session.spaceService().getRootSpaceSummaries()
|
||||
val orders = rootSpaces.map {
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -46,8 +47,7 @@ import im.vector.app.features.permalink.PermalinkHandler
|
|||
import im.vector.app.features.spaces.manage.ManageType
|
||||
import im.vector.app.features.spaces.manage.SpaceAddRoomSpaceChooserBottomSheet
|
||||
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import java.net.URL
|
||||
|
@ -200,33 +200,29 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onUrlClicked(url: String, title: String): Boolean {
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, null)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { managed ->
|
||||
if (!managed) {
|
||||
if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) {
|
||||
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive)
|
||||
.setTitle(R.string.external_link_confirmation_title)
|
||||
.setMessage(
|
||||
getString(R.string.external_link_confirmation_message, title, url)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
.colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
}
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
val isHandled = permalinkHandler.launch(requireActivity(), url, null)
|
||||
if (!isHandled) {
|
||||
if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) {
|
||||
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive)
|
||||
.setTitle(R.string.external_link_confirmation_title)
|
||||
.setMessage(
|
||||
getString(R.string.external_link_confirmation_message, title, url)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
.colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary))
|
||||
)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
}
|
||||
// In fact it is always managed
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorViewModel
|
|||
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -42,7 +43,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomType
|
|||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
|
||||
class SpaceDirectoryViewModel @AssistedInject constructor(
|
||||
|
@ -147,7 +148,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
excludeType = null
|
||||
}
|
||||
session
|
||||
.rx()
|
||||
.flow()
|
||||
.liveRoomSummaries(queryParams)
|
||||
.map {
|
||||
it.map { it.roomId }.toSet()
|
||||
|
@ -158,12 +159,11 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun observeMembershipChanges() {
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveRoomChangeMembershipState()
|
||||
.subscribe {
|
||||
setState { copy(changeMembershipStates = it) }
|
||||
.setOnEach {
|
||||
copy(changeMembershipStates = it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun handle(action: SpaceDirectoryViewAction) {
|
||||
|
|
|
@ -160,16 +160,15 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
|
|||
}
|
||||
|
||||
private fun observeUsers() = withState { state ->
|
||||
|
||||
identityServerUsersSearch
|
||||
.filter { it.isEmail() }
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS)
|
||||
.switchMapSingle { search ->
|
||||
val rx = session.rx()
|
||||
val flowSession = session.rx()
|
||||
val stream =
|
||||
rx.lookupThreePid(ThreePid.Email(search)).flatMap {
|
||||
flowSession.lookupThreePid(ThreePid.Email(search)).flatMap {
|
||||
it.getOrNull()?.let { foundThreePid ->
|
||||
rx.getProfileInfo(foundThreePid.matrixId)
|
||||
flowSession.getProfileInfo(foundThreePid.matrixId)
|
||||
.map { json ->
|
||||
ThreePidUser(
|
||||
email = search,
|
||||
|
|
|
@ -30,6 +30,7 @@ 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.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
|
@ -44,7 +45,6 @@ import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure
|
|||
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 timber.log.Timber
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
|
@ -135,7 +135,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
|
|||
return
|
||||
}
|
||||
val widgetId = initialState.widgetId ?: return
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveRoomWidgets(initialState.roomId, QueryStringValue.Equals(widgetId))
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { it.first() }
|
||||
|
|
|
@ -15,23 +15,24 @@
|
|||
*/
|
||||
package im.vector.app.features.widgets.permissions
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
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.platform.VectorViewModel
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
|
||||
|
@ -48,7 +49,7 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in
|
|||
|
||||
private fun observeWidget() {
|
||||
val widgetId = initialState.widgetId ?: return
|
||||
session.rx()
|
||||
session.flow()
|
||||
.liveRoomWidgets(initialState.roomId, QueryStringValue.Equals(widgetId))
|
||||
.filter { it.isNotEmpty() }
|
||||
.map {
|
||||
|
|
Loading…
Reference in a new issue