Makes space bottom sheet header reflect backstack

This commit is contained in:
ericdecanini 2022-08-15 20:41:29 +02:00
parent 5012f37e6f
commit 894d4f700e
8 changed files with 76 additions and 17 deletions

View File

@ -57,6 +57,8 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
*/ */
fun popSpaceBackstack(): String? fun popSpaceBackstack(): String?
fun getPersistedSpaceBackstack(): List<String?>
/** /**
* Gets a flow of the selected space for clients to react immediately to space changes. * Gets a flow of the selected space for clients to react immediately to space changes.
*/ */

View File

@ -75,26 +75,28 @@ class SpaceStateHandlerImpl @Inject constructor(
isForwardNavigation: Boolean, isForwardNavigation: Boolean,
) { ) {
val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
val currentSpace = selectedSpaceDataSource.currentValue?.orNull() val spaceToLeave = selectedSpaceDataSource.currentValue?.orNull()
val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }
val sameSpaceSelected = spaceId == currentSpace?.roomId val sameSpaceSelected = spaceId == spaceToLeave?.roomId
if (sameSpaceSelected) { if (sameSpaceSelected) {
return return
} }
if (isForwardNavigation) { if (isForwardNavigation) {
addToBackstacks(currentSpace) addToBackstacks(spaceToLeave, spaceToSet)
} else {
popBackstackUntil(spaceToSet)
} }
if (persistNow) { if (persistNow) {
uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId) uiStateRepository.storeSelectedSpace(spaceToSet?.roomId, activeSession.sessionId)
} }
if (spaceSummary == null) { if (spaceToSet == null) {
selectedSpaceDataSource.post(Option.empty()) selectedSpaceDataSource.post(Option.empty())
} else { } else {
selectedSpaceDataSource.post(Option.just(spaceSummary)) selectedSpaceDataSource.post(Option.just(spaceToSet))
} }
if (spaceId != null) { 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 val spaceId = space?.roomId
spaceBackstack.addLast(spaceId) while (spaceBackstack.last() != spaceId) {
spaceBackstack.removeLast()
}
val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList() val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList()
currentPersistedBackstack.add(spaceId) while (currentPersistedBackstack.last() != spaceId) {
currentPersistedBackstack.removeLast()
}
vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack) vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack)
} }
@ -147,6 +166,8 @@ class SpaceStateHandlerImpl @Inject constructor(
return poppedSpaceId return poppedSpaceId
} }
override fun getPersistedSpaceBackstack() = vectorPreferences.getPersistedSpaceBackstack()
override fun getSelectedSpaceFlow() = selectedSpaceFlow override fun getSelectedSpaceFlow() = selectedSpaceFlow
override fun getSafeActiveSpaceId(): String? { override fun getSafeActiveSpaceId(): String? {

View File

@ -1121,7 +1121,7 @@ class VectorPreferences @Inject constructor(
* Only the IDs of the spaces are stored * Only the IDs of the spaces are stored
*/ */
fun setPersistedSpaceBackstack(spaceBackstack: List<String?>) { fun setPersistedSpaceBackstack(spaceBackstack: List<String?>) {
val spaceIdsJoined = spaceBackstack.joinToString(",") val spaceIdsJoined = spaceBackstack.takeIf { it.isNotEmpty() }?.joinToString(",")
defaultPrefs.edit().putString(SETTINGS_PERSISTED_SPACE_BACKSTACK, spaceIdsJoined).apply() defaultPrefs.edit().putString(SETTINGS_PERSISTED_SPACE_BACKSTACK, spaceIdsJoined).apply()
} }
@ -1130,7 +1130,7 @@ class VectorPreferences @Inject constructor(
*/ */
fun getPersistedSpaceBackstack(): List<String?> { fun getPersistedSpaceBackstack(): List<String?> {
val spaceIdsJoined = defaultPrefs.getString(SETTINGS_PERSISTED_SPACE_BACKSTACK, null) val spaceIdsJoined = defaultPrefs.getString(SETTINGS_PERSISTED_SPACE_BACKSTACK, null)
return spaceIdsJoined?.split(",").orEmpty() return spaceIdsJoined?.takeIf { it.isNotEmpty() }?.split(",").orEmpty()
} }
fun showLiveSenderInfo(): Boolean { fun showLiveSenderInfo(): Boolean {

View File

@ -16,6 +16,9 @@
package im.vector.app.features.spaces 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 com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyHolder
@ -23,5 +26,28 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
@EpoxyModelClass @EpoxyModelClass
abstract class NewSpaceListHeaderItem : VectorEpoxyModel<NewSpaceListHeaderItem.Holder>(R.layout.item_new_space_list_header) { abstract class NewSpaceListHeaderItem : VectorEpoxyModel<NewSpaceListHeaderItem.Holder>(R.layout.item_new_space_list_header) {
class Holder : VectorEpoxyHolder()
@EpoxyAttribute var currentSpace: String? = null
@EpoxyAttribute var spaceHistory: List<Pair<String?, String>> = 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<TextView>(R.id.space_header)
}
} }

View File

@ -50,7 +50,8 @@ class NewSpaceSummaryController @Inject constructor(
nonNullViewState.spaces, nonNullViewState.spaces,
nonNullViewState.selectedSpace, nonNullViewState.selectedSpace,
nonNullViewState.rootSpacesOrdered, nonNullViewState.rootSpacesOrdered,
nonNullViewState.homeAggregateCount nonNullViewState.homeAggregateCount,
nonNullViewState.spaceHistory,
) )
} }
@ -58,11 +59,15 @@ class NewSpaceSummaryController @Inject constructor(
spaceSummaries: List<RoomSummary>?, spaceSummaries: List<RoomSummary>?,
selectedSpace: RoomSummary?, selectedSpace: RoomSummary?,
rootSpaces: List<RoomSummary>?, rootSpaces: List<RoomSummary>?,
homeCount: RoomAggregateNotificationCount homeCount: RoomAggregateNotificationCount,
spaceHistory: List<Pair<String?, String>>,
) { ) {
val host = this val host = this
newSpaceListHeaderItem { newSpaceListHeaderItem {
id("space_list_header") id("space_list_header")
currentSpace(selectedSpace?.displayName)
spaceHistory(spaceHistory)
} }
if (selectedSpace != null) { if (selectedSpace != null) {

View File

@ -65,7 +65,7 @@ class SpaceListViewModel @AssistedInject constructor(
private val session: Session, private val session: Session,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val autoAcceptInvites: AutoAcceptInvites, private val autoAcceptInvites: AutoAcceptInvites,
private val analyticsTracker: AnalyticsTracker private val analyticsTracker: AnalyticsTracker,
) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) { ) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
@AssistedFactory @AssistedFactory
@ -85,11 +85,14 @@ class SpaceListViewModel @AssistedInject constructor(
} }
observeSpaceSummaries() observeSpaceSummaries()
val spaceHistory = spaceStateHandler.getPersistedSpaceBackstack()
.map { it to it?.let { session.roomService().getRoomSummary(it)?.displayName }.orEmpty() }
spaceStateHandler.getSelectedSpaceFlow() spaceStateHandler.getSelectedSpaceFlow()
.distinctUntilChanged() .distinctUntilChanged()
.setOnEach { selectedSpaceOption -> .setOnEach { selectedSpaceOption ->
copy( copy(
selectedSpace = selectedSpaceOption.orNull() selectedSpace = selectedSpaceOption.orNull(),
spaceHistory = spaceHistory,
) )
} }

View File

@ -32,5 +32,6 @@ data class SpaceListViewState(
val spaceOrderInfo: Map<String, String?>? = null, val spaceOrderInfo: Map<String, String?>? = null,
val spaceOrderLocalEchos: Map<String, String?>? = null, val spaceOrderLocalEchos: Map<String, String?>? = null,
val expandedStates: Map<String, Boolean> = emptyMap(), val expandedStates: Map<String, Boolean> = emptyMap(),
val spaceHistory: List<Pair<String?, String>> = emptyList(), // List of space id to display name
val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0) val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
) : MavericksState ) : MavericksState

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" <TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/space_header"
style="@style/TextAppearance.Vector.Body.Medium" style="@style/TextAppearance.Vector.Body.Medium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"