ViewPager: never react to own space-changes

Change-Id: I45a1fd1e9ec6048dffdc4d54e8022d53afc627ff
This commit is contained in:
SpiritCroc 2022-03-31 09:12:28 +02:00
parent f50b21d9b7
commit e21f9443d5
4 changed files with 30 additions and 25 deletions

View file

@ -19,6 +19,7 @@ package im.vector.app
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import arrow.core.Option import arrow.core.Option
import arrow.core.getOrElse
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.utils.BehaviorDataSource import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.session.coroutineScope import im.vector.app.features.session.coroutineScope
@ -28,7 +29,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
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.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
@ -59,16 +62,21 @@ class AppStateHandler @Inject constructor(
) : DefaultLifecycleObserver { ) : DefaultLifecycleObserver {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomGroupingMethod>>(Option.empty()) ///private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomGroupingMethod>>(Option.empty())
val selectedRoomGroupingFlow = selectedSpaceDataSource.stream() // SchildiChat: the boolean means pendingSwipe and defaults to false. Set to true for swiping spaces, so you want to ignore updates which have pendingSwipe = true.
// Call it different then the upstream one so we don't forget adding `first` to upstream's logic.
private val selectedSpaceDataSourceSc = BehaviorDataSource<Option<Pair<RoomGroupingMethod, Boolean>>>(Option.empty())
val selectedRoomGroupingFlow = selectedSpaceDataSourceSc.stream().map { it.map { it.first } }
val selectedRoomGroupingFlowIgnoreSwipe = selectedSpaceDataSourceSc.stream().filter { it.getOrElse{ null }?.second != true }.map { it.map { it.first } }
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? { fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? {
// XXX we should somehow make it live :/ just a work around // XXX we should somehow make it live :/ just a work around
// For example just after creating a space and switching to it the // For example just after creating a space and switching to it the
// name in the app Bar could show Empty Room, and it will not update unless you // name in the app Bar could show Empty Room, and it will not update unless you
// switch space // switch space
return selectedSpaceDataSource.currentValue?.orNull()?.let { return selectedSpaceDataSourceSc.currentValue?.orNull()?.first?.let {
if (it is RoomGroupingMethod.BySpace) { if (it is RoomGroupingMethod.BySpace) {
// try to refresh sum? // try to refresh sum?
it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.getRoomSummary(it) }?.let { it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.getRoomSummary(it) }?.let {
@ -78,10 +86,10 @@ class AppStateHandler @Inject constructor(
} }
} }
fun setCurrentSpace(spaceId: String?, session: Session? = null, persistNow: Boolean = false) { fun setCurrentSpace(spaceId: String?, session: Session? = null, persistNow: Boolean = false, pendingSwipe: Boolean = false) {
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace && if (selectedSpaceDataSourceSc.currentValue?.orNull()?.first is RoomGroupingMethod.BySpace &&
spaceId == selectedSpaceDataSource.currentValue?.orNull()?.space()?.roomId) return spaceId == selectedSpaceDataSourceSc.currentValue?.orNull()?.first?.space()?.roomId) return
val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) } val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) }
if (persistNow) { if (persistNow) {
@ -89,7 +97,7 @@ class AppStateHandler @Inject constructor(
uiStateRepository.storeSelectedSpace(spaceSum?.roomId, uSession.sessionId) uiStateRepository.storeSelectedSpace(spaceSum?.roomId, uSession.sessionId)
} }
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.BySpace(spaceSum))) selectedSpaceDataSourceSc.post(Option.just(Pair(RoomGroupingMethod.BySpace(spaceSum), pendingSwipe)))
if (spaceId != null) { if (spaceId != null) {
uSession.coroutineScope.launch(Dispatchers.IO) { uSession.coroutineScope.launch(Dispatchers.IO) {
tryOrNull { tryOrNull {
@ -101,10 +109,10 @@ class AppStateHandler @Inject constructor(
fun setCurrentGroup(groupId: String?, session: Session? = null) { fun setCurrentGroup(groupId: String?, session: Session? = null) {
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.ByLegacyGroup && if (selectedSpaceDataSourceSc.currentValue?.orNull()?.first is RoomGroupingMethod.ByLegacyGroup &&
groupId == selectedSpaceDataSource.currentValue?.orNull()?.group()?.groupId) return groupId == selectedSpaceDataSourceSc.currentValue?.orNull()?.first?.group()?.groupId) return
val activeGroup = groupId?.let { uSession.getGroupSummary(groupId) } val activeGroup = groupId?.let { uSession.getGroupSummary(groupId) }
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.ByLegacyGroup(activeGroup))) selectedSpaceDataSourceSc.post(Option.just(Pair(RoomGroupingMethod.ByLegacyGroup(activeGroup), false)))
if (groupId != null) { if (groupId != null) {
uSession.coroutineScope.launch { uSession.coroutineScope.launch {
tryOrNull { tryOrNull {
@ -131,11 +139,11 @@ class AppStateHandler @Inject constructor(
} }
fun safeActiveSpaceId(): String? { fun safeActiveSpaceId(): String? {
return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId return (selectedSpaceDataSourceSc.currentValue?.orNull()?.first as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId
} }
fun safeActiveGroupId(): String? { fun safeActiveGroupId(): String? {
return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId return (selectedSpaceDataSourceSc.currentValue?.orNull()?.first as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
} }
override fun onResume(owner: LifecycleOwner) { override fun onResume(owner: LifecycleOwner) {
@ -145,7 +153,7 @@ class AppStateHandler @Inject constructor(
override fun onPause(owner: LifecycleOwner) { override fun onPause(owner: LifecycleOwner) {
coroutineScope.coroutineContext.cancelChildren() coroutineScope.coroutineContext.cancelChildren()
val session = activeSessionHolder.getSafeActiveSession() ?: return val session = activeSessionHolder.getSafeActiveSession() ?: return
when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) { when (val currentMethod = selectedSpaceDataSourceSc.currentValue?.orNull()?.first ?: RoomGroupingMethod.BySpace(null)) {
is RoomGroupingMethod.BySpace -> { is RoomGroupingMethod.BySpace -> {
uiStateRepository.storeGroupingMethod(true, session.sessionId) uiStateRepository.storeGroupingMethod(true, session.sessionId)
uiStateRepository.storeSelectedSpace(currentMethod.spaceSummary?.roomId, session.sessionId) uiStateRepository.storeSelectedSpace(currentMethod.spaceSummary?.roomId, session.sessionId)

View file

@ -105,7 +105,6 @@ class HomeDetailFragment @Inject constructor(
private var pagerSpaces: List<String?>? = null private var pagerSpaces: List<String?>? = null
private var pagerTab: HomeTab? = null private var pagerTab: HomeTab? = null
private var pagerPagingEnabled: Boolean = false private var pagerPagingEnabled: Boolean = false
private val pendingSpaceIds = mutableListOf<String?>()
override fun getMenuRes() = R.menu.room_list override fun getMenuRes() = R.menu.room_list
@ -163,8 +162,7 @@ class HomeDetailFragment @Inject constructor(
} }
} }
val selectedId = getSpaceIdForPageIndex(position) val selectedId = getSpaceIdForPageIndex(position)
pendingSpaceIds.add(selectedId) appStateHandler.setCurrentSpace(selectedId, pendingSwipe = true)
appStateHandler.setCurrentSpace(selectedId)
} }
}) })
@ -225,7 +223,7 @@ class HomeDetailFragment @Inject constructor(
) )
} }
viewModel.onEach(HomeDetailViewState::roomGroupingMethod, HomeDetailViewState::rootSpacesOrdered, HomeDetailViewState::currentTab) { roomGroupingMethod, rootSpacesOrdered, currentTab -> viewModel.onEach(HomeDetailViewState::roomGroupingMethodIgnoreSwipe, HomeDetailViewState::rootSpacesOrdered, HomeDetailViewState::currentTab) { roomGroupingMethod, rootSpacesOrdered, currentTab ->
setupViewPager(roomGroupingMethod, rootSpacesOrdered, currentTab) setupViewPager(roomGroupingMethod, rootSpacesOrdered, currentTab)
} }
@ -529,13 +527,6 @@ class HomeDetailFragment @Inject constructor(
if (!changed) { if (!changed) {
if (pagingEnabled) { if (pagingEnabled) {
// No need to re-setup pager, just check for selected page // 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 != null) {
if (selectedIndex != views.roomListContainerPager.currentItem) { if (selectedIndex != views.roomListContainerPager.currentItem) {
// post() mitigates a case where we could end up in an endless loop circling around the same few spaces // post() mitigates a case where we could end up in an endless loop circling around the same few spaces
@ -566,7 +557,6 @@ class HomeDetailFragment @Inject constructor(
pagerTab = tab pagerTab = tab
pagerPagingEnabled = pagingEnabled pagerPagingEnabled = pagingEnabled
initialPageSelected = false initialPageSelected = false
pendingSpaceIds.clear()
// OFFSCREEN_PAGE_LIMIT_DEFAULT: default recyclerview caching mechanism instead of explicit fixed prefetching // OFFSCREEN_PAGE_LIMIT_DEFAULT: default recyclerview caching mechanism instead of explicit fixed prefetching
//views.roomListContainerPager.offscreenPageLimit = 2 //views.roomListContainerPager.offscreenPageLimit = 2

View file

@ -212,6 +212,12 @@ class HomeDetailViewModel @AssistedInject constructor(
roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null) roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
) )
} }
appStateHandler.selectedRoomGroupingFlowIgnoreSwipe
.setOnEach {
copy(
roomGroupingMethodIgnoreSwipe = it.orNull() ?: RoomGroupingMethod.BySpace(null)
)
}
} }
private fun observeRoomSummaries() { private fun observeRoomSummaries() {

View file

@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.util.MatrixItem
data class HomeDetailViewState( data class HomeDetailViewState(
val roomGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null), val roomGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
val roomGroupingMethodIgnoreSwipe: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
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),