mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-12-23 17:40:37 +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 androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import de.spiritcroc.viewpager.reduceDragSensitivity
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
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.toMvRxBundle
|
||||
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.home.room.list.RoomListFragment
|
||||
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.popup.PopupAlertManager
|
||||
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.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeDetailFragment @Inject constructor(
|
||||
|
@ -73,6 +77,10 @@ class HomeDetailFragment @Inject constructor(
|
|||
KeysBackupBanner.Delegate,
|
||||
CurrentCallsView.Callback {
|
||||
|
||||
companion object {
|
||||
const val DEBUG_VIEW_PAGER = true
|
||||
}
|
||||
|
||||
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel 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 onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -131,6 +145,29 @@ class HomeDetailFragment @Inject constructor(
|
|||
|
||||
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 ->
|
||||
when (roomGroupingMethod) {
|
||||
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
|
||||
.liveKnownCalls
|
||||
.observe(viewLifecycleOwner) {
|
||||
|
@ -438,12 +479,13 @@ class HomeDetailFragment @Inject constructor(
|
|||
private fun updateUIForTab(tab: HomeTab) {
|
||||
views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
|
||||
views.groupToolbarTitleView.setText(tab.titleRes)
|
||||
updateSelectedFragment(tab)
|
||||
//updateSelectedFragment(tab)
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
private fun HomeTab.toFragmentTag() = "FRAGMENT_TAG_$this"
|
||||
|
||||
/*
|
||||
private fun updateSelectedFragment(tab: HomeTab) {
|
||||
val fragmentTag = tab.toFragmentTag()
|
||||
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 {
|
||||
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.ui.UiStateRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
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.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.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.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.flow.flow
|
||||
import timber.log.Timber
|
||||
|
@ -92,6 +99,7 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
observeRoomSummaries()
|
||||
updatePstnSupportFlag()
|
||||
observeDataStore()
|
||||
observeRootSpaces()
|
||||
callManager.addProtocolsCheckerListener(this)
|
||||
session.flow().liveUser(session.myUserId).execute {
|
||||
copy(
|
||||
|
@ -276,4 +284,46 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
.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 asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val currentTab: HomeTab = HomeTab.RoomList(RoomListDisplayMode.ALL),
|
||||
val rootSpacesOrdered: List<RoomSummary>? = null,
|
||||
val notificationCountCatchup: Int = 0,
|
||||
val notificationHighlightCatchup: Boolean = false,
|
||||
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.features.home.RoomListDisplayMode
|
||||
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.RoomListQuickActionsBottomSheet
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
||||
|
@ -66,7 +67,8 @@ import javax.inject.Inject
|
|||
|
||||
@Parcelize
|
||||
data class RoomListParams(
|
||||
val displayMode: RoomListDisplayMode
|
||||
val displayMode: RoomListDisplayMode,
|
||||
val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP
|
||||
) : Parcelable
|
||||
|
||||
class RoomListFragment @Inject constructor(
|
||||
|
@ -559,6 +561,9 @@ class RoomListFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onSwitchSpace(spaceId: String?) {
|
||||
if (roomListParams.explicitSpaceId == SPACE_ID_FOLLOW_APP) {
|
||||
return
|
||||
}
|
||||
if (spaceId != expandStatusSpaceId) {
|
||||
persistExpandStatus()
|
||||
expandStatusSpaceId = spaceId
|
||||
|
|
|
@ -19,5 +19,5 @@ package im.vector.app.features.home.room.list
|
|||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
|
||||
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
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
override fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection> {
|
||||
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
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.summary.RoomAggregateNotificationCount
|
||||
import timber.log.Timber
|
||||
import kotlin.math.exp
|
||||
|
||||
class RoomListSectionBuilderSpace(
|
||||
private val session: Session,
|
||||
|
@ -61,6 +62,10 @@ class RoomListSectionBuilderSpace(
|
|||
private val onlyOrphansInHome: Boolean = false
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
companion object {
|
||||
const val SPACE_ID_FOLLOW_APP = "de.spiritcroc.riotx.SPACE_ID_FOLLOW_APP"
|
||||
}
|
||||
|
||||
private val pagedListConfig = PagedList.Config.Builder()
|
||||
.setPageSize(10)
|
||||
.setInitialLoadSizeHint(20)
|
||||
|
@ -68,20 +73,20 @@ class RoomListSectionBuilderSpace(
|
|||
.setPrefetchDistance(10)
|
||||
.build()
|
||||
|
||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
override fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection> {
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
|
||||
when (mode) {
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
// 4 sections Invites / Fav / Dms / Low Priority
|
||||
buildDmSections(sections, activeSpaceAwareQueries)
|
||||
buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId)
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
// 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms
|
||||
buildRoomsSections(sections, activeSpaceAwareQueries)
|
||||
buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId)
|
||||
}
|
||||
RoomListDisplayMode.ALL -> {
|
||||
buildUnifiedSections(sections, activeSpaceAwareQueries)
|
||||
buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId)
|
||||
}
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Used when searching for rooms
|
||||
|
@ -106,6 +111,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -123,6 +129,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -135,24 +142,31 @@ class RoomListSectionBuilderSpace(
|
|||
}
|
||||
}
|
||||
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.onEach { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.orNull()?.space()
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
if (explicitSpaceId == SPACE_ID_FOLLOW_APP) {
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.onEach { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.orNull()?.space()
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
} else {
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(explicitSpaceId)
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
|
@ -164,7 +178,8 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
|
@ -175,6 +190,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.normal_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -190,6 +206,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.low_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -205,6 +222,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.system_alerts_header,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -215,17 +233,19 @@ class RoomListSectionBuilderSpace(
|
|||
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
|
||||
}
|
||||
|
||||
addSuggestedRoomsSection(sections)
|
||||
addSuggestedRoomsSection(sections, explicitSpaceId)
|
||||
}
|
||||
|
||||
private fun buildRoomsSections(sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
|
||||
explicitSpaceId: String?) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
|
@ -239,7 +259,8 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -251,6 +272,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -267,6 +289,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.low_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -283,6 +306,7 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.system_alerts_header,
|
||||
notifyOfLocalEcho = false,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
|
@ -294,12 +318,13 @@ class RoomListSectionBuilderSpace(
|
|||
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
|
||||
val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>()
|
||||
val suggestedRoomsFlow = if (explicitSpaceId == SPACE_ID_FOLLOW_APP) { // MutableLiveData<List<SpaceChildInfo>>()
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { groupingMethod ->
|
||||
|
@ -321,6 +346,24 @@ class RoomListSectionBuilderSpace(
|
|||
}.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>()
|
||||
combine(
|
||||
|
@ -345,13 +388,15 @@ class RoomListSectionBuilderSpace(
|
|||
}
|
||||
|
||||
private fun buildDmSections(sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
|
||||
explicitSpaceId: String?) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
explicitSpaceId = explicitSpaceId,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
|
@ -365,7 +410,8 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
explicitSpaceId = explicitSpaceId
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
|
@ -377,7 +423,8 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_people_x,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
explicitSpaceId = explicitSpaceId
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
|
@ -389,7 +436,8 @@ class RoomListSectionBuilderSpace(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
explicitSpaceId = explicitSpaceId
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
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>,
|
||||
activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
|
||||
@StringRes nameRes: Int,
|
||||
notifyOfLocalEcho: Boolean = false,
|
||||
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
|
||||
countRoomAsNotif: Boolean = false,
|
||||
explicitSpaceId: String?,
|
||||
query: (RoomSummaryQueryParams.Builder) -> Unit) {
|
||||
withQueryParams(
|
||||
{ query.invoke(it) },
|
||||
{ roomQueryParams ->
|
||||
val name = stringProvider.getString(nameRes)
|
||||
session.getFilteredPagedRoomSummariesLive(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()),
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId)),
|
||||
pagedListConfig
|
||||
).also {
|
||||
when (spaceFilterStrategy) {
|
||||
|
@ -461,7 +518,7 @@ class RoomListSectionBuilderSpace(
|
|||
RoomAggregateNotificationCount(it.size, it.size, 0)
|
||||
} else {
|
||||
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 {
|
||||
roomListSectionBuilder.buildSections(initialState.displayMode)
|
||||
roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId)
|
||||
}
|
||||
|
||||
override fun handle(action: RoomListAction) {
|
||||
|
|
|
@ -30,8 +30,10 @@ data class RoomListViewState(
|
|||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
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 {
|
||||
|
||||
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"
|
||||
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_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_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)
|
||||
}
|
||||
|
||||
// SC addition
|
||||
fun jumpToBottomOnSend(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_JUMP_TO_BOTTOM_ON_SEND, true)
|
||||
}
|
||||
|
||||
// SC addition
|
||||
fun forceUseCustomUpGateway(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, false)
|
||||
}
|
||||
|
||||
// SC addition
|
||||
fun forceAllowBackgroundSync(): Boolean {
|
||||
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
|
||||
* 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_UNIFIED_PUSH_FORCE_CUSTOM_GATEWAY, true)
|
||||
.putBoolean(SETTINGS_AGGREGATE_UNREAD_COUNTS, false)
|
||||
.putBoolean(SETTINGS_ENABLE_SPACE_PAGER, true)
|
||||
.apply()
|
||||
}
|
||||
|
||||
|
|
|
@ -137,12 +137,21 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!--
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/roomListContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||
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
|
||||
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_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>
|
||||
|
|
|
@ -74,6 +74,12 @@
|
|||
android:key="SETTINGS_LABS_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
|
||||
android:defaultValue="false"
|
||||
|
|
Loading…
Reference in a new issue