Experimental: Swipe to switch between root spaces

Change-Id: I8849a4a2fd2cea0a7904f8c4259adf8c09f6864a
This commit is contained in:
SpiritCroc 2021-10-03 16:07:26 +02:00
parent 3eef15ae3e
commit af0b3a8897
14 changed files with 355 additions and 34 deletions

View file

@ -0,0 +1,22 @@
package de.spiritcroc.viewpager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import timber.log.Timber
import java.lang.Exception
// Mainly taken from https://stackoverflow.com/a/63455547
fun ViewPager2.reduceDragSensitivity(factor: Int) {
try {
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
recyclerViewField.isAccessible = true
val recyclerView = recyclerViewField.get(this) as RecyclerView
val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
touchSlopField.isAccessible = true
val touchSlop = touchSlopField.get(recyclerView) as Int
touchSlopField.set(recyclerView, touchSlop * factor)
} catch (e: Exception) {
Timber.e("Cannot reduce viewpager drag sensitivity: $e")
}
}

View file

@ -24,14 +24,16 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.badge.BadgeDrawable import com.google.android.material.badge.BadgeDrawable
import de.spiritcroc.viewpager.reduceDragSensitivity
import im.vector.app.AppStateHandler import im.vector.app.AppStateHandler
import im.vector.app.R import im.vector.app.R
import im.vector.app.RoomGroupingMethod import im.vector.app.RoomGroupingMethod
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.extensions.restart import im.vector.app.core.extensions.restart
import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
@ -48,6 +50,7 @@ import im.vector.app.features.call.dialpad.DialPadFragment
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.list.RoomListFragment
import im.vector.app.features.home.room.list.RoomListParams import im.vector.app.features.home.room.list.RoomListParams
import im.vector.app.features.home.room.list.RoomListSectionBuilderSpace.Companion.SPACE_ID_FOLLOW_APP
import im.vector.app.features.home.room.list.UnreadCounterBadgeView import im.vector.app.features.home.room.list.UnreadCounterBadgeView
import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert import im.vector.app.features.popup.VerificationVectorAlert
@ -60,6 +63,7 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
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.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class HomeDetailFragment @Inject constructor( class HomeDetailFragment @Inject constructor(
@ -73,6 +77,10 @@ class HomeDetailFragment @Inject constructor(
KeysBackupBanner.Delegate, KeysBackupBanner.Delegate,
CurrentCallsView.Callback { CurrentCallsView.Callback {
companion object {
const val DEBUG_VIEW_PAGER = true
}
private val viewModel: HomeDetailViewModel by fragmentViewModel() private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel() private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel()
@ -93,6 +101,12 @@ class HomeDetailFragment @Inject constructor(
} }
} }
private var initialPageSelected = false
private var pagerSpaces: List<String?>? = null
private var pagerTab: HomeTab? = null
private var pagerPagingEnabled: Boolean = false
private val pendingSpaceIds = mutableListOf<String?>()
override fun getMenuRes() = R.menu.room_list override fun getMenuRes() = R.menu.room_list
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -131,6 +145,29 @@ class HomeDetailFragment @Inject constructor(
checkNotificationTabStatus() checkNotificationTabStatus()
// Reduce sensitivity of viewpager to avoid scrolling horizontally by accident too easily
views.roomListContainerPager.reduceDragSensitivity(4)
// space pager: update appStateHandler's current page to update rest of the UI accordingly
views.roomListContainerPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
if (DEBUG_VIEW_PAGER) Timber.i("Home pager: selected page $position $initialPageSelected")
super.onPageSelected(position)
if (!initialPageSelected) {
// Do not apply before we have restored the previous value
if (position == 0) {
return
} else {
// User has swiped, store it anyways
initialPageSelected = true
}
}
val selectedId = getSpaceIdForPageIndex(position)
pendingSpaceIds.add(selectedId)
appStateHandler.setCurrentSpace(selectedId)
}
})
viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod -> viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
when (roomGroupingMethod) { when (roomGroupingMethod) {
is RoomGroupingMethod.ByLegacyGroup -> { is RoomGroupingMethod.ByLegacyGroup -> {
@ -188,6 +225,10 @@ class HomeDetailFragment @Inject constructor(
) )
} }
viewModel.onEach(HomeDetailViewState::roomGroupingMethod, HomeDetailViewState::rootSpacesOrdered, HomeDetailViewState::currentTab) { roomGroupingMethod, rootSpacesOrdered, currentTab ->
setupViewPager(roomGroupingMethod, rootSpacesOrdered, currentTab)
}
sharedCallActionViewModel sharedCallActionViewModel
.liveKnownCalls .liveKnownCalls
.observe(viewLifecycleOwner) { .observe(viewLifecycleOwner) {
@ -438,12 +479,13 @@ class HomeDetailFragment @Inject constructor(
private fun updateUIForTab(tab: HomeTab) { private fun updateUIForTab(tab: HomeTab) {
views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
views.groupToolbarTitleView.setText(tab.titleRes) views.groupToolbarTitleView.setText(tab.titleRes)
updateSelectedFragment(tab) //updateSelectedFragment(tab)
invalidateOptionsMenu() invalidateOptionsMenu()
} }
private fun HomeTab.toFragmentTag() = "FRAGMENT_TAG_$this" private fun HomeTab.toFragmentTag() = "FRAGMENT_TAG_$this"
/*
private fun updateSelectedFragment(tab: HomeTab) { private fun updateSelectedFragment(tab: HomeTab) {
val fragmentTag = tab.toFragmentTag() val fragmentTag = tab.toFragmentTag()
val fragmentToShow = childFragmentManager.findFragmentByTag(fragmentTag) val fragmentToShow = childFragmentManager.findFragmentByTag(fragmentTag)
@ -471,6 +513,120 @@ class HomeDetailFragment @Inject constructor(
} }
} }
} }
*/
private fun setupViewPager(roomGroupingMethod: RoomGroupingMethod, spaces: List<RoomSummary>?, tab: HomeTab) {
val oldAdapter = views.roomListContainerPager.adapter as? FragmentStateAdapter
val pagingAllowed = vectorPreferences.enableSpacePager()
if (DEBUG_VIEW_PAGER) Timber.i("Home pager: setup, old adapter: $oldAdapter")
val unsafeSpaces = spaces?.map { it.roomId } ?: listOf()
val selectedSpaceId = (roomGroupingMethod as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId
val selectedIndex = getPageIndexForSpaceId(selectedSpaceId, unsafeSpaces)
val pagingEnabled = pagingAllowed && roomGroupingMethod is RoomGroupingMethod.BySpace && unsafeSpaces.size > 0 && selectedIndex != null
val safeSpaces = if (pagingEnabled) unsafeSpaces else listOf()
// Check if we need to recreate the adapter for a new tab
if (oldAdapter != null) {
val changed = pagerTab != tab || pagerSpaces != safeSpaces || pagerPagingEnabled != pagingEnabled
if (DEBUG_VIEW_PAGER) Timber.i("Home pager: has changed: $changed (${pagerTab != tab} ${pagerSpaces != safeSpaces} ${pagerPagingEnabled != pagingEnabled} $selectedIndex ${views.roomListContainerPager.currentItem}) | $safeSpaces")
if (!changed) {
if (pagingEnabled) {
// No need to re-setup pager, just check for selected page
// Discard state changes that we created ourselves by swiping on the pager
while (pendingSpaceIds.size > 0) {
val pendingSpaceId = pendingSpaceIds.removeAt(0)
if (pendingSpaceId == selectedSpaceId) {
return
}
}
if (selectedIndex != null) {
if (selectedIndex != views.roomListContainerPager.currentItem) {
// post() mitigates a case where we could end up in an endless loop circling around the same few spaces
views.roomListContainerPager.post {
views.roomListContainerPager.currentItem = selectedIndex
}
}
return
}
} else {
// Nothing to change
return
}
} else {
// Clean up old fragments
val transaction = childFragmentManager.beginTransaction()
childFragmentManager.fragments
.forEach {
transaction.detach(it)
}
transaction.commit()
}
}
pagerSpaces = safeSpaces
pagerTab = tab
pagerPagingEnabled = pagingEnabled
initialPageSelected = false
pendingSpaceIds.clear()
views.roomListContainerPager.offscreenPageLimit = 2
val adapter = object: FragmentStateAdapter(this@HomeDetailFragment) {
override fun getItemCount(): Int {
if (!pagingEnabled) {
return 1
}
return when (tab) {
is HomeTab.DialPad -> 1
else -> safeSpaces.size + 1
}
}
override fun createFragment(position: Int): Fragment {
if (DEBUG_VIEW_PAGER) Timber.i("Home pager: create fragment for position $position")
return when (tab) {
is HomeTab.DialPad -> createDialPadFragment()
is HomeTab.RoomList -> {
val params = if (pagingEnabled) {
RoomListParams(tab.displayMode, getSpaceIdForPageIndex(position)).toMvRxBundle()
} else {
RoomListParams(tab.displayMode, SPACE_ID_FOLLOW_APP).toMvRxBundle()
}
childFragmentManager.fragmentFactory.instantiate(activity!!.classLoader, RoomListFragment::class.java.name).apply {
arguments = params
}
}
}
}
}
views.roomListContainerPager.adapter = adapter
if (pagingEnabled) {
views.roomListContainerPager.post {
try {
if (DEBUG_VIEW_PAGER) Timber.i("Home pager: set initial page $selectedIndex")
views.roomListContainerPager.setCurrentItem(selectedIndex ?: 0, false)
initialPageSelected = true
} catch (e: Exception) {
Timber.e("Home pager: Could not set initial page after creating adapter: $e")
}
}
}
}
private fun getPageIndexForSpaceId(spaceId: String?, spaces: List<String?>? = pagerSpaces): Int? {
if (spaceId == null) {
return 0
}
val indexInList = spaces?.indexOf(spaceId)
return when (indexInList) {
null, -1 -> null
else -> indexInList + 1
}
}
private fun getSpaceIdForPageIndex(position: Int, spaces: List<String?>? = pagerSpaces): String? {
val safeSpaces = spaces ?: return null
return if (position == 0) null else safeSpaces[position-1]
}
private fun createDialPadFragment(): Fragment { private fun createDialPadFragment(): Fragment {
val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name) val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name)

View file

@ -38,19 +38,26 @@ import im.vector.app.features.invite.showInvites
import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.ui.UiStateRepository import im.vector.app.features.ui.UiStateRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.ActiveSpaceFilter 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.RoomCategoryFilter
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.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.session.space.model.SpaceOrderContent
import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
@ -92,6 +99,7 @@ class HomeDetailViewModel @AssistedInject constructor(
observeRoomSummaries() observeRoomSummaries()
updatePstnSupportFlag() updatePstnSupportFlag()
observeDataStore() observeDataStore()
observeRootSpaces()
callManager.addProtocolsCheckerListener(this) callManager.addProtocolsCheckerListener(this)
session.flow().liveUser(session.myUserId).execute { session.flow().liveUser(session.myUserId).execute {
copy( copy(
@ -276,4 +284,46 @@ class HomeDetailViewModel @AssistedInject constructor(
} }
.launchIn(viewModelScope) .launchIn(viewModelScope)
} }
// Taken from SpaceListViewModel.observeSpaceSummaries()
private fun observeRootSpaces() {
val spaceSummaryQueryParams = roomSummaryQueryParams {
memberships = listOf(Membership.JOIN, Membership.INVITE)
displayName = QueryStringValue.IsNotEmpty
excludeType = listOf(/**RoomType.MESSAGING,$*/
null)
}
val flowSession = session.flow()
combine(
flowSession
.liveUser(session.myUserId)
.map {
it.getOrNull()
},
flowSession
.liveSpaceSummaries(spaceSummaryQueryParams),
session
.accountDataService()
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
.asFlow()
) { _, communityGroups, _ ->
communityGroups
}
.execute { //async ->
val rootSpaces = session.spaceService().getRootSpaceSummaries()
val orders = rootSpaces.map {
it.roomId to session.getRoom(it.roomId)
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
?.content.toModel<SpaceOrderContent>()
?.safeOrder()
}.toMap()
copy(
//asyncSpaces = async,
rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)),
//spaceOrderInfo = orders
)
}
}
} }

View file

@ -32,6 +32,7 @@ data class HomeDetailViewState(
val myMatrixItem: MatrixItem? = null, val myMatrixItem: MatrixItem? = null,
val asyncRooms: Async<List<RoomSummary>> = Uninitialized, val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
val currentTab: HomeTab = HomeTab.RoomList(RoomListDisplayMode.ALL), val currentTab: HomeTab = HomeTab.RoomList(RoomListDisplayMode.ALL),
val rootSpacesOrdered: List<RoomSummary>? = null,
val notificationCountCatchup: Int = 0, val notificationCountCatchup: Int = 0,
val notificationHighlightCatchup: Boolean = false, val notificationHighlightCatchup: Boolean = false,
val notificationCountPeople: Int = 0, val notificationCountPeople: Int = 0,

View file

@ -47,6 +47,7 @@ import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.databinding.FragmentRoomListBinding
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
import im.vector.app.features.home.room.list.RoomListSectionBuilderSpace.Companion.SPACE_ID_FOLLOW_APP
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
@ -66,7 +67,8 @@ import javax.inject.Inject
@Parcelize @Parcelize
data class RoomListParams( data class RoomListParams(
val displayMode: RoomListDisplayMode val displayMode: RoomListDisplayMode,
val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP
) : Parcelable ) : Parcelable
class RoomListFragment @Inject constructor( class RoomListFragment @Inject constructor(
@ -559,6 +561,9 @@ class RoomListFragment @Inject constructor(
} }
override fun onSwitchSpace(spaceId: String?) { override fun onSwitchSpace(spaceId: String?) {
if (roomListParams.explicitSpaceId == SPACE_ID_FOLLOW_APP) {
return
}
if (spaceId != expandStatusSpaceId) { if (spaceId != expandStatusSpaceId) {
persistExpandStatus() persistExpandStatus()
expandStatusSpaceId = spaceId expandStatusSpaceId = spaceId

View file

@ -19,5 +19,5 @@ package im.vector.app.features.home.room.list
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.RoomListDisplayMode
interface RoomListSectionBuilder { interface RoomListSectionBuilder {
fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection>
} }

View file

@ -47,7 +47,7 @@ class RoomListSectionBuilderGroup(
private val onUpdatable: (UpdatableLivePageResult) -> Unit private val onUpdatable: (UpdatableLivePageResult) -> Unit
) : RoomListSectionBuilder { ) : RoomListSectionBuilder {
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> { override fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection> {
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>() val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
val sections = mutableListOf<RoomsSection>() val sections = mutableListOf<RoomsSection>()
val actualGroupId = appStateHandler.safeActiveGroupId() val actualGroupId = appStateHandler.safeActiveGroupId()

View file

@ -49,6 +49,7 @@ 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.Membership
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
import timber.log.Timber import timber.log.Timber
import kotlin.math.exp
class RoomListSectionBuilderSpace( class RoomListSectionBuilderSpace(
private val session: Session, private val session: Session,
@ -61,6 +62,10 @@ class RoomListSectionBuilderSpace(
private val onlyOrphansInHome: Boolean = false private val onlyOrphansInHome: Boolean = false
) : RoomListSectionBuilder { ) : RoomListSectionBuilder {
companion object {
const val SPACE_ID_FOLLOW_APP = "de.spiritcroc.riotx.SPACE_ID_FOLLOW_APP"
}
private val pagedListConfig = PagedList.Config.Builder() private val pagedListConfig = PagedList.Config.Builder()
.setPageSize(10) .setPageSize(10)
.setInitialLoadSizeHint(20) .setInitialLoadSizeHint(20)
@ -68,20 +73,20 @@ class RoomListSectionBuilderSpace(
.setPrefetchDistance(10) .setPrefetchDistance(10)
.build() .build()
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> { override fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection> {
val sections = mutableListOf<RoomsSection>() val sections = mutableListOf<RoomsSection>()
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>() val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
when (mode) { when (mode) {
RoomListDisplayMode.PEOPLE -> { RoomListDisplayMode.PEOPLE -> {
// 4 sections Invites / Fav / Dms / Low Priority // 4 sections Invites / Fav / Dms / Low Priority
buildDmSections(sections, activeSpaceAwareQueries) buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId)
} }
RoomListDisplayMode.ROOMS -> { RoomListDisplayMode.ROOMS -> {
// 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms // 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms
buildRoomsSections(sections, activeSpaceAwareQueries) buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId)
} }
RoomListDisplayMode.ALL -> { RoomListDisplayMode.ALL -> {
buildUnifiedSections(sections, activeSpaceAwareQueries) buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId)
} }
RoomListDisplayMode.FILTERED -> { RoomListDisplayMode.FILTERED -> {
// Used when searching for rooms // Used when searching for rooms
@ -106,6 +111,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -123,6 +129,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.bottom_action_rooms, nameRes = R.string.bottom_action_rooms,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -135,24 +142,31 @@ class RoomListSectionBuilderSpace(
} }
} }
appStateHandler.selectedRoomGroupingObservable if (explicitSpaceId == SPACE_ID_FOLLOW_APP) {
.distinctUntilChanged() appStateHandler.selectedRoomGroupingObservable
.onEach { groupingMethod -> .distinctUntilChanged()
val selectedSpace = groupingMethod.orNull()?.space() .onEach { groupingMethod ->
activeSpaceAwareQueries.onEach { updater -> val selectedSpace = groupingMethod.orNull()?.space()
updater.updateForSpaceId(selectedSpace?.roomId) activeSpaceAwareQueries.onEach { updater ->
} updater.updateForSpaceId(selectedSpace?.roomId)
}.launchIn(viewModelScope) }
}.launchIn(viewModelScope)
} else {
activeSpaceAwareQueries.onEach { updater ->
updater.updateForSpaceId(explicitSpaceId)
}
}
return sections return sections
} }
private fun buildUnifiedSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) { private fun buildUnifiedSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, explicitSpaceId: String?) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
countRoomAsNotif = true countRoomAsNotif = true
) { ) {
@ -164,7 +178,8 @@ class RoomListSectionBuilderSpace(
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.bottom_action_favourites, R.string.bottom_action_favourites,
false, false,
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
explicitSpaceId = explicitSpaceId,
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null) it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
@ -175,6 +190,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.normal_priority_header, nameRes = R.string.normal_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -190,6 +206,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.low_priority_header, nameRes = R.string.low_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -205,6 +222,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.system_alerts_header, nameRes = R.string.system_alerts_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -215,17 +233,19 @@ class RoomListSectionBuilderSpace(
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true) it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
} }
addSuggestedRoomsSection(sections) addSuggestedRoomsSection(sections, explicitSpaceId)
} }
private fun buildRoomsSections(sections: MutableList<RoomsSection>, private fun buildRoomsSections(sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) { activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
explicitSpaceId: String?) {
if (autoAcceptInvites.showInvites()) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
countRoomAsNotif = true countRoomAsNotif = true
) { ) {
@ -239,7 +259,8 @@ class RoomListSectionBuilderSpace(
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.bottom_action_favourites, R.string.bottom_action_favourites,
false, false,
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
explicitSpaceId = explicitSpaceId,
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
@ -251,6 +272,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.bottom_action_rooms, nameRes = R.string.bottom_action_rooms,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -267,6 +289,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.low_priority_header, nameRes = R.string.low_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -283,6 +306,7 @@ class RoomListSectionBuilderSpace(
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.system_alerts_header, nameRes = R.string.system_alerts_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -294,12 +318,13 @@ class RoomListSectionBuilderSpace(
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true) it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
} }
addSuggestedRoomsSection(sections) addSuggestedRoomsSection(sections, explicitSpaceId)
} }
private fun addSuggestedRoomsSection(sections: MutableList<RoomsSection>) { private fun addSuggestedRoomsSection(sections: MutableList<RoomsSection>,
explicitSpaceId: String?) {
// add suggested rooms // add suggested rooms
val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>() val suggestedRoomsFlow = if (explicitSpaceId == SPACE_ID_FOLLOW_APP) { // MutableLiveData<List<SpaceChildInfo>>()
appStateHandler.selectedRoomGroupingObservable appStateHandler.selectedRoomGroupingObservable
.distinctUntilChanged() .distinctUntilChanged()
.flatMapLatest { groupingMethod -> .flatMapLatest { groupingMethod ->
@ -321,6 +346,24 @@ class RoomListSectionBuilderSpace(
}.asFlow() }.asFlow()
} }
} }
} else {
if (explicitSpaceId == null) {
flowOf(emptyList())
} else {
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
val spaceSum = tryOrNull {
session.spaceService()
.querySpaceChildren(explicitSpaceId, suggestedOnly = true, null, null)
}
val value = spaceSum?.children.orEmpty().distinctBy { it.childRoomId }
// i need to check if it's already joined.
val filtered = value.filter {
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
}
emit(filtered)
}.asFlow()
}
}
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>() val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
combine( combine(
@ -345,13 +388,15 @@ class RoomListSectionBuilderSpace(
} }
private fun buildDmSections(sections: MutableList<RoomsSection>, private fun buildDmSections(sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) { activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
explicitSpaceId: String?) {
if (autoAcceptInvites.showInvites()) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId,
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
countRoomAsNotif = true countRoomAsNotif = true
) { ) {
@ -365,7 +410,8 @@ class RoomListSectionBuilderSpace(
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.bottom_action_favourites, R.string.bottom_action_favourites,
false, false,
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
explicitSpaceId = explicitSpaceId
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -377,7 +423,8 @@ class RoomListSectionBuilderSpace(
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.bottom_action_people_x, R.string.bottom_action_people_x,
false, false,
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
explicitSpaceId = explicitSpaceId
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -389,7 +436,8 @@ class RoomListSectionBuilderSpace(
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.low_priority_header, R.string.low_priority_header,
false, false,
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
explicitSpaceId = explicitSpaceId
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -398,19 +446,28 @@ class RoomListSectionBuilderSpace(
} }
private fun AppStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId: String?): String? {
return if (explicitSpaceId == SPACE_ID_FOLLOW_APP) {
safeActiveSpaceId()
} else {
explicitSpaceId
}
}
private fun addSection(sections: MutableList<RoomsSection>, private fun addSection(sections: MutableList<RoomsSection>,
activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
@StringRes nameRes: Int, @StringRes nameRes: Int,
notifyOfLocalEcho: Boolean = false, notifyOfLocalEcho: Boolean = false,
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE, spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
countRoomAsNotif: Boolean = false, countRoomAsNotif: Boolean = false,
explicitSpaceId: String?,
query: (RoomSummaryQueryParams.Builder) -> Unit) { query: (RoomSummaryQueryParams.Builder) -> Unit) {
withQueryParams( withQueryParams(
{ query.invoke(it) }, { query.invoke(it) },
{ roomQueryParams -> { roomQueryParams ->
val name = stringProvider.getString(nameRes) val name = stringProvider.getString(nameRes)
session.getFilteredPagedRoomSummariesLive( session.getFilteredPagedRoomSummariesLive(
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()), roomQueryParams.process(spaceFilterStrategy, appStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId)),
pagedListConfig pagedListConfig
).also { ).also {
when (spaceFilterStrategy) { when (spaceFilterStrategy) {
@ -461,7 +518,7 @@ class RoomListSectionBuilderSpace(
RoomAggregateNotificationCount(it.size, it.size, 0) RoomAggregateNotificationCount(it.size, it.size, 0)
} else { } else {
session.getNotificationCountForRooms( session.getNotificationCountForRooms(
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()) roomQueryParams.process(spaceFilterStrategy, appStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId))
) )
} }
) )

View file

@ -146,7 +146,7 @@ class RoomListViewModel @AssistedInject constructor(
} }
val sections: List<RoomsSection> by lazy { val sections: List<RoomsSection> by lazy {
roomListSectionBuilder.buildSections(initialState.displayMode) roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId)
} }
override fun handle(action: RoomListAction) { override fun handle(action: RoomListAction) {

View file

@ -30,8 +30,10 @@ data class RoomListViewState(
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(), val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized, val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
val currentUserName: String? = null, val currentUserName: String? = null,
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized,
// In comparison to currentRoomGrouping, the explicit space id fixes a filter method that should not change afterwards
val explicitSpaceId: String? = null
) : MavericksState { ) : MavericksState {
constructor(args: RoomListParams) : this(displayMode = args.displayMode) constructor(args: RoomListParams) : this(displayMode = args.displayMode, explicitSpaceId = args.explicitSpaceId)
} }

View file

@ -214,6 +214,7 @@ class VectorPreferences @Inject constructor(private val context: Context): Stati
const val SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC = "SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC" const val SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC = "SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC"
private const val SETTINGS_JUMP_TO_BOTTOM_ON_SEND = "SETTINGS_JUMP_TO_BOTTOM_ON_SEND" private const val SETTINGS_JUMP_TO_BOTTOM_ON_SEND = "SETTINGS_JUMP_TO_BOTTOM_ON_SEND"
private const val SETTINGS_SPACE_MEMBERS_IN_SPACE_ROOMS = "SETTINGS_SPACE_MEMBERS_IN_SPACE_ROOMS" private const val SETTINGS_SPACE_MEMBERS_IN_SPACE_ROOMS = "SETTINGS_SPACE_MEMBERS_IN_SPACE_ROOMS"
private const val SETTINGS_ENABLE_SPACE_PAGER = "SETTINGS_ENABLE_SPACE_PAGER"
private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH" private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH"
private const val DID_PROMOTE_NEW_RESTRICTED_JOIN_RULE = "DID_PROMOTE_NEW_RESTRICTED_JOIN_RULE" private const val DID_PROMOTE_NEW_RESTRICTED_JOIN_RULE = "DID_PROMOTE_NEW_RESTRICTED_JOIN_RULE"
@ -1043,18 +1044,26 @@ class VectorPreferences @Inject constructor(private val context: Context): Stati
return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP && defaultPrefs.getBoolean(SETTINGS_VOICE_MESSAGE, true) return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP && defaultPrefs.getBoolean(SETTINGS_VOICE_MESSAGE, true)
} }
// SC addition
fun jumpToBottomOnSend(): Boolean { fun jumpToBottomOnSend(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_JUMP_TO_BOTTOM_ON_SEND, true) return defaultPrefs.getBoolean(SETTINGS_JUMP_TO_BOTTOM_ON_SEND, true)
} }
// SC addition
fun forceUseCustomUpGateway(): Boolean { fun forceUseCustomUpGateway(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, false) return defaultPrefs.getBoolean(SETTINGS_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, false)
} }
// SC addition
fun forceAllowBackgroundSync(): Boolean { fun forceAllowBackgroundSync(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC, false) return defaultPrefs.getBoolean(SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC, false)
} }
// SC addition
fun enableSpacePager(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_ENABLE_SPACE_PAGER, false)
}
/** /**
* I likely do more fresh installs of the app than anyone else, so a shortcut to change some of the default settings to * I likely do more fresh installs of the app than anyone else, so a shortcut to change some of the default settings to
* my preferred values can safe me some time * my preferred values can safe me some time
@ -1077,6 +1086,7 @@ class VectorPreferences @Inject constructor(private val context: Context): Stati
.putBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true) .putBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true)
.putBoolean(SETTINGS_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, true) .putBoolean(SETTINGS_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, true)
.putBoolean(SETTINGS_AGGREGATE_UNREAD_COUNTS, false) .putBoolean(SETTINGS_AGGREGATE_UNREAD_COUNTS, false)
.putBoolean(SETTINGS_ENABLE_SPACE_PAGER, true)
.apply() .apply()
} }

View file

@ -137,12 +137,21 @@
app:layout_constraintTop_toBottomOf="@id/syncStateView" app:layout_constraintTop_toBottomOf="@id/syncStateView"
tools:visibility="visible" /> tools:visibility="visible" />
<!--
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/roomListContainer" android:id="@+id/roomListContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView" app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintTop_toBottomOf="@+id/homeKeysBackupBanner" /> app:layout_constraintTop_toBottomOf="@+id/homeKeysBackupBanner" />
-->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/roomListContainerPager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintTop_toBottomOf="@+id/homeKeysBackupBanner" />
<com.google.android.material.bottomnavigation.BottomNavigationView <com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView" android:id="@+id/bottomNavigationView"

View file

@ -151,4 +151,7 @@
<string name="settings_include_space_members_as_rooms">Show people in spaces</string> <string name="settings_include_space_members_as_rooms">Show people in spaces</string>
<string name="settings_include_space_members_as_rooms_summary">If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you\'ll automatically see everyone who is a member of the Space.</string> <string name="settings_include_space_members_as_rooms_summary">If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you\'ll automatically see everyone who is a member of the Space.</string>
<string name="settings_enable_space_pager">Swipe chat list to switch space</string>
<string name="settings_enable_space_pager_summary">Allow to switch between root spaces by swiping horizontally in the chat list</string>
</resources> </resources>

View file

@ -74,6 +74,12 @@
android:key="SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB" android:key="SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB"
android:title="@string/labs_show_unread_notifications_as_tab" /> android:title="@string/labs_show_unread_notifications_as_tab" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_ENABLE_SPACE_PAGER"
android:title="@string/settings_enable_space_pager"
android:summary="@string/settings_enable_space_pager_summary" />
<im.vector.app.core.preference.VectorSwitchPreference <im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false" android:defaultValue="false"