diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt index dcd4eec230..b8f90471e8 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 af050df995..53e2ebd1b5 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 6e2fdd1d6c..cb571da9d3 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 8fc53f07d4..647b31084e 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 7c4435bf59..47b0f23f44 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 9048026771..fdec36add0 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 f75c336b5d..ebdc9e72ac 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 2c52304249..bb05f4cb53 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 @@