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

View File

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

View File

@ -212,6 +212,11 @@ internal open class RoomSummaryEntity(
if (value != field) field = value if (value != field) field = value
} }
var groupIds: String? = null
set(value) {
if (value != field) field = value
}
@Index @Index
private var membershipStr: String = Membership.NONE.name 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) { override fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams) {
realmDataSourceFactory.updateQuery { realmDataSourceFactory.updateQuery {
roomSummariesQuery(it, builder.invoke(queryParams)) roomSummariesQuery(it, builder.invoke(queryParams))
.sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
} }
} }
} }
@ -275,6 +276,10 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
// nop // nop
} }
} }
if (queryParams.activeGroupId != null) {
query.contains(RoomSummaryEntityFields.GROUP_IDS, queryParams.activeGroupId)
}
return query 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.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity 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.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.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
@ -322,6 +323,38 @@ internal class RoomSummaryUpdater @Inject constructor(
// we need also to filter DMs... // we need also to filter DMs...
// it's more annoying as based on if the other members belong the space or not // 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 { }.also {
Timber.v("## SPACES: Finish checking room hierarchy in $it ms") 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 // TODO Keep this class for now, will maybe be used fro Space
@Singleton @Singleton
class AppStateHandler @Inject constructor( class AppStateHandler @Inject constructor(
private val sessionDataSource: ActiveSessionDataSource, sessionDataSource: ActiveSessionDataSource,
private val uiStateRepository: UiStateRepository private val uiStateRepository: UiStateRepository
) : LifecycleObserver { ) : LifecycleObserver {

View File

@ -131,11 +131,15 @@ class HomeDetailFragment @Inject constructor(
} }
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary -> viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
onGroupChange(groupSummary.orNull()) if (!vectorPreferences.labSpaces()) {
onGroupChange(groupSummary.orNull())
}
} }
viewModel.selectSubscribe(this, HomeDetailViewState::spaceSummary) { spaceSummary -> viewModel.selectSubscribe(this, HomeDetailViewState::spaceSummary) { spaceSummary ->
onSpaceChange(spaceSummary.orNull()) if (vectorPreferences.labSpaces()) {
onSpaceChange(spaceSummary.orNull())
}
} }
viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode -> viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode ->
@ -245,9 +249,23 @@ class HomeDetailFragment @Inject constructor(
} }
private fun onGroupChange(groupSummary: GroupSummary?) { 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 // 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 views.groupToolbarSpaceTitleView.isVisible = false
} else { } else {
avatarRenderer.clear(views.groupToolbarAvatarImageView)
views.groupToolbarAvatarImageView.background = null views.groupToolbarAvatarImageView.background = null
avatarRenderer.renderSpace(spaceSummary.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity())) avatarRenderer.renderSpace(spaceSummary.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
views.groupToolbarSpaceTitleView.isVisible = true views.groupToolbarSpaceTitleView.isVisible = true
@ -279,10 +298,10 @@ class HomeDetailFragment @Inject constructor(
serverBackupStatusViewModel serverBackupStatusViewModel
.subscribe(this) { .subscribe(this) {
when (val banState = it.bannerState.invoke()) { 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) BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
null, null,
BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false) BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
} }
} }
views.homeKeysBackupBanner.delegate = this views.homeKeysBackupBanner.delegate = this
@ -309,10 +328,12 @@ class HomeDetailFragment @Inject constructor(
views.homeToolbarContent.debouncedClicks { views.homeToolbarContent.debouncedClicks {
withState(viewModel) { withState(viewModel) {
val currentSpace = it.spaceSummary.orNull() if (vectorPreferences.labSpaces()) {
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID } val currentSpace = it.spaceSummary.orNull()
if (vectorPreferences.labSpaces() && currentSpace != null) { ?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId)) if (vectorPreferences.labSpaces() && currentSpace != null) {
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
}
} }
} }
} }
@ -323,7 +344,7 @@ class HomeDetailFragment @Inject constructor(
views.bottomNavigationView.setOnNavigationItemSelectedListener { views.bottomNavigationView.setOnNavigationItemSelectedListener {
val displayMode = when (it.itemId) { val displayMode = when (it.itemId) {
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
else -> RoomListDisplayMode.NOTIFICATIONS else -> RoomListDisplayMode.NOTIFICATIONS
} }
viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode)) viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode))
@ -401,7 +422,7 @@ class HomeDetailFragment @Inject constructor(
private fun RoomListDisplayMode.toMenuId() = when (this) { private fun RoomListDisplayMode.toMenuId() = when (this) {
RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people 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 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.Session
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.rx.asObservable import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
@ -80,6 +81,12 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
observeSelectedGroupStore() observeSelectedGroupStore()
observeSelectedSpaceStore() observeSelectedSpaceStore()
observeRoomSummaries() observeRoomSummaries()
session.rx().liveUser(session.myUserId).execute {
copy(
myMatrixItem = it.invoke()?.getOrNull()?.toMatrixItem()
)
}
} }
override fun handle(action: HomeDetailAction) { 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.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary 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.session.sync.SyncState
import org.matrix.android.sdk.api.util.MatrixItem
data class HomeDetailViewState( data class HomeDetailViewState(
val groupSummary: Option<GroupSummary> = Option.empty(), val groupSummary: Option<GroupSummary> = Option.empty(),
val spaceSummary: Option<RoomSummary> = Option.empty(), val spaceSummary: Option<RoomSummary> = Option.empty(),
val myMatrixItem: MatrixItem? = null,
val asyncRooms: Async<List<RoomSummary>> = Uninitialized, val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
val displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE, val displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE,
val notificationCountCatchup: Int = 0, 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 package im.vector.app.features.home.room.list
import androidx.annotation.StringRes
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
@ -28,33 +26,20 @@ import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import im.vector.app.AppStateHandler import im.vector.app.AppStateHandler
import im.vector.app.R
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.grouplist.SelectedGroupDataSource
import io.reactivex.Observable import im.vector.app.features.settings.VectorPreferences
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch 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.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.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.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.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState 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.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.api.session.room.state.isPublic
import org.matrix.android.sdk.rx.asObservable
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -63,7 +48,9 @@ class RoomListViewModel @Inject constructor(
initialState: RoomListViewState, initialState: RoomListViewState,
private val session: Session, private val session: Session,
private val stringProvider: StringProvider, 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) { ) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
interface Factory { interface Factory {
@ -72,9 +59,7 @@ class RoomListViewModel @Inject constructor(
private var updatableQuery: UpdatableLivePageResult? = null private var updatableQuery: UpdatableLivePageResult? = null
private var activeSpaceAwareQueries: List<ActiveSpaceQueryUpdater>? = null private val suggestedRoomJoiningState: MutableLiveData<Map<String, Async<Unit>>> = MutableLiveData(emptyMap())
val suggestedRoomJoiningState: MutableLiveData<Map<String, Async<Unit>>> = MutableLiveData(emptyMap())
interface ActiveSpaceQueryUpdater { interface ActiveSpaceQueryUpdater {
fun updateForSpaceId(roomId: String?) fun updateForSpaceId(roomId: String?)
@ -90,17 +75,6 @@ class RoomListViewModel @Inject constructor(
observeMembershipChanges() observeMembershipChanges()
appStateHandler.selectedSpaceDataSource.observe() 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() .distinctUntilChanged()
.map { it.orNull() } .map { it.orNull() }
.distinctUntilChanged() .distinctUntilChanged()
@ -139,210 +113,34 @@ class RoomListViewModel @Inject constructor(
} }
val sections: List<RoomsSection> by lazy { val sections: List<RoomsSection> by lazy {
val sections = mutableListOf<RoomsSection>() if (vectorPreferences.labSpaces()) {
val activeSpaceAwareQueries = mutableListOf<ActiveSpaceQueryUpdater>() SpaceRoomListSectionBuilder(
if (initialState.displayMode == RoomListDisplayMode.PEOPLE) { session,
addSection(sections, stringProvider,
activeSpaceAwareQueries, appStateHandler,
R.string.invitations_header, viewModelScope,
true, suggestedRoomJoiningState,
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(
{ {
it.memberships = Membership.activeMemberships() it.disposeOnClear()
}, },
{ qpm -> {
val name = stringProvider.getString(R.string.bottom_action_rooms) updatableQuery = it
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
updatableQuery = updatableFilterLivePageResult
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
}
} }
) ).buildSections(initialState.displayMode)
} else if (initialState.displayMode == RoomListDisplayMode.NOTIFICATIONS) { } else {
addSection( GroupRoomListSectionBuilder(
sections, session,
activeSpaceAwareQueries, stringProvider,
R.string.invitations_header, viewModelScope,
true, selectedGroupDataSource,
SpaceFilterStrategy.NORMAL {
) { it.disposeOnClear()
it.memberships = listOf(Membership.INVITE) },
it.roomCategoryFilter = RoomCategoryFilter.ALL {
} updatableQuery = it
}
addSection( ).buildSections(initialState.displayMode)
sections,
activeSpaceAwareQueries,
R.string.bottom_action_rooms,
false,
SpaceFilterStrategy.NORMAL
) {
it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
}
} }
sections
} }
override fun handle(action: RoomListAction) { override fun handle(action: RoomListAction) {
@ -359,100 +157,6 @@ class RoomListViewModel @Inject constructor(
}.exhaustive }.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 { fun isPublicRoom(roomId: String): Boolean {
return session.getRoom(roomId)?.isPublic().orFalse() return session.getRoom(roomId)?.isPublic().orFalse()
} }
@ -604,7 +308,7 @@ class RoomListViewModel @Inject constructor(
private fun String.otherTag(): String? { private fun String.otherTag(): String? {
return when (this) { 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 RoomTag.ROOM_TAG_LOW_PRIORITY -> RoomTag.ROOM_TAG_FAVOURITE
else -> null 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.AppStateHandler
import im.vector.app.core.resources.StringProvider 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 org.matrix.android.sdk.api.session.Session
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>, class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
private val appStateHandler: AppStateHandler, private val appStateHandler: AppStateHandler,
private val stringProvider: StringProvider) private val stringProvider: StringProvider,
private val vectorPreferences: VectorPreferences,
private val selectedGroupDataSource: SelectedGroupDataSource)
: RoomListViewModel.Factory { : RoomListViewModel.Factory {
override fun create(initialState: RoomListViewState): RoomListViewModel { override fun create(initialState: RoomListViewState): RoomListViewModel {
@ -32,7 +36,9 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
initialState, initialState,
session.get(), session.get(),
stringProvider, 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) }
}
}