mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Fix / group switch + refactoring
This commit is contained in:
parent
6aaf6bdf9b
commit
e735aee724
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
@ -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>
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user