Fix / group switch + refactoring

This commit is contained in:
Valere 2021-04-14 14:43:21 +02:00
parent 6aaf6bdf9b
commit e735aee724
14 changed files with 796 additions and 344 deletions

View file

@ -58,7 +58,8 @@ data class RoomSummaryQueryParams(
val roomTagQueryFilter: RoomTagQueryFilter?,
val excludeType: List<String?>?,
val includeType: List<String?>?,
val activeSpaceId: ActiveSpaceFilter?
val activeSpaceId: ActiveSpaceFilter?,
var activeGroupId: String? = null
) {
class Builder {
@ -72,6 +73,7 @@ data class RoomSummaryQueryParams(
var excludeType: List<String?>? = listOf(RoomType.SPACE)
var includeType: List<String?>? = null
var activeSpaceId: ActiveSpaceFilter = ActiveSpaceFilter.None
var activeGroupId: String? = null
fun build() = RoomSummaryQueryParams(
roomId = roomId,
@ -82,7 +84,8 @@ data class RoomSummaryQueryParams(
roomTagQueryFilter = roomTagQueryFilter,
excludeType = excludeType,
includeType = includeType,
activeSpaceId = activeSpaceId
activeSpaceId = activeSpaceId,
activeGroupId = activeGroupId
)
}
}

View file

@ -218,6 +218,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
?.transform { obj ->
// Should I put messaging type here?
obj.setString(RoomSummaryEntityFields.ROOM_TYPE, null)

View file

@ -212,6 +212,11 @@ internal open class RoomSummaryEntity(
if (value != field) field = value
}
var groupIds: String? = null
set(value) {
if (value != field) field = value
}
@Index
private var membershipStr: String = Membership.NONE.name

View file

@ -197,6 +197,7 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
override fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams) {
realmDataSourceFactory.updateQuery {
roomSummariesQuery(it, builder.invoke(queryParams))
.sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
}
}
}
@ -275,6 +276,10 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
// nop
}
}
if (queryParams.activeGroupId != null) {
query.contains(RoomSummaryEntityFields.GROUP_IDS, queryParams.activeGroupId)
}
return query
}

View file

@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
@ -322,6 +323,38 @@ internal class RoomSummaryUpdater @Inject constructor(
// we need also to filter DMs...
// it's more annoying as based on if the other members belong the space or not
// LEGACY GROUPS
// lets mark rooms that belongs to groups
val existingGroups = GroupSummaryEntity.where(realm).findAll()
// For rooms
realm.where(RoomSummaryEntity::class.java)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
.findAll().forEach { room ->
val belongsTo = existingGroups.filter { it.roomIds.contains(room.roomId) }
room.groupIds = if (belongsTo.isEmpty()) {
null
} else {
"|${belongsTo.joinToString("|")}|"
}
}
// For DMS
realm.where(RoomSummaryEntity::class.java)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
.findAll().forEach { room ->
val belongsTo = existingGroups.filter {
it.userIds.intersect(room.otherMemberIds).isNotEmpty()
}
room.groupIds = if (belongsTo.isEmpty()) {
null
} else {
"|${belongsTo.joinToString("|")}|"
}
}
}.also {
Timber.v("## SPACES: Finish checking room hierarchy in $it ms")
}

View file

@ -35,7 +35,7 @@ import javax.inject.Singleton
// TODO Keep this class for now, will maybe be used fro Space
@Singleton
class AppStateHandler @Inject constructor(
private val sessionDataSource: ActiveSessionDataSource,
sessionDataSource: ActiveSessionDataSource,
private val uiStateRepository: UiStateRepository
) : LifecycleObserver {

View file

@ -131,11 +131,15 @@ class HomeDetailFragment @Inject constructor(
}
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
onGroupChange(groupSummary.orNull())
if (!vectorPreferences.labSpaces()) {
onGroupChange(groupSummary.orNull())
}
}
viewModel.selectSubscribe(this, HomeDetailViewState::spaceSummary) { spaceSummary ->
onSpaceChange(spaceSummary.orNull())
if (vectorPreferences.labSpaces()) {
onSpaceChange(spaceSummary.orNull())
}
}
viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode ->
@ -245,9 +249,23 @@ class HomeDetailFragment @Inject constructor(
}
private fun onGroupChange(groupSummary: GroupSummary?) {
groupSummary?.let {
groupSummary ?: return
if (groupSummary.groupId == ALL_COMMUNITIES_GROUP_ID) {
// Special case
avatarRenderer.clear(views.groupToolbarAvatarImageView)
views.groupToolbarAvatarImageView.background = null
val myMxItem = withState(viewModel) { it.myMatrixItem }
if (myMxItem != null) {
avatarRenderer.render(myMxItem, views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
}
views.groupToolbarSpaceTitleView.isVisible = false
} else {
views.groupToolbarAvatarImageView.background = null
// Use GlideApp with activity context to avoid the glideRequests to be paused
avatarRenderer.render(it.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
avatarRenderer.render(groupSummary.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
views.groupToolbarSpaceTitleView.isVisible = true
views.groupToolbarSpaceTitleView.text = groupSummary.displayName
}
}
@ -268,6 +286,7 @@ class HomeDetailFragment @Inject constructor(
views.groupToolbarSpaceTitleView.isVisible = false
} else {
avatarRenderer.clear(views.groupToolbarAvatarImageView)
views.groupToolbarAvatarImageView.background = null
avatarRenderer.renderSpace(spaceSummary.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
views.groupToolbarSpaceTitleView.isVisible = true
@ -279,10 +298,10 @@ class HomeDetailFragment @Inject constructor(
serverBackupStatusViewModel
.subscribe(this) {
when (val banState = it.bannerState.invoke()) {
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
null,
BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
}
}
views.homeKeysBackupBanner.delegate = this
@ -309,10 +328,12 @@ class HomeDetailFragment @Inject constructor(
views.homeToolbarContent.debouncedClicks {
withState(viewModel) {
val currentSpace = it.spaceSummary.orNull()
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
if (vectorPreferences.labSpaces() && currentSpace != null) {
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
if (vectorPreferences.labSpaces()) {
val currentSpace = it.spaceSummary.orNull()
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
if (vectorPreferences.labSpaces() && currentSpace != null) {
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
}
}
}
}
@ -323,7 +344,7 @@ class HomeDetailFragment @Inject constructor(
views.bottomNavigationView.setOnNavigationItemSelectedListener {
val displayMode = when (it.itemId) {
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
else -> RoomListDisplayMode.NOTIFICATIONS
}
viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode))
@ -401,7 +422,7 @@ class HomeDetailFragment @Inject constructor(
private fun RoomListDisplayMode.toMenuId() = when (this) {
RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people
RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
else -> R.id.bottom_action_notification
}

View file

@ -37,6 +37,7 @@ 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.api.util.toMatrixItem
import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
@ -80,6 +81,12 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
observeSelectedGroupStore()
observeSelectedSpaceStore()
observeRoomSummaries()
session.rx().liveUser(session.myUserId).execute {
copy(
myMatrixItem = it.invoke()?.getOrNull()?.toMatrixItem()
)
}
}
override fun handle(action: HomeDetailAction) {

View file

@ -23,10 +23,12 @@ import com.airbnb.mvrx.Uninitialized
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.util.MatrixItem
data class HomeDetailViewState(
val groupSummary: Option<GroupSummary> = Option.empty(),
val spaceSummary: Option<RoomSummary> = Option.empty(),
val myMatrixItem: MatrixItem? = null,
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
val displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE,
val notificationCountCatchup: Int = 0,

View file

@ -0,0 +1,261 @@
/*
* 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.home.room.list
import androidx.annotation.StringRes
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID
import im.vector.app.features.grouplist.SelectedGroupDataSource
import im.vector.app.features.home.RoomListDisplayMode
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.rx.asObservable
class GroupRoomListSectionBuilder(
val session: Session,
val stringProvider: StringProvider,
val viewModelScope: CoroutineScope,
val selectedGroupDataSource: SelectedGroupDataSource,
val onDisposable: (Disposable) -> Unit,
val onUdpatable: (UpdatableLivePageResult) -> Unit
) : RoomListSectionBuilder {
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
val activeSpaceAwareQueries = mutableListOf<UpdatableLivePageResult>()
val sections = mutableListOf<RoomsSection>()
val actualGroupId = selectedGroupDataSource.currentValue?.orNull()
?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
when (mode) {
RoomListDisplayMode.PEOPLE -> {
// 3 sections Invites / Fav / Dms
buildPeopleSections(sections, activeSpaceAwareQueries, actualGroupId)
}
RoomListDisplayMode.ROOMS -> {
// 5 sections invites / Fav / Rooms / Low Priority / Server notice
buildRoomsSections(sections, activeSpaceAwareQueries, actualGroupId)
}
RoomListDisplayMode.FILTERED -> {
// Used when searching for rooms
withQueryParams(
{
it.memberships = Membership.activeMemberships()
},
{ qpm ->
val name = stringProvider.getString(R.string.bottom_action_rooms)
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
onUdpatable(updatableFilterLivePageResult)
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
}
}
)
}
RoomListDisplayMode.NOTIFICATIONS -> {
addSection(
sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ALL
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
it.activeGroupId = actualGroupId
}
}
}
selectedGroupDataSource.observe()
.distinctUntilChanged()
.subscribe { activeSpaceOption ->
val selectedGroupId = activeSpaceOption.orNull()?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
activeSpaceAwareQueries.onEach { updater ->
updater.updateQuery { query ->
query.copy(activeGroupId = selectedGroupId)
}
}
}.also {
onDisposable.invoke(it)
}
return sections
}
private fun buildRoomsSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>, actualGroupId: String?) {
addSection(
sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.low_priority_header,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.system_alerts_header,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
it.activeGroupId = actualGroupId
}
}
private fun buildPeopleSections(
sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>,
actualGroupId: String?
) {
addSection(sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
it.activeGroupId = actualGroupId
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_people_x,
false
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
it.roomTagQueryFilter = RoomTagQueryFilter(false, null, null)
it.activeGroupId = actualGroupId
}
}
private fun addSection(sections: MutableList<RoomsSection>,
activeSpaceUpdaters: MutableList<UpdatableLivePageResult>,
@StringRes nameRes: Int,
notifyOfLocalEcho: Boolean = false,
query: (RoomSummaryQueryParams.Builder) -> Unit) {
withQueryParams(
{ query.invoke(it) },
{ roomQueryParams ->
val name = stringProvider.getString(nameRes)
session.getFilteredPagedRoomSummariesLive(roomQueryParams)
.also {
activeSpaceUpdaters.add(it)
}.livePagedList
.let { livePagedList ->
// use it also as a source to update count
livePagedList.asObservable()
.observeOn(Schedulers.computation())
.subscribe {
sections.find { it.sectionName == name }
?.notificationCount
?.postValue(session.getNotificationCountForRooms(roomQueryParams))
}.also {
onDisposable.invoke(it)
}
sections.add(
RoomsSection(
sectionName = name,
livePages = livePagedList,
notifyOfLocalEcho = notifyOfLocalEcho
)
)
}
}
)
}
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
RoomSummaryQueryParams.Builder()
.apply { builder.invoke(this) }
.build()
.let { block(it) }
}
}

View file

@ -0,0 +1,23 @@
/*
* 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.home.room.list
import im.vector.app.features.home.RoomListDisplayMode
interface RoomListSectionBuilder {
fun buildSections(mode: RoomListDisplayMode) : List<RoomsSection>
}

View file

@ -16,9 +16,7 @@
package im.vector.app.features.home.room.list
import androidx.annotation.StringRes
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
@ -28,33 +26,20 @@ import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import im.vector.app.AppStateHandler
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 im.vector.app.features.home.RoomListDisplayMode
import io.reactivex.Observable
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers
import im.vector.app.features.grouplist.SelectedGroupDataSource
import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
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.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic
import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import javax.inject.Inject
@ -63,7 +48,9 @@ class RoomListViewModel @Inject constructor(
initialState: RoomListViewState,
private val session: Session,
private val stringProvider: StringProvider,
private val appStateHandler: AppStateHandler
private val appStateHandler: AppStateHandler,
private val selectedGroupDataSource: SelectedGroupDataSource,
private val vectorPreferences: VectorPreferences
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
interface Factory {
@ -72,9 +59,7 @@ class RoomListViewModel @Inject constructor(
private var updatableQuery: UpdatableLivePageResult? = null
private var activeSpaceAwareQueries: List<ActiveSpaceQueryUpdater>? = null
val suggestedRoomJoiningState: MutableLiveData<Map<String, Async<Unit>>> = MutableLiveData(emptyMap())
private val suggestedRoomJoiningState: MutableLiveData<Map<String, Async<Unit>>> = MutableLiveData(emptyMap())
interface ActiveSpaceQueryUpdater {
fun updateForSpaceId(roomId: String?)
@ -90,17 +75,6 @@ class RoomListViewModel @Inject constructor(
observeMembershipChanges()
appStateHandler.selectedSpaceDataSource.observe()
// .observeOn(Schedulers.computation())
.distinctUntilChanged()
.subscribe { activeSpaceOption ->
val selectedSpace = activeSpaceOption.orNull()
activeSpaceAwareQueries?.onEach { updater ->
updater.updateForSpaceId(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
}
}.disposeOnClear()
appStateHandler.selectedSpaceDataSource.observe()
// .observeOn(Schedulers.computation())
.distinctUntilChanged()
.map { it.orNull() }
.distinctUntilChanged()
@ -139,210 +113,34 @@ class RoomListViewModel @Inject constructor(
}
val sections: List<RoomsSection> by lazy {
val sections = mutableListOf<RoomsSection>()
val activeSpaceAwareQueries = mutableListOf<ActiveSpaceQueryUpdater>()
if (initialState.displayMode == RoomListDisplayMode.PEOPLE) {
addSection(sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true,
SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
}
addSection(sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false,
SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
}
// For DMs we still need some post query filter :/
// It's probably less important as home is not filtering at all
val dmList = MutableLiveData<List<RoomSummary>>()
Observables.combineLatest(
session.getRoomSummariesLive(
roomSummaryQueryParams {
memberships = listOf(Membership.JOIN)
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
}
).asObservable(),
appStateHandler.selectedSpaceDataSource.observe()
) { rooms, currentSpaceOption ->
val currentSpace = currentSpaceOption.orNull()
.takeIf {
// the +ALL trick is annoying, should find a way to fix that at the source!
MatrixPatterns.isRoomId(it?.roomId)
}
if (currentSpace == null) {
rooms
} else {
rooms.filter {
it.otherMemberIds
.intersect(currentSpace.otherMemberIds)
.isNotEmpty()
}
}
}.subscribe {
dmList.postValue(it)
}.disposeOnClear()
sections.add(
RoomsSection(
sectionName = stringProvider.getString(R.string.bottom_action_people_x),
liveList = dmList,
notifyOfLocalEcho = false
)
)
} else if (initialState.displayMode == RoomListDisplayMode.ROOMS) {
addSection(
sections, activeSpaceAwareQueries,
R.string.invitations_header,
true,
SpaceFilterStrategy.NONE
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false,
SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.low_priority_header,
false,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.system_alerts_header,
false,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
}
// add suggested rooms
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
appStateHandler.selectedSpaceDataSource.observe()
.distinctUntilChanged()
.switchMap { activeSpaceOption ->
val selectedSpace = activeSpaceOption.orNull()
if (selectedSpace == null) {
Observable.just(emptyList())
} else {
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
val value = spaceSum?.second ?: emptyList()
// i need to check if it's already joined.
val filtered = value.filter {
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
}
emit(filtered)
}.asObservable()
}
}
// .subscribe {
// Timber.w("VAL: Suggested rooms is ${it}")
// liveSuggestedRooms.postValue(it)
// }.disposeOnClear()
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
Observables.combineLatest(
suggestedRoomsObservable,
suggestedRoomJoiningState.asObservable()
) { rooms, joinStates ->
SuggestedRoomInfo(
rooms,
joinStates
)
}.subscribe {
liveSuggestedRooms.postValue(it)
}.disposeOnClear()
sections.add(
RoomsSection(
sectionName = stringProvider.getString(R.string.suggested_header),
liveSuggested = liveSuggestedRooms,
notifyOfLocalEcho = false
)
)
} else if (initialState.displayMode == RoomListDisplayMode.FILTERED) {
withQueryParams(
if (vectorPreferences.labSpaces()) {
SpaceRoomListSectionBuilder(
session,
stringProvider,
appStateHandler,
viewModelScope,
suggestedRoomJoiningState,
{
it.memberships = Membership.activeMemberships()
it.disposeOnClear()
},
{ qpm ->
val name = stringProvider.getString(R.string.bottom_action_rooms)
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
updatableQuery = updatableFilterLivePageResult
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
}
{
updatableQuery = it
}
)
} else if (initialState.displayMode == RoomListDisplayMode.NOTIFICATIONS) {
addSection(
sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ALL
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
}
).buildSections(initialState.displayMode)
} else {
GroupRoomListSectionBuilder(
session,
stringProvider,
viewModelScope,
selectedGroupDataSource,
{
it.disposeOnClear()
},
{
updatableQuery = it
}
).buildSections(initialState.displayMode)
}
sections
}
override fun handle(action: RoomListAction) {
@ -359,100 +157,6 @@ class RoomListViewModel @Inject constructor(
}.exhaustive
}
private fun addSection(sections: MutableList<RoomsSection>,
activeSpaceUpdaters: MutableList<ActiveSpaceQueryUpdater>,
@StringRes nameRes: Int,
notifyOfLocalEcho: Boolean = false,
spaceFilterStrategy: SpaceFilterStrategy = SpaceFilterStrategy.NONE,
query: (RoomSummaryQueryParams.Builder) -> Unit) {
withQueryParams(
{ query.invoke(it) },
{ roomQueryParams ->
val name = stringProvider.getString(nameRes)
// if (activeSpaceAwareQueries != null) {
session.getFilteredPagedRoomSummariesLive(
when (spaceFilterStrategy) {
SpaceFilterStrategy.NORMAL -> {
roomQueryParams.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(appStateHandler.safeActiveSpaceId())
)
}
SpaceFilterStrategy.NOT_IF_ALL -> {
if (appStateHandler.safeActiveSpaceId() == null) {
roomQueryParams
} else {
roomQueryParams.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(appStateHandler.safeActiveSpaceId())
)
}
}
SpaceFilterStrategy.NONE -> roomQueryParams
}
).also {
when (spaceFilterStrategy) {
SpaceFilterStrategy.NORMAL -> {
activeSpaceUpdaters.add(object : ActiveSpaceQueryUpdater {
override fun updateForSpaceId(roomId: String?) {
it.updateQuery {
it.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(roomId)
)
}
}
})
}
SpaceFilterStrategy.NOT_IF_ALL -> {
activeSpaceUpdaters.add(object : ActiveSpaceQueryUpdater {
override fun updateForSpaceId(roomId: String?) {
if (roomId != null) {
it.updateQuery {
it.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(roomId)
)
}
}
}
})
}
SpaceFilterStrategy.NONE -> {
// we ignore current space for this one
}
}
}.livePagedList
.let { livePagedList ->
// use it also as a source to update count
livePagedList.asObservable()
.observeOn(Schedulers.computation())
.subscribe {
sections.find { it.sectionName == name }
?.notificationCount
?.postValue(session.getNotificationCountForRooms(roomQueryParams))
}
.disposeOnClear()
sections.add(
RoomsSection(
sectionName = name,
livePages = livePagedList,
notifyOfLocalEcho = notifyOfLocalEcho
)
)
}
}
)
}
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
RoomSummaryQueryParams.Builder()
.apply { builder.invoke(this) }
.build()
.let { block(it) }
}
fun isPublicRoom(roomId: String): Boolean {
return session.getRoom(roomId)?.isPublic().orFalse()
}
@ -604,7 +308,7 @@ class RoomListViewModel @Inject constructor(
private fun String.otherTag(): String? {
return when (this) {
RoomTag.ROOM_TAG_FAVOURITE -> RoomTag.ROOM_TAG_LOW_PRIORITY
RoomTag.ROOM_TAG_FAVOURITE -> RoomTag.ROOM_TAG_LOW_PRIORITY
RoomTag.ROOM_TAG_LOW_PRIORITY -> RoomTag.ROOM_TAG_FAVOURITE
else -> null
}

View file

@ -18,13 +18,17 @@ package im.vector.app.features.home.room.list
import im.vector.app.AppStateHandler
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.grouplist.SelectedGroupDataSource
import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
import javax.inject.Provider
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
private val appStateHandler: AppStateHandler,
private val stringProvider: StringProvider)
private val stringProvider: StringProvider,
private val vectorPreferences: VectorPreferences,
private val selectedGroupDataSource: SelectedGroupDataSource)
: RoomListViewModel.Factory {
override fun create(initialState: RoomListViewState): RoomListViewModel {
@ -32,7 +36,9 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
initialState,
session.get(),
stringProvider,
appStateHandler
appStateHandler,
selectedGroupDataSource,
vectorPreferences
)
}
}

View file

@ -0,0 +1,381 @@
/*
* 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.home.room.list
import androidx.annotation.StringRes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
import com.airbnb.mvrx.Async
import im.vector.app.AppStateHandler
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.RoomListDisplayMode
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.rx.asObservable
class SpaceRoomListSectionBuilder(
val session: Session,
val stringProvider: StringProvider,
val appStateHandler: AppStateHandler,
val viewModelScope: CoroutineScope,
private val suggestedRoomJoiningState: LiveData<Map<String, Async<Unit>>>,
val onDisposable: (Disposable) -> Unit,
val onUdpatable: (UpdatableLivePageResult) -> Unit
) : RoomListSectionBuilder {
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
val sections = mutableListOf<RoomsSection>()
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
when (mode) {
RoomListDisplayMode.PEOPLE -> {
buildDmSections(sections, activeSpaceAwareQueries)
}
RoomListDisplayMode.ROOMS -> {
buildRoomsSections(sections, activeSpaceAwareQueries)
}
RoomListDisplayMode.FILTERED -> {
withQueryParams(
{
it.memberships = Membership.activeMemberships()
},
{ qpm ->
val name = stringProvider.getString(R.string.bottom_action_rooms)
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
onUdpatable(updatableFilterLivePageResult)
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
}
}
)
}
RoomListDisplayMode.NOTIFICATIONS -> {
addSection(
sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true,
RoomListViewModel.SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ALL
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false,
RoomListViewModel.SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
}
}
}
appStateHandler.selectedSpaceDataSource.observe()
.distinctUntilChanged()
.subscribe { activeSpaceOption ->
val selectedSpace = activeSpaceOption.orNull()
activeSpaceAwareQueries.onEach { updater ->
updater.updateForSpaceId(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
}
}.also {
onDisposable.invoke(it)
}
return sections
}
private fun buildRoomsSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
addSection(
sections, activeSpaceAwareQueries,
R.string.invitations_header,
true,
RoomListViewModel.SpaceFilterStrategy.NONE
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false,
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false,
RoomListViewModel.SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.low_priority_header,
false,
RoomListViewModel.SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
}
addSection(
sections,
activeSpaceAwareQueries,
R.string.system_alerts_header,
false,
RoomListViewModel.SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
}
// add suggested rooms
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
appStateHandler.selectedSpaceDataSource.observe()
.distinctUntilChanged()
.switchMap { activeSpaceOption ->
val selectedSpace = activeSpaceOption.orNull()
if (selectedSpace == null) {
Observable.just(emptyList())
} else {
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
val value = spaceSum?.second ?: emptyList()
// i need to check if it's already joined.
val filtered = value.filter {
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
}
emit(filtered)
}.asObservable()
}
}
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
Observables.combineLatest(
suggestedRoomsObservable,
suggestedRoomJoiningState.asObservable()
) { rooms, joinStates ->
SuggestedRoomInfo(
rooms,
joinStates
)
}.subscribe {
liveSuggestedRooms.postValue(it)
}.also {
onDisposable.invoke(it)
}
sections.add(
RoomsSection(
sectionName = stringProvider.getString(R.string.suggested_header),
liveSuggested = liveSuggestedRooms,
notifyOfLocalEcho = false
)
)
}
private fun buildDmSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
addSection(sections,
activeSpaceAwareQueries,
R.string.invitations_header,
true,
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.INVITE)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
}
addSection(sections,
activeSpaceAwareQueries,
R.string.bottom_action_favourites,
false,
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
}
// For DMs we still need some post query filter :/
// It's probably less important as home is not filtering at all
val dmList = MutableLiveData<List<RoomSummary>>()
Observables.combineLatest(
session.getRoomSummariesLive(
roomSummaryQueryParams {
memberships = listOf(Membership.JOIN)
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
}
).asObservable(),
appStateHandler.selectedSpaceDataSource.observe()
) { rooms, currentSpaceOption ->
val currentSpace = currentSpaceOption.orNull()
.takeIf {
// the +ALL trick is annoying, should find a way to fix that at the source!
MatrixPatterns.isRoomId(it?.roomId)
}
if (currentSpace == null) {
rooms
} else {
rooms.filter {
it.otherMemberIds
.intersect(currentSpace.otherMemberIds)
.isNotEmpty()
}
}
}.subscribe {
dmList.postValue(it)
}.also {
onDisposable.invoke(it)
}
sections.add(
RoomsSection(
sectionName = stringProvider.getString(R.string.bottom_action_people_x),
liveList = dmList,
notifyOfLocalEcho = false
)
)
}
private fun addSection(sections: MutableList<RoomsSection>,
activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
@StringRes nameRes: Int,
notifyOfLocalEcho: Boolean = false,
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
query: (RoomSummaryQueryParams.Builder) -> Unit) {
withQueryParams(
{ query.invoke(it) },
{ roomQueryParams ->
val name = stringProvider.getString(nameRes)
session.getFilteredPagedRoomSummariesLive(
when (spaceFilterStrategy) {
RoomListViewModel.SpaceFilterStrategy.NORMAL -> {
roomQueryParams.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(appStateHandler.safeActiveSpaceId())
)
}
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL -> {
if (appStateHandler.safeActiveSpaceId() == null) {
roomQueryParams
} else {
roomQueryParams.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(appStateHandler.safeActiveSpaceId())
)
}
}
RoomListViewModel.SpaceFilterStrategy.NONE -> roomQueryParams
}
).also {
when (spaceFilterStrategy) {
RoomListViewModel.SpaceFilterStrategy.NORMAL -> {
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
override fun updateForSpaceId(roomId: String?) {
it.updateQuery {
it.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(roomId)
)
}
}
})
}
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL -> {
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
override fun updateForSpaceId(roomId: String?) {
if (roomId != null) {
it.updateQuery {
it.copy(
activeSpaceId = ActiveSpaceFilter.ActiveSpace(roomId)
)
}
}
}
})
}
RoomListViewModel.SpaceFilterStrategy.NONE -> {
// we ignore current space for this one
}
}
}.livePagedList
.let { livePagedList ->
// use it also as a source to update count
livePagedList.asObservable()
.observeOn(Schedulers.computation())
.subscribe {
sections.find { it.sectionName == name }
?.notificationCount
?.postValue(session.getNotificationCountForRooms(roomQueryParams))
}.also {
onDisposable.invoke(it)
}
sections.add(
RoomsSection(
sectionName = name,
livePages = livePagedList,
notifyOfLocalEcho = notifyOfLocalEcho
)
)
}
}
)
}
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
RoomSummaryQueryParams.Builder()
.apply { builder.invoke(this) }
.build()
.let { block(it) }
}
}