Skip to content

Commit 1ce81cb

Browse files
committed
Multi accounts - swipe on account icon
1 parent 9333339 commit 1ce81cb

File tree

6 files changed

+171
-20
lines changed

6 files changed

+171
-20
lines changed

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeEvents.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
package io.element.android.features.home.impl
99

10+
import io.element.android.libraries.matrix.api.core.SessionId
11+
1012
sealed interface HomeEvents {
1113
data class SelectHomeNavigationBarItem(val item: HomeNavigationBarItem) : HomeEvents
14+
data class SwitchToAccount(val sessionId: SessionId) : HomeEvents
1215
}

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomePresenter.kt

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.runtime.derivedStateOf
1414
import androidx.compose.runtime.getValue
1515
import androidx.compose.runtime.mutableIntStateOf
1616
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.rememberCoroutineScope
1718
import androidx.compose.runtime.saveable.rememberSaveable
1819
import androidx.compose.runtime.setValue
1920
import dev.zacsweers.metro.Inject
@@ -27,8 +28,15 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService
2728
import io.element.android.libraries.featureflag.api.FeatureFlags
2829
import io.element.android.libraries.indicator.api.IndicatorService
2930
import io.element.android.libraries.matrix.api.MatrixClient
31+
import io.element.android.libraries.matrix.api.core.UserId
3032
import io.element.android.libraries.matrix.api.sync.SyncService
33+
import io.element.android.libraries.matrix.api.user.MatrixUser
34+
import io.element.android.libraries.sessionstorage.api.SessionData
3135
import io.element.android.libraries.sessionstorage.api.SessionStore
36+
import kotlinx.collections.immutable.persistentListOf
37+
import kotlinx.collections.immutable.toPersistentList
38+
import kotlinx.coroutines.flow.map
39+
import kotlinx.coroutines.launch
3240

3341
@Inject
3442
class HomePresenter(
@@ -44,7 +52,13 @@ class HomePresenter(
4452
) : Presenter<HomeState> {
4553
@Composable
4654
override fun present(): HomeState {
55+
val coroutineState = rememberCoroutineScope()
4756
val matrixUser by client.userProfile.collectAsState()
57+
val matrixUserAndNeighbors by remember {
58+
sessionStore.sessionsFlow().map { list ->
59+
list.takeCurrentUserWithNeighbors(matrixUser).toPersistentList()
60+
}
61+
}.collectAsState(initial = persistentListOf(matrixUser))
4862
val isOnline by syncService.isOnline.collectAsState()
4963
val canReportBug by remember { rageshakeFeatureAvailability.isAvailable() }.collectAsState(false)
5064
val roomListState = roomListPresenter.present()
@@ -79,12 +93,15 @@ class HomePresenter(
7993
is HomeEvents.SelectHomeNavigationBarItem -> {
8094
currentHomeNavigationBarItemOrdinal = event.item.ordinal
8195
}
96+
is HomeEvents.SwitchToAccount -> coroutineState.launch {
97+
sessionStore.setLatestSession(event.sessionId.value)
98+
}
8299
}
83100
}
84101

85102
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
86103
return HomeState(
87-
matrixUser = matrixUser,
104+
matrixUserAndNeighbors = matrixUserAndNeighbors,
88105
showAvatarIndicator = showAvatarIndicator,
89106
hasNetworkConnection = isOnline,
90107
currentHomeNavigationBarItem = currentHomeNavigationBarItem,
@@ -97,3 +114,45 @@ class HomePresenter(
97114
)
98115
}
99116
}
117+
118+
private fun List<SessionData>.takeCurrentUserWithNeighbors(matrixUser: MatrixUser): List<MatrixUser> {
119+
// Sort by userId to always have the same order (not depending on last account usage)
120+
return sortedBy { it.userId }
121+
.map {
122+
if (it.userId == matrixUser.userId.value) {
123+
// Always use the freshest profile for the current user
124+
matrixUser
125+
} else {
126+
// Use the data from the DB
127+
MatrixUser(
128+
userId = UserId(it.userId),
129+
displayName = it.userDisplayName,
130+
avatarUrl = it.userAvatarUrl,
131+
)
132+
}
133+
}
134+
.let { sessionList ->
135+
// If the list has one item, there is no other session, return the list
136+
when (sessionList.size) {
137+
// Can happen when the user signs out (?)
138+
0 -> listOf(matrixUser)
139+
1 -> sessionList
140+
else -> {
141+
// Create a list with extra item at the start and end if necessary to have the current user in the middle
142+
// If the list is [A, B, C, D] and the current user is A we want to return [D, A, B]
143+
// If the current user is B, we want to return [A, B, C]
144+
// If the current user is C, we want to return [B, C, D]
145+
// If the current user is D, we want to return [C, D, A]
146+
val currentUserIndex = sessionList.indexOfFirst { it.userId == matrixUser.userId }
147+
when (currentUserIndex) {
148+
// This can happen when the user signs out.
149+
// In this case, just return a singleton list with the current user.
150+
-1 -> listOf(matrixUser)
151+
0 -> listOf(sessionList.last()) + sessionList.take(2)
152+
sessionList.lastIndex -> sessionList.takeLast(2) + sessionList.first()
153+
else -> sessionList.slice(currentUserIndex - 1..currentUserIndex + 1)
154+
}
155+
}
156+
}
157+
}
158+
}

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ import io.element.android.features.home.impl.roomlist.RoomListState
1212
import io.element.android.features.logout.api.direct.DirectLogoutState
1313
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
1414
import io.element.android.libraries.matrix.api.user.MatrixUser
15+
import kotlinx.collections.immutable.ImmutableList
1516

1617
@Immutable
1718
data class HomeState(
18-
val matrixUser: MatrixUser,
19+
/**
20+
* The current user of this session, in case of multiple accounts, will contains 3 items, with the
21+
* current user in the middle.
22+
*/
23+
val matrixUserAndNeighbors: ImmutableList<MatrixUser>,
1924
val showAvatarIndicator: Boolean,
2025
val hasNetworkConnection: Boolean,
2126
val currentHomeNavigationBarItem: HomeNavigationBarItem,

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
1919
import io.element.android.libraries.matrix.api.core.UserId
2020
import io.element.android.libraries.matrix.api.user.MatrixUser
2121
import io.element.android.libraries.ui.strings.CommonStrings
22+
import kotlinx.collections.immutable.toPersistentList
2223

2324
open class HomeStateProvider : PreviewParameterProvider<HomeState> {
2425
override val values: Sequence<HomeState>
@@ -46,6 +47,7 @@ open class HomeStateProvider : PreviewParameterProvider<HomeState> {
4647

4748
internal fun aHomeState(
4849
matrixUser: MatrixUser = MatrixUser(userId = UserId("@id:domain"), displayName = "User#1"),
50+
matrixUserAndNeighbors: List<MatrixUser> = listOf(matrixUser),
4951
showAvatarIndicator: Boolean = false,
5052
hasNetworkConnection: Boolean = true,
5153
snackbarMessage: SnackbarMessage? = null,
@@ -56,7 +58,7 @@ internal fun aHomeState(
5658
directLogoutState: DirectLogoutState = aDirectLogoutState(),
5759
eventSink: (HomeEvents) -> Unit = {}
5860
) = HomeState(
59-
matrixUser = matrixUser,
61+
matrixUserAndNeighbors = matrixUserAndNeighbors.toPersistentList(),
6062
showAvatarIndicator = showAvatarIndicator,
6163
hasNetworkConnection = hasNetworkConnection,
6264
snackbarMessage = snackbarMessage,

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,15 @@ private fun HomeScaffold(
172172
topBar = {
173173
RoomListTopBar(
174174
title = stringResource(state.currentHomeNavigationBarItem.labelRes),
175-
matrixUser = state.matrixUser,
175+
matrixUserAndNeighbors = state.matrixUserAndNeighbors,
176176
showAvatarIndicator = state.showAvatarIndicator,
177177
areSearchResultsDisplayed = roomListState.searchState.isSearchActive,
178178
onToggleSearch = { roomListState.eventSink(RoomListEvents.ToggleSearchResults) },
179179
onMenuActionClick = onMenuActionClick,
180180
onOpenSettings = onOpenSettings,
181+
onAccountSwitch = {
182+
state.eventSink(HomeEvents.SwitchToAccount(it))
183+
},
181184
scrollBehavior = scrollBehavior,
182185
displayMenuItems = state.displayActions,
183186
displayFilters = roomListState.displayFilters && state.currentHomeNavigationBarItem == HomeNavigationBarItem.Chats,

0 commit comments

Comments
 (0)