From d8115a79a4c57172db6757700472eda8ee72eede Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 12 Aug 2022 11:17:13 +0200 Subject: [PATCH 1/6] Adds persisted backstack --- .../im/vector/app/SpaceStateHandlerImpl.kt | 19 +++++++++++++++-- .../features/settings/VectorPreferences.kt | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index c6a4b2c5f03..a8739bfd0ff 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -23,6 +23,7 @@ import im.vector.app.core.utils.BehaviorDataSource import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.plan.UserProperties import im.vector.app.features.session.coroutineScope +import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -52,7 +53,8 @@ class SpaceStateHandlerImpl @Inject constructor( private val sessionDataSource: ActiveSessionDataSource, private val uiStateRepository: UiStateRepository, private val activeSessionHolder: ActiveSessionHolder, - private val analyticsTracker: AnalyticsTracker + private val analyticsTracker: AnalyticsTracker, + private val vectorPreferences: VectorPreferences, ) : SpaceStateHandler { private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) @@ -82,7 +84,7 @@ class SpaceStateHandlerImpl @Inject constructor( } if (isForwardNavigation) { - spaceBackstack.addLast(currentSpace?.roomId) + addToBackstacks(spaceSummary) } if (persistNow) { @@ -104,6 +106,15 @@ class SpaceStateHandlerImpl @Inject constructor( } } + private fun addToBackstacks(space: RoomSummary?) { + val spaceId = space?.roomId ?: ROOT_SPACE_ID + spaceBackstack.addLast(spaceId) + + val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() + currentPersistedBackstack.add(spaceId) + vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) + } + private fun observeActiveSession() { sessionDataSource.stream() .distinctUntilChanged() @@ -144,4 +155,8 @@ class SpaceStateHandlerImpl @Inject constructor( val session = activeSessionHolder.getSafeActiveSession() ?: return uiStateRepository.storeSelectedSpace(selectedSpaceDataSource.currentValue?.orNull()?.roomId, session.sessionId) } + + companion object { + private const val ROOT_SPACE_ID = "ROOT" + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index ac14bfc3c7f..0a99cffe475 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -25,6 +25,7 @@ import androidx.core.content.edit import com.squareup.seismic.ShakeDetector import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.extensions.join import im.vector.app.core.resources.BuildMeta import im.vector.app.core.time.Clock import im.vector.app.features.disclaimer.SHARED_PREF_KEY @@ -77,6 +78,7 @@ class VectorPreferences @Inject constructor( const val SETTINGS_ALLOW_INTEGRATIONS_KEY = "SETTINGS_ALLOW_INTEGRATIONS_KEY" const val SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY = "SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY" const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY" + const val SETTINGS_PERSISTED_SPACE_BACKSTACK = "SETTINGS_PERSISTED_SPACE_BACKSTACK" const val SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT = "SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT" // const val SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY = "SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY" @@ -1113,6 +1115,25 @@ class VectorPreferences @Inject constructor( .apply() } + /** + * Sets the space backstack that is used for up navigation + * This needs to be persisted because navigating up through spaces should work across sessions + * + * Only the IDs of the spaces are stored + */ + fun setPersistedSpaceBackstack(spaceBackstack: List) { + val spaceIdsJoined = spaceBackstack.joinToString(",") + defaultPrefs.edit().putString(SETTINGS_PERSISTED_SPACE_BACKSTACK, spaceIdsJoined).apply() + } + + /** + * Gets the space backstack used for up navigation + */ + fun getPersistedSpaceBackstack(): List { + val spaceIdsJoined = defaultPrefs.getString(SETTINGS_PERSISTED_SPACE_BACKSTACK, null) + return spaceIdsJoined?.split(",").orEmpty() + } + fun showLiveSenderInfo(): Boolean { return defaultPrefs.getBoolean(SETTINGS_TIMELINE_SHOW_LIVE_SENDER_INFO, getDefault(R.bool.settings_timeline_show_live_sender_info_default)) } From 7ee58ccc88184daa88d70204bdb337711b452442 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 12 Aug 2022 13:18:26 +0200 Subject: [PATCH 2/6] Fixes back navigation --- .../im/vector/app/SpaceStateHandlerImpl.kt | 10 +++------- .../app/features/home/NewHomeDetailFragment.kt | 18 ++++++++++-------- .../app/features/settings/VectorPreferences.kt | 5 ++--- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index a8739bfd0ff..800b3f9589d 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -77,14 +77,14 @@ class SpaceStateHandlerImpl @Inject constructor( val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val currentSpace = selectedSpaceDataSource.currentValue?.orNull() val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } - val sameSpaceSelected = currentSpace != null && spaceId == currentSpace.roomId + val sameSpaceSelected = spaceId == currentSpace?.roomId if (sameSpaceSelected) { return } if (isForwardNavigation) { - addToBackstacks(spaceSummary) + addToBackstacks(currentSpace) } if (persistNow) { @@ -107,7 +107,7 @@ class SpaceStateHandlerImpl @Inject constructor( } private fun addToBackstacks(space: RoomSummary?) { - val spaceId = space?.roomId ?: ROOT_SPACE_ID + val spaceId = space?.roomId spaceBackstack.addLast(spaceId) val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() @@ -155,8 +155,4 @@ class SpaceStateHandlerImpl @Inject constructor( val session = activeSessionHolder.getSafeActiveSession() ?: return uiStateRepository.storeSelectedSpace(selectedSpaceDataSource.currentValue?.orNull()?.roomId, session.sessionId) } - - companion object { - private const val ROOT_SPACE_ID = "ROOT" - } } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 4766cd5006a..16600abea56 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -178,14 +178,18 @@ class NewHomeDetailFragment @Inject constructor( } private fun navigateBack() { - val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull() - val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() - setCurrentSpace(previousSpaceId ?: parentSpaceId) + val spaceBackstack = spaceStateHandler.getSpaceBackstack() + + try { + val previousSpaceId = spaceBackstack.removeLast() + setCurrentSpace(previousSpaceId) + } catch (e: NoSuchElementException) { + requireActivity().finish() + } } private fun setCurrentSpace(spaceId: String?) { spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) - sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace) } private fun handleCallStarted() { @@ -452,10 +456,8 @@ class NewHomeDetailFragment @Inject constructor( return this } - override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) { + override fun onBackPressed(toolbarButton: Boolean): Boolean { navigateBack() - true - } else { - false + return true } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 0a99cffe475..6e2fdd1d6c6 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -25,7 +25,6 @@ import androidx.core.content.edit import com.squareup.seismic.ShakeDetector import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences -import im.vector.app.core.extensions.join import im.vector.app.core.resources.BuildMeta import im.vector.app.core.time.Clock import im.vector.app.features.disclaimer.SHARED_PREF_KEY @@ -1121,7 +1120,7 @@ class VectorPreferences @Inject constructor( * * Only the IDs of the spaces are stored */ - fun setPersistedSpaceBackstack(spaceBackstack: List) { + fun setPersistedSpaceBackstack(spaceBackstack: List) { val spaceIdsJoined = spaceBackstack.joinToString(",") defaultPrefs.edit().putString(SETTINGS_PERSISTED_SPACE_BACKSTACK, spaceIdsJoined).apply() } @@ -1129,7 +1128,7 @@ class VectorPreferences @Inject constructor( /** * Gets the space backstack used for up navigation */ - fun getPersistedSpaceBackstack(): List { + fun getPersistedSpaceBackstack(): List { val spaceIdsJoined = defaultPrefs.getString(SETTINGS_PERSISTED_SPACE_BACKSTACK, null) return spaceIdsJoined?.split(",").orEmpty() } From 5012f37e6f0453ee0dd6dee6aa1427757b1938b9 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 12 Aug 2022 13:28:01 +0200 Subject: [PATCH 3/6] Refactors space backstack handling --- vector/src/main/java/im/vector/app/SpaceStateHandler.kt | 6 +++--- .../src/main/java/im/vector/app/SpaceStateHandlerImpl.kt | 9 ++++++++- .../im/vector/app/features/home/HomeDetailFragment.kt | 2 +- .../im/vector/app/features/home/NewHomeDetailFragment.kt | 4 +--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt index d9f002be37f..dcd4eec2304 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt @@ -51,11 +51,11 @@ interface SpaceStateHandler : DefaultLifecycleObserver { ) /** - * Gets the current backstack of spaces (via their id). + * Gets the Space ID of the space on top of the backstack * - * null may be an entry in the ArrayDeque to indicate the root space (All Chats) + * May return null to indicate the All Chats space */ - fun getSpaceBackstack(): ArrayDeque + fun popSpaceBackstack(): String? /** * Gets a flow of the selected space for clients to react immediately to space changes. diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index 800b3f9589d..af050df995c 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -138,7 +138,14 @@ class SpaceStateHandlerImpl @Inject constructor( }.launchIn(session.coroutineScope) } - override fun getSpaceBackstack() = spaceBackstack + override fun popSpaceBackstack(): String? { + val poppedSpaceId = spaceBackstack.removeLast() + vectorPreferences.getPersistedSpaceBackstack().toMutableList().apply { + removeLast() + vectorPreferences.setPersistedSpaceBackstack(this) + } + return poppedSpaceId + } override fun getSelectedSpaceFlow() = selectedSpaceFlow diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index d4c89c1bcae..e4a572e2a03 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -183,7 +183,7 @@ class HomeDetailFragment @Inject constructor( } private fun navigateBack() { - val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull() + val previousSpaceId = spaceStateHandler.popSpaceBackstack() val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() setCurrentSpace(previousSpaceId ?: parentSpaceId) } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 16600abea56..09617a8dd8e 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -178,10 +178,8 @@ class NewHomeDetailFragment @Inject constructor( } private fun navigateBack() { - val spaceBackstack = spaceStateHandler.getSpaceBackstack() - try { - val previousSpaceId = spaceBackstack.removeLast() + val previousSpaceId = spaceStateHandler.popSpaceBackstack() setCurrentSpace(previousSpaceId) } catch (e: NoSuchElementException) { requireActivity().finish() From 894d4f700ea056327f49a8e92e6960bbaed259af Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Mon, 15 Aug 2022 20:41:29 +0200 Subject: [PATCH 4/6] Makes space bottom sheet header reflect backstack --- .../java/im/vector/app/SpaceStateHandler.kt | 2 + .../im/vector/app/SpaceStateHandlerImpl.kt | 41 ++++++++++++++----- .../features/settings/VectorPreferences.kt | 4 +- .../features/spaces/NewSpaceListHeaderItem.kt | 28 ++++++++++++- .../spaces/NewSpaceSummaryController.kt | 9 +++- .../app/features/spaces/SpaceListViewModel.kt | 7 +++- .../app/features/spaces/SpaceListViewState.kt | 1 + .../res/layout/item_new_space_list_header.xml | 1 + 8 files changed, 76 insertions(+), 17 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt index dcd4eec2304..b8f90471e8d 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt @@ -57,6 +57,8 @@ interface SpaceStateHandler : DefaultLifecycleObserver { */ fun popSpaceBackstack(): String? + fun getPersistedSpaceBackstack(): List + /** * Gets a flow of the selected space for clients to react immediately to space changes. */ diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index af050df995c..53e2ebd1b54 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -75,26 +75,28 @@ class SpaceStateHandlerImpl @Inject constructor( isForwardNavigation: Boolean, ) { val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return - val currentSpace = selectedSpaceDataSource.currentValue?.orNull() - val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } - val sameSpaceSelected = spaceId == currentSpace?.roomId + val spaceToLeave = selectedSpaceDataSource.currentValue?.orNull() + val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) } + val sameSpaceSelected = spaceId == spaceToLeave?.roomId if (sameSpaceSelected) { return } if (isForwardNavigation) { - addToBackstacks(currentSpace) + addToBackstacks(spaceToLeave, spaceToSet) + } else { + popBackstackUntil(spaceToSet) } if (persistNow) { - uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId) + uiStateRepository.storeSelectedSpace(spaceToSet?.roomId, activeSession.sessionId) } - if (spaceSummary == null) { + if (spaceToSet == null) { selectedSpaceDataSource.post(Option.empty()) } else { - selectedSpaceDataSource.post(Option.just(spaceSummary)) + selectedSpaceDataSource.post(Option.just(spaceToSet)) } if (spaceId != null) { @@ -106,12 +108,29 @@ class SpaceStateHandlerImpl @Inject constructor( } } - private fun addToBackstacks(space: RoomSummary?) { + private fun addToBackstacks(spaceToLeave: RoomSummary?, spaceToSet: RoomSummary?) { + spaceBackstack.addLast(spaceToLeave?.roomId) + + // Only add to the persisted backstack if the space to set is not All Chats, else reset the persisted stack + if (spaceToSet != null && spaceToLeave != null) { + val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() + currentPersistedBackstack.add(spaceToLeave.roomId) + vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) + } else if (spaceToSet == null) { + vectorPreferences.setPersistedSpaceBackstack(emptyList()) + } + } + + private fun popBackstackUntil(space: RoomSummary?) { val spaceId = space?.roomId - spaceBackstack.addLast(spaceId) + while (spaceBackstack.last() != spaceId) { + spaceBackstack.removeLast() + } val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() - currentPersistedBackstack.add(spaceId) + while (currentPersistedBackstack.last() != spaceId) { + currentPersistedBackstack.removeLast() + } vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) } @@ -147,6 +166,8 @@ class SpaceStateHandlerImpl @Inject constructor( return poppedSpaceId } + override fun getPersistedSpaceBackstack() = vectorPreferences.getPersistedSpaceBackstack() + override fun getSelectedSpaceFlow() = selectedSpaceFlow override fun getSafeActiveSpaceId(): String? { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 6e2fdd1d6c6..cb571da9d3f 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -1121,7 +1121,7 @@ class VectorPreferences @Inject constructor( * Only the IDs of the spaces are stored */ fun setPersistedSpaceBackstack(spaceBackstack: List) { - val spaceIdsJoined = spaceBackstack.joinToString(",") + val spaceIdsJoined = spaceBackstack.takeIf { it.isNotEmpty() }?.joinToString(",") defaultPrefs.edit().putString(SETTINGS_PERSISTED_SPACE_BACKSTACK, spaceIdsJoined).apply() } @@ -1130,7 +1130,7 @@ class VectorPreferences @Inject constructor( */ fun getPersistedSpaceBackstack(): List { val spaceIdsJoined = defaultPrefs.getString(SETTINGS_PERSISTED_SPACE_BACKSTACK, null) - return spaceIdsJoined?.split(",").orEmpty() + return spaceIdsJoined?.takeIf { it.isNotEmpty() }?.split(",").orEmpty() } fun showLiveSenderInfo(): Boolean { diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt index 8fc53f07d47..647b31084e7 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt @@ -16,6 +16,9 @@ package im.vector.app.features.spaces +import android.content.Context +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyHolder @@ -23,5 +26,28 @@ import im.vector.app.core.epoxy.VectorEpoxyModel @EpoxyModelClass abstract class NewSpaceListHeaderItem : VectorEpoxyModel(R.layout.item_new_space_list_header) { - class Holder : VectorEpoxyHolder() + + @EpoxyAttribute var currentSpace: String? = null + @EpoxyAttribute var spaceHistory: List> = emptyList() + + override fun bind(holder: Holder) { + super.bind(holder) + holder.spaceHeader.text = buildSpaceHeaderText(holder.spaceHeader.context) + } + + private fun buildSpaceHeaderText(context: Context): String { + val allChats = context.getString(R.string.all_chats) + var spaceHeaderText = allChats + if (spaceHistory.isNotEmpty()) { + spaceHeaderText += " > ${spaceHistory.joinToString(" > ") { it.second }}" + } + if (currentSpace != null) { + spaceHeaderText += " > $currentSpace" + } + return spaceHeaderText + } + + class Holder : VectorEpoxyHolder() { + val spaceHeader by bind(R.id.space_header) + } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt index 7c4435bf591..47b0f23f44a 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -50,7 +50,8 @@ class NewSpaceSummaryController @Inject constructor( nonNullViewState.spaces, nonNullViewState.selectedSpace, nonNullViewState.rootSpacesOrdered, - nonNullViewState.homeAggregateCount + nonNullViewState.homeAggregateCount, + nonNullViewState.spaceHistory, ) } @@ -58,11 +59,15 @@ class NewSpaceSummaryController @Inject constructor( spaceSummaries: List?, selectedSpace: RoomSummary?, rootSpaces: List?, - homeCount: RoomAggregateNotificationCount + homeCount: RoomAggregateNotificationCount, + spaceHistory: List>, ) { val host = this + newSpaceListHeaderItem { id("space_list_header") + currentSpace(selectedSpace?.displayName) + spaceHistory(spaceHistory) } if (selectedSpace != null) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt index 9048026771c..fdec36add08 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt @@ -65,7 +65,7 @@ class SpaceListViewModel @AssistedInject constructor( private val session: Session, private val vectorPreferences: VectorPreferences, private val autoAcceptInvites: AutoAcceptInvites, - private val analyticsTracker: AnalyticsTracker + private val analyticsTracker: AnalyticsTracker, ) : VectorViewModel(initialState) { @AssistedFactory @@ -85,11 +85,14 @@ class SpaceListViewModel @AssistedInject constructor( } observeSpaceSummaries() + val spaceHistory = spaceStateHandler.getPersistedSpaceBackstack() + .map { it to it?.let { session.roomService().getRoomSummary(it)?.displayName }.orEmpty() } spaceStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .setOnEach { selectedSpaceOption -> copy( - selectedSpace = selectedSpaceOption.orNull() + selectedSpace = selectedSpaceOption.orNull(), + spaceHistory = spaceHistory, ) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt index f75c336b5de..ebdc9e72ac8 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt @@ -32,5 +32,6 @@ data class SpaceListViewState( val spaceOrderInfo: Map? = null, val spaceOrderLocalEchos: Map? = null, val expandedStates: Map = emptyMap(), + val spaceHistory: List> = emptyList(), // List of space id to display name val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0) ) : MavericksState diff --git a/vector/src/main/res/layout/item_new_space_list_header.xml b/vector/src/main/res/layout/item_new_space_list_header.xml index 2c52304249e..bb05f4cb536 100644 --- a/vector/src/main/res/layout/item_new_space_list_header.xml +++ b/vector/src/main/res/layout/item_new_space_list_header.xml @@ -1,6 +1,7 @@ Date: Tue, 16 Aug 2022 10:59:32 +0200 Subject: [PATCH 5/6] Adds working back navigation --- .../im/vector/app/SpaceStateHandlerImpl.kt | 17 +------------- .../features/home/NewHomeDetailFragment.kt | 23 +++++-------------- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index 53e2ebd1b54..6c70c3266ad 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -85,8 +85,6 @@ class SpaceStateHandlerImpl @Inject constructor( if (isForwardNavigation) { addToBackstacks(spaceToLeave, spaceToSet) - } else { - popBackstackUntil(spaceToSet) } if (persistNow) { @@ -121,19 +119,6 @@ class SpaceStateHandlerImpl @Inject constructor( } } - private fun popBackstackUntil(space: RoomSummary?) { - val spaceId = space?.roomId - while (spaceBackstack.last() != spaceId) { - spaceBackstack.removeLast() - } - - val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() - while (currentPersistedBackstack.last() != spaceId) { - currentPersistedBackstack.removeLast() - } - vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) - } - private fun observeActiveSession() { sessionDataSource.stream() .distinctUntilChanged() @@ -160,7 +145,7 @@ class SpaceStateHandlerImpl @Inject constructor( override fun popSpaceBackstack(): String? { val poppedSpaceId = spaceBackstack.removeLast() vectorPreferences.getPersistedSpaceBackstack().toMutableList().apply { - removeLast() + removeLastOrNull() vectorPreferences.setPersistedSpaceBackstack(this) } return poppedSpaceId diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 09617a8dd8e..4e429c4bf95 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -79,7 +79,6 @@ class NewHomeDetailFragment @Inject constructor( private val viewModel: HomeDetailViewModel by fragmentViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() - private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel() private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel() private lateinit var sharedActionViewModel: HomeSharedActionViewModel @@ -177,19 +176,6 @@ class NewHomeDetailFragment @Inject constructor( } } - private fun navigateBack() { - try { - val previousSpaceId = spaceStateHandler.popSpaceBackstack() - setCurrentSpace(previousSpaceId) - } catch (e: NoSuchElementException) { - requireActivity().finish() - } - } - - private fun setCurrentSpace(spaceId: String?) { - spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) - } - private fun handleCallStarted() { dismissLoadingDialog() val fragmentTag = HomeTab.DialPad.toFragmentTag() @@ -454,8 +440,11 @@ class NewHomeDetailFragment @Inject constructor( return this } - override fun onBackPressed(toolbarButton: Boolean): Boolean { - navigateBack() - return true + override fun onBackPressed(toolbarButton: Boolean) = try { + val lastSpace = spaceStateHandler.popSpaceBackstack() + spaceStateHandler.setCurrentSpace(lastSpace, isForwardNavigation = false) + true + } catch (e: NoSuchElementException) { + false } } From fc301c8a2e956c63d3e3b4c84b53fa50d8d42fdc Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 16 Aug 2022 11:50:15 +0200 Subject: [PATCH 6/6] Unifies back and persisted navigation --- .../im/vector/app/SpaceStateHandlerImpl.kt | 18 +++++++----------- .../features/spaces/NewSpaceListHeaderItem.kt | 7 +++++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index 6c70c3266ad..c36b6de17b2 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -60,7 +60,6 @@ class SpaceStateHandlerImpl @Inject constructor( private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val selectedSpaceDataSource = BehaviorDataSource>(Option.empty()) private val selectedSpaceFlow = selectedSpaceDataSource.stream() - private val spaceBackstack = ArrayDeque() override fun getCurrentSpace(): RoomSummary? { return selectedSpaceDataSource.currentValue?.orNull()?.let { spaceSummary -> @@ -84,7 +83,7 @@ class SpaceStateHandlerImpl @Inject constructor( } if (isForwardNavigation) { - addToBackstacks(spaceToLeave, spaceToSet) + addToBackstack(spaceToLeave, spaceToSet) } if (persistNow) { @@ -106,15 +105,13 @@ class SpaceStateHandlerImpl @Inject constructor( } } - private fun addToBackstacks(spaceToLeave: RoomSummary?, spaceToSet: RoomSummary?) { - spaceBackstack.addLast(spaceToLeave?.roomId) - + private fun addToBackstack(spaceToLeave: RoomSummary?, spaceToSet: RoomSummary?) { // Only add to the persisted backstack if the space to set is not All Chats, else reset the persisted stack - if (spaceToSet != null && spaceToLeave != null) { + if (spaceToSet != null) { val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() - currentPersistedBackstack.add(spaceToLeave.roomId) + currentPersistedBackstack.add(spaceToLeave?.roomId) vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) - } else if (spaceToSet == null) { + } else { vectorPreferences.setPersistedSpaceBackstack(emptyList()) } } @@ -143,12 +140,11 @@ class SpaceStateHandlerImpl @Inject constructor( } override fun popSpaceBackstack(): String? { - val poppedSpaceId = spaceBackstack.removeLast() vectorPreferences.getPersistedSpaceBackstack().toMutableList().apply { - removeLastOrNull() + val poppedSpaceId = removeLast() vectorPreferences.setPersistedSpaceBackstack(this) + return poppedSpaceId } - return poppedSpaceId } override fun getPersistedSpaceBackstack() = vectorPreferences.getPersistedSpaceBackstack() diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt index 647b31084e7..29538be16ea 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt @@ -38,8 +38,11 @@ abstract class NewSpaceListHeaderItem : VectorEpoxyModel ") { it.second }}" + + val nonRootSpaceHistory = spaceHistory.filter { it.second.isNotEmpty() } + + if (nonRootSpaceHistory.isNotEmpty()) { + spaceHeaderText += " > ${nonRootSpaceHistory.joinToString(" > ") { it.second }}" } if (currentSpace != null) { spaceHeaderText += " > $currentSpace"