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 getPersistedSpaceBackstack(): List<String?>
/**
* 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,
) {
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? {

View file

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

View file

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

View file

@ -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<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(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,
)
}

View file

@ -32,5 +32,6 @@ data class SpaceListViewState(
val spaceOrderInfo: Map<String, String?>? = null,
val spaceOrderLocalEchos: Map<String, String?>? = null,
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)
) : MavericksState

View file

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