mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-12-24 01:48:31 +03:00
Experimental: Swipe to switch between root spaces
Change-Id: I8849a4a2fd2cea0a7904f8c4259adf8c09f6864a
This commit is contained in:
parent
3eef15ae3e
commit
af0b3a8897
14 changed files with 355 additions and 34 deletions
22
vector/src/main/java/de/spiritcroc/viewpager/ViewPager2.kt
Normal file
22
vector/src/main/java/de/spiritcroc/viewpager/ViewPager2.kt
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue