mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-10-31 08:15:02 +00:00
Handle account switch in RootFlowNode instead of in presenters
PreferencesRootPresenter and HomePresenter were updating the latest session in the session store directly, relying on RootNavStateFlow to trigger the navigation as a side effect. Changing the current session is app-level navigation, so it is now forwarded through a new `navigateToSession` callback up to RootFlowNode, which performs the session store update. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ import io.element.android.libraries.architecture.createNode
|
|||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrixmedia.api.ImageLoaderHolder
|
import io.element.android.libraries.matrixmedia.api.ImageLoaderHolder
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ class LoggedInAppScopeFlowNode(
|
|||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToBugReport()
|
fun navigateToBugReport()
|
||||||
fun navigateToAddAccount()
|
fun navigateToAddAccount()
|
||||||
|
fun navigateToSession(sessionId: SessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callback: Callback = callback()
|
private val callback: Callback = callback()
|
||||||
@@ -91,6 +93,10 @@ class LoggedInAppScopeFlowNode(
|
|||||||
override fun navigateToAddAccount() {
|
override fun navigateToAddAccount() {
|
||||||
callback.navigateToAddAccount()
|
callback.navigateToAddAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun navigateToSession(sessionId: SessionId) {
|
||||||
|
callback.navigateToSession(sessionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return createNode<LoggedInFlowNode>(buildContext, listOf(callback))
|
return createNode<LoggedInFlowNode>(buildContext, listOf(callback))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
|||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
@@ -169,6 +170,7 @@ class LoggedInFlowNode(
|
|||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToBugReport()
|
fun navigateToBugReport()
|
||||||
fun navigateToAddAccount()
|
fun navigateToAddAccount()
|
||||||
|
fun navigateToSession(sessionId: SessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callback: Callback = callback()
|
private val callback: Callback = callback()
|
||||||
@@ -356,6 +358,10 @@ class LoggedInFlowNode(
|
|||||||
override fun navigateToAddAccount() {
|
override fun navigateToAddAccount() {
|
||||||
callback.navigateToAddAccount()
|
callback.navigateToAddAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun navigateToSession(sessionId: SessionId) {
|
||||||
|
callback.navigateToSession(sessionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
homeEntryPoint.createNode(
|
homeEntryPoint.createNode(
|
||||||
parentNode = this,
|
parentNode = this,
|
||||||
@@ -448,6 +454,10 @@ class LoggedInFlowNode(
|
|||||||
callback.navigateToAddAccount()
|
callback.navigateToAddAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun navigateToSession(sessionId: SessionId) {
|
||||||
|
callback.navigateToSession(sessionId)
|
||||||
|
}
|
||||||
|
|
||||||
override fun navigateToLinkNewDevice() {
|
override fun navigateToLinkNewDevice() {
|
||||||
backstack.push(NavTarget.LinkNewDevice)
|
backstack.push(NavTarget.LinkNewDevice)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -416,6 +416,12 @@ class RootFlowNode(
|
|||||||
override fun navigateToAddAccount() {
|
override fun navigateToAddAccount() {
|
||||||
backstack.push(NavTarget.NotLoggedInFlow(null))
|
backstack.push(NavTarget.NotLoggedInFlow(null))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun navigateToSession(sessionId: SessionId) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
sessionStore.setLatestSession(sessionId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val savedNavState = extractSavedStateForNavTarget(navTarget, this.buildContext.savedStateMap)
|
val savedNavState = extractSavedStateForNavTarget(navTarget, this.buildContext.savedStateMap)
|
||||||
val buildContext = if (savedNavState != null) {
|
val buildContext = if (savedNavState != null) {
|
||||||
|
|||||||
+2
@@ -14,6 +14,7 @@ import com.bumble.appyx.core.plugin.Plugin
|
|||||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
||||||
interface HomeEntryPoint : FeatureEntryPoint {
|
interface HomeEntryPoint : FeatureEntryPoint {
|
||||||
@@ -33,5 +34,6 @@ interface HomeEntryPoint : FeatureEntryPoint {
|
|||||||
fun navigateToRoomSettings(roomId: RoomId)
|
fun navigateToRoomSettings(roomId: RoomId)
|
||||||
fun navigateToBugReport()
|
fun navigateToBugReport()
|
||||||
fun navigateToAddAccount()
|
fun navigateToAddAccount()
|
||||||
|
fun navigateToSession(sessionId: SessionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,7 @@
|
|||||||
|
|
||||||
package io.element.android.features.home.impl
|
package io.element.android.features.home.impl
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
|
||||||
|
|
||||||
sealed interface HomeEvent {
|
sealed interface HomeEvent {
|
||||||
data class SelectHomeNavigationBarItem(val item: HomeNavigationBarItem) : HomeEvent
|
data class SelectHomeNavigationBarItem(val item: HomeNavigationBarItem) : HomeEvent
|
||||||
data class SwitchToAccount(val sessionId: SessionId) : HomeEvent
|
|
||||||
data object DismissMultiAccountAnnouncement : HomeEvent
|
data object DismissMultiAccountAnnouncement : HomeEvent
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -222,6 +222,7 @@ class HomeFlowNode(
|
|||||||
onRoomClick = ::navigateToRoom,
|
onRoomClick = ::navigateToRoom,
|
||||||
onSettingsClick = callback::navigateToSettings,
|
onSettingsClick = callback::navigateToSettings,
|
||||||
onAddAccountClick = callback::navigateToAddAccount,
|
onAddAccountClick = callback::navigateToAddAccount,
|
||||||
|
onSwitchToAccount = callback::navigateToSession,
|
||||||
onStartChatClick = callback::navigateToCreateRoom,
|
onStartChatClick = callback::navigateToCreateRoom,
|
||||||
onCreateSpaceClick = callback::navigateToCreateSpace,
|
onCreateSpaceClick = callback::navigateToCreateSpace,
|
||||||
onSetUpRecoveryClick = callback::navigateToSetUpRecovery,
|
onSetUpRecoveryClick = callback::navigateToSetUpRecovery,
|
||||||
|
|||||||
-3
@@ -126,9 +126,6 @@ class HomePresenter(
|
|||||||
is HomeEvent.SelectHomeNavigationBarItem -> {
|
is HomeEvent.SelectHomeNavigationBarItem -> {
|
||||||
currentHomeNavigationBarItemOrdinal = event.item.ordinal
|
currentHomeNavigationBarItemOrdinal = event.item.ordinal
|
||||||
}
|
}
|
||||||
is HomeEvent.SwitchToAccount -> coroutineState.launch {
|
|
||||||
sessionStore.setLatestSession(event.sessionId.value)
|
|
||||||
}
|
|
||||||
HomeEvent.DismissMultiAccountAnnouncement -> coroutineState.launch {
|
HomeEvent.DismissMultiAccountAnnouncement -> coroutineState.launch {
|
||||||
announcementService.onAnnouncementDismissed(Announcement.MultiAccount)
|
announcementService.onAnnouncementDismissed(Announcement.MultiAccount)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -69,6 +69,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
|||||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -78,6 +79,7 @@ fun HomeView(
|
|||||||
onRoomClick: (RoomId, EventId?) -> Unit,
|
onRoomClick: (RoomId, EventId?) -> Unit,
|
||||||
onSettingsClick: () -> Unit,
|
onSettingsClick: () -> Unit,
|
||||||
onAddAccountClick: () -> Unit,
|
onAddAccountClick: () -> Unit,
|
||||||
|
onSwitchToAccount: (SessionId) -> Unit,
|
||||||
onSetUpRecoveryClick: () -> Unit,
|
onSetUpRecoveryClick: () -> Unit,
|
||||||
onConfirmRecoveryKeyClick: () -> Unit,
|
onConfirmRecoveryKeyClick: () -> Unit,
|
||||||
onStartChatClick: () -> Unit,
|
onStartChatClick: () -> Unit,
|
||||||
@@ -130,6 +132,7 @@ fun HomeView(
|
|||||||
onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() },
|
onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() },
|
||||||
onCreateSpaceClick = { if (firstThrottler.canHandle()) onCreateSpaceClick() },
|
onCreateSpaceClick = { if (firstThrottler.canHandle()) onCreateSpaceClick() },
|
||||||
onMenuActionClick = onMenuActionClick,
|
onMenuActionClick = onMenuActionClick,
|
||||||
|
onSwitchToAccount = onSwitchToAccount,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (state.globalSearchState.isEnabled) {
|
if (state.globalSearchState.isEnabled) {
|
||||||
@@ -167,6 +170,7 @@ private fun HomeScaffold(
|
|||||||
onStartChatClick: () -> Unit,
|
onStartChatClick: () -> Unit,
|
||||||
onCreateSpaceClick: () -> Unit,
|
onCreateSpaceClick: () -> Unit,
|
||||||
onMenuActionClick: (RoomListMenuAction) -> Unit,
|
onMenuActionClick: (RoomListMenuAction) -> Unit,
|
||||||
|
onSwitchToAccount: (SessionId) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
fun onRoomClick(room: RoomListRoomSummary) {
|
fun onRoomClick(room: RoomListRoomSummary) {
|
||||||
@@ -213,9 +217,7 @@ private fun HomeScaffold(
|
|||||||
},
|
},
|
||||||
onMenuActionClick = onMenuActionClick,
|
onMenuActionClick = onMenuActionClick,
|
||||||
onOpenSettings = onOpenSettings,
|
onOpenSettings = onOpenSettings,
|
||||||
onAccountSwitch = {
|
onAccountSwitch = onSwitchToAccount,
|
||||||
state.eventSink(HomeEvent.SwitchToAccount(it))
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
displayFilters = state.displayRoomListFilters,
|
displayFilters = state.displayRoomListFilters,
|
||||||
filtersState = roomListState.filtersState,
|
filtersState = roomListState.filtersState,
|
||||||
@@ -379,6 +381,7 @@ internal fun HomeViewPreview(@PreviewParameter(HomeStatePreviewParam::class) sta
|
|||||||
onRoomClick = { _, _ -> },
|
onRoomClick = { _, _ -> },
|
||||||
onSettingsClick = {},
|
onSettingsClick = {},
|
||||||
onAddAccountClick = {},
|
onAddAccountClick = {},
|
||||||
|
onSwitchToAccount = {},
|
||||||
onSetUpRecoveryClick = {},
|
onSetUpRecoveryClick = {},
|
||||||
onConfirmRecoveryKeyClick = {},
|
onConfirmRecoveryKeyClick = {},
|
||||||
onStartChatClick = {},
|
onStartChatClick = {},
|
||||||
@@ -400,6 +403,7 @@ internal fun HomeViewA11yPreview() = ElementPreview {
|
|||||||
onRoomClick = { _, _ -> },
|
onRoomClick = { _, _ -> },
|
||||||
onSettingsClick = {},
|
onSettingsClick = {},
|
||||||
onAddAccountClick = {},
|
onAddAccountClick = {},
|
||||||
|
onSwitchToAccount = {},
|
||||||
onSetUpRecoveryClick = {},
|
onSetUpRecoveryClick = {},
|
||||||
onConfirmRecoveryKeyClick = {},
|
onConfirmRecoveryKeyClick = {},
|
||||||
onStartChatClick = {},
|
onStartChatClick = {},
|
||||||
|
|||||||
+2
@@ -14,6 +14,7 @@ import io.element.android.features.home.api.HomeEntryPoint
|
|||||||
import io.element.android.features.invite.test.declineandblock.FakeDeclineInviteAndBlockEntryPoint
|
import io.element.android.features.invite.test.declineandblock.FakeDeclineInviteAndBlockEntryPoint
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
@@ -53,6 +54,7 @@ class DefaultHomeEntryPointTest : RobolectricTest() {
|
|||||||
override fun navigateToRoomSettings(roomId: RoomId) = lambdaError()
|
override fun navigateToRoomSettings(roomId: RoomId) = lambdaError()
|
||||||
override fun navigateToBugReport() = lambdaError()
|
override fun navigateToBugReport() = lambdaError()
|
||||||
override fun navigateToAddAccount() = lambdaError()
|
override fun navigateToAddAccount() = lambdaError()
|
||||||
|
override fun navigateToSession(sessionId: SessionId) = lambdaError()
|
||||||
}
|
}
|
||||||
val result = entryPoint.createNode(
|
val result = entryPoint.createNode(
|
||||||
parentNode = parentNode,
|
parentNode = parentNode,
|
||||||
|
|||||||
+1
@@ -305,6 +305,7 @@ private fun AndroidComposeUiTest<ComponentActivity>.setRoomListView(
|
|||||||
onRoomClick = { roomId, _ -> onRoomClick(roomId) },
|
onRoomClick = { roomId, _ -> onRoomClick(roomId) },
|
||||||
onSettingsClick = onSettingsClick,
|
onSettingsClick = onSettingsClick,
|
||||||
onAddAccountClick = onAddAccountClick,
|
onAddAccountClick = onAddAccountClick,
|
||||||
|
onSwitchToAccount = EnsureNeverCalledWithParam(),
|
||||||
onSetUpRecoveryClick = onSetUpRecoveryClick,
|
onSetUpRecoveryClick = onSetUpRecoveryClick,
|
||||||
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
|
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
|
||||||
onStartChatClick = onCreateRoomClick,
|
onStartChatClick = onCreateRoomClick,
|
||||||
|
|||||||
+2
@@ -16,6 +16,7 @@ import io.element.android.libraries.architecture.FeatureEntryPoint
|
|||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
interface PreferencesEntryPoint : FeatureEntryPoint {
|
interface PreferencesEntryPoint : FeatureEntryPoint {
|
||||||
@@ -44,6 +45,7 @@ interface PreferencesEntryPoint : FeatureEntryPoint {
|
|||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToAddAccount()
|
fun navigateToAddAccount()
|
||||||
|
fun navigateToSession(sessionId: SessionId)
|
||||||
fun navigateToLinkNewDevice()
|
fun navigateToLinkNewDevice()
|
||||||
fun navigateToBugReport()
|
fun navigateToBugReport()
|
||||||
fun navigateToSecureBackup()
|
fun navigateToSecureBackup()
|
||||||
|
|||||||
+5
@@ -46,6 +46,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes
|
|||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.mediaviewer.api.FileViewerEntryPoint
|
import io.element.android.libraries.mediaviewer.api.FileViewerEntryPoint
|
||||||
import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint
|
import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint
|
||||||
@@ -141,6 +142,10 @@ class PreferencesFlowNode(
|
|||||||
callback.navigateToAddAccount()
|
callback.navigateToAddAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun navigateToSession(sessionId: SessionId) {
|
||||||
|
callback.navigateToSession(sessionId)
|
||||||
|
}
|
||||||
|
|
||||||
override fun navigateToAnalyticsSettings() {
|
override fun navigateToAnalyticsSettings() {
|
||||||
backstack.push(NavTarget.AnalyticsSettings)
|
backstack.push(NavTarget.AnalyticsSettings)
|
||||||
}
|
}
|
||||||
|
|||||||
-3
@@ -8,11 +8,8 @@
|
|||||||
|
|
||||||
package io.element.android.features.preferences.impl.root
|
package io.element.android.features.preferences.impl.root
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
|
||||||
|
|
||||||
sealed interface PreferencesRootEvent {
|
sealed interface PreferencesRootEvent {
|
||||||
data object OnVersionInfoClick : PreferencesRootEvent
|
data object OnVersionInfoClick : PreferencesRootEvent
|
||||||
data class SwitchToSession(val sessionId: SessionId) : PreferencesRootEvent
|
|
||||||
data object ToggleOtherAccountsExpanded : PreferencesRootEvent
|
data object ToggleOtherAccountsExpanded : PreferencesRootEvent
|
||||||
data class SetTheme(val theme: ThemeOption) : PreferencesRootEvent
|
data class SetTheme(val theme: ThemeOption) : PreferencesRootEvent
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -24,6 +24,7 @@ import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTa
|
|||||||
import io.element.android.libraries.architecture.callback
|
import io.element.android.libraries.architecture.callback
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.emoji.api.picker.EmojiPickerRenderer
|
import io.element.android.libraries.emoji.api.picker.EmojiPickerRenderer
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
|
||||||
@ContributesNode(SessionScope::class)
|
@ContributesNode(SessionScope::class)
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
@@ -35,6 +36,7 @@ class PreferencesRootNode(
|
|||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
interface Callback : PreferencesAccountCallback, Plugin {
|
interface Callback : PreferencesAccountCallback, Plugin {
|
||||||
fun navigateToAddAccount()
|
fun navigateToAddAccount()
|
||||||
|
fun navigateToSession(sessionId: SessionId)
|
||||||
fun navigateToAnalyticsSettings()
|
fun navigateToAnalyticsSettings()
|
||||||
fun navigateToAbout()
|
fun navigateToAbout()
|
||||||
fun navigateToDeveloperSettings()
|
fun navigateToDeveloperSettings()
|
||||||
@@ -72,6 +74,7 @@ class PreferencesRootNode(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackClick = this::navigateUp,
|
onBackClick = this::navigateUp,
|
||||||
onAddAccountClick = callback::navigateToAddAccount,
|
onAddAccountClick = callback::navigateToAddAccount,
|
||||||
|
onSwitchToSession = callback::navigateToSession,
|
||||||
onOpenAnalytics = callback::navigateToAnalyticsSettings,
|
onOpenAnalytics = callback::navigateToAnalyticsSettings,
|
||||||
onOpenAbout = callback::navigateToAbout,
|
onOpenAbout = callback::navigateToAbout,
|
||||||
onOpenDeveloperSettings = callback::navigateToDeveloperSettings,
|
onOpenDeveloperSettings = callback::navigateToDeveloperSettings,
|
||||||
|
|||||||
-3
@@ -124,9 +124,6 @@ class PreferencesRootPresenter(
|
|||||||
is PreferencesRootEvent.OnVersionInfoClick -> {
|
is PreferencesRootEvent.OnVersionInfoClick -> {
|
||||||
showDeveloperSettingsProvider.unlockDeveloperSettings(coroutineScope)
|
showDeveloperSettingsProvider.unlockDeveloperSettings(coroutineScope)
|
||||||
}
|
}
|
||||||
is PreferencesRootEvent.SwitchToSession -> coroutineScope.launch {
|
|
||||||
sessionStore.setLatestSession(event.sessionId.value)
|
|
||||||
}
|
|
||||||
PreferencesRootEvent.ToggleOtherAccountsExpanded -> coroutineScope.launch {
|
PreferencesRootEvent.ToggleOtherAccountsExpanded -> coroutineScope.launch {
|
||||||
appPreferencesStore.setOtherAccountsExpanded(!isOtherAccountsSectionExpanded)
|
appPreferencesStore.setOtherAccountsExpanded(!isOtherAccountsSectionExpanded)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -65,6 +65,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
|||||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.emoji.api.picker.EmojiPickerRenderer
|
import io.element.android.libraries.emoji.api.picker.EmojiPickerRenderer
|
||||||
import io.element.android.libraries.emoji.api.picker.NoOpEmojiPickerRenderer
|
import io.element.android.libraries.emoji.api.picker.NoOpEmojiPickerRenderer
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.MatrixUserRow
|
import io.element.android.libraries.matrix.ui.components.MatrixUserRow
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
@@ -79,6 +80,7 @@ fun PreferencesRootView(
|
|||||||
emojiPickerRenderer: EmojiPickerRenderer,
|
emojiPickerRenderer: EmojiPickerRenderer,
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
onAddAccountClick: () -> Unit,
|
onAddAccountClick: () -> Unit,
|
||||||
|
onSwitchToSession: (SessionId) -> Unit,
|
||||||
onOpenAnalytics: () -> Unit,
|
onOpenAnalytics: () -> Unit,
|
||||||
onOpenLockScreenSettings: () -> Unit,
|
onOpenLockScreenSettings: () -> Unit,
|
||||||
onOpenAbout: () -> Unit,
|
onOpenAbout: () -> Unit,
|
||||||
@@ -124,6 +126,7 @@ fun PreferencesRootView(
|
|||||||
MultiAccountSection(
|
MultiAccountSection(
|
||||||
state = state,
|
state = state,
|
||||||
onAddAccountClick = onAddAccountClick,
|
onAddAccountClick = onAddAccountClick,
|
||||||
|
onSwitchToSession = onSwitchToSession,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
@@ -208,6 +211,7 @@ private fun ColumnScope.UserStatusSection(
|
|||||||
private fun ColumnScope.MultiAccountSection(
|
private fun ColumnScope.MultiAccountSection(
|
||||||
state: PreferencesRootState,
|
state: PreferencesRootState,
|
||||||
onAddAccountClick: () -> Unit,
|
onAddAccountClick: () -> Unit,
|
||||||
|
onSwitchToSession: (SessionId) -> Unit,
|
||||||
) {
|
) {
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
thickness = 8.dp,
|
thickness = 8.dp,
|
||||||
@@ -275,7 +279,7 @@ private fun ColumnScope.MultiAccountSection(
|
|||||||
MatrixUserRow(
|
MatrixUserRow(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
state.eventSink(PreferencesRootEvent.SwitchToSession(matrixUser.userId))
|
onSwitchToSession(matrixUser.userId)
|
||||||
}
|
}
|
||||||
.padding(top = 2.dp, bottom = 2.dp, end = 8.dp),
|
.padding(top = 2.dp, bottom = 2.dp, end = 8.dp),
|
||||||
matrixUser = matrixUser,
|
matrixUser = matrixUser,
|
||||||
@@ -427,6 +431,7 @@ private fun ContentToPreview(state: PreferencesRootState) {
|
|||||||
emojiPickerRenderer = NoOpEmojiPickerRenderer,
|
emojiPickerRenderer = NoOpEmojiPickerRenderer,
|
||||||
onBackClick = {},
|
onBackClick = {},
|
||||||
onAddAccountClick = {},
|
onAddAccountClick = {},
|
||||||
|
onSwitchToSession = {},
|
||||||
onOpenAnalytics = {},
|
onOpenAnalytics = {},
|
||||||
onOpenDeveloperSettings = {},
|
onOpenDeveloperSettings = {},
|
||||||
onOpenLocationSettings = {},
|
onOpenLocationSettings = {},
|
||||||
|
|||||||
+2
@@ -19,6 +19,7 @@ import io.element.android.features.logout.test.FakeLogoutEntryPoint
|
|||||||
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.mediaviewer.test.FakeFileViewerEntryPoint
|
import io.element.android.libraries.mediaviewer.test.FakeFileViewerEntryPoint
|
||||||
import io.element.android.libraries.troubleshoot.test.FakeNotificationTroubleShootEntryPoint
|
import io.element.android.libraries.troubleshoot.test.FakeNotificationTroubleShootEntryPoint
|
||||||
import io.element.android.libraries.troubleshoot.test.FakePushHistoryEntryPoint
|
import io.element.android.libraries.troubleshoot.test.FakePushHistoryEntryPoint
|
||||||
@@ -52,6 +53,7 @@ class DefaultPreferencesEntryPointTest {
|
|||||||
}
|
}
|
||||||
val callback = object : PreferencesEntryPoint.Callback {
|
val callback = object : PreferencesEntryPoint.Callback {
|
||||||
override fun navigateToAddAccount() = lambdaError()
|
override fun navigateToAddAccount() = lambdaError()
|
||||||
|
override fun navigateToSession(sessionId: SessionId) = lambdaError()
|
||||||
override fun navigateToLinkNewDevice() = lambdaError()
|
override fun navigateToLinkNewDevice() = lambdaError()
|
||||||
override fun navigateToBugReport() = lambdaError()
|
override fun navigateToBugReport() = lambdaError()
|
||||||
override fun navigateToSecureBackup() = lambdaError()
|
override fun navigateToSecureBackup() = lambdaError()
|
||||||
|
|||||||
-20
@@ -39,8 +39,6 @@ import io.element.android.libraries.sessionstorage.test.aSessionData
|
|||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
|
||||||
import io.element.android.tests.testutils.lambda.value
|
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -179,24 +177,6 @@ class PreferencesRootPresenterTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `present - switch session invoke method on the session store`() = runTest {
|
|
||||||
val setLatestSessionResult = lambdaRecorder<String, Unit> { }
|
|
||||||
val sessionStore = InMemorySessionStore(
|
|
||||||
initialList = listOf(
|
|
||||||
aSessionData(sessionId = A_SESSION_ID.value),
|
|
||||||
aSessionData(sessionId = A_SESSION_ID_2.value),
|
|
||||||
),
|
|
||||||
setLatestSessionResult = setLatestSessionResult,
|
|
||||||
)
|
|
||||||
createPreferencesRootPresenter(sessionStore = sessionStore).test {
|
|
||||||
val loadedState = awaitFirstItem()
|
|
||||||
loadedState.eventSink(PreferencesRootEvent.SwitchToSession(A_SESSION_ID_2))
|
|
||||||
setLatestSessionResult.assertions().isCalledOnce()
|
|
||||||
.with(value(A_SESSION_ID_2.value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - labs can be shown if any feature flag is in labs and not finished`() = runTest {
|
fun `present - labs can be shown if any feature flag is in labs and not finished`() = runTest {
|
||||||
createPreferencesRootPresenter(
|
createPreferencesRootPresenter(
|
||||||
|
|||||||
+21
-16
@@ -20,6 +20,7 @@ import androidx.compose.ui.test.performScrollTo
|
|||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
import io.element.android.libraries.emoji.api.picker.NoOpEmojiPickerRenderer
|
import io.element.android.libraries.emoji.api.picker.NoOpEmojiPickerRenderer
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
@@ -69,23 +70,25 @@ class PreferencesRootViewTest : RobolectricTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on other session sends a SwitchToSession`() = runAndroidComposeUiTest {
|
fun `clicking on other session invokes the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<PreferencesRootEvent>()
|
val eventsRecorder = EventsRecorder<PreferencesRootEvent>(expectEvents = false)
|
||||||
setView(
|
ensureCalledOnceWithParam(A_USER_ID_2) { callback ->
|
||||||
aPreferencesRootState(
|
setView(
|
||||||
isMultiAccountEnabled = true,
|
aPreferencesRootState(
|
||||||
isOtherAccountsSectionExpanded = true,
|
isMultiAccountEnabled = true,
|
||||||
otherSessions = listOf(
|
isOtherAccountsSectionExpanded = true,
|
||||||
aMatrixUser(
|
otherSessions = listOf(
|
||||||
id = A_USER_ID_2.value,
|
aMatrixUser(
|
||||||
displayName = "Bob",
|
id = A_USER_ID_2.value,
|
||||||
)
|
displayName = "Bob",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
eventSink = eventsRecorder,
|
onSwitchToSession = callback,
|
||||||
),
|
)
|
||||||
)
|
onNodeWithText("Bob").performClick()
|
||||||
onNodeWithText("Bob").performClick()
|
}
|
||||||
eventsRecorder.assertSingle(PreferencesRootEvent.SwitchToSession(A_USER_ID_2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -395,6 +398,7 @@ private fun AndroidComposeUiTest<ComponentActivity>.setView(
|
|||||||
state: PreferencesRootState,
|
state: PreferencesRootState,
|
||||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onAddAccountClick: () -> Unit = EnsureNeverCalled(),
|
onAddAccountClick: () -> Unit = EnsureNeverCalled(),
|
||||||
|
onSwitchToSession: (SessionId) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onOpenAnalytics: () -> Unit = EnsureNeverCalled(),
|
onOpenAnalytics: () -> Unit = EnsureNeverCalled(),
|
||||||
onOpenLockScreenSettings: () -> Unit = EnsureNeverCalled(),
|
onOpenLockScreenSettings: () -> Unit = EnsureNeverCalled(),
|
||||||
onOpenAbout: () -> Unit = EnsureNeverCalled(),
|
onOpenAbout: () -> Unit = EnsureNeverCalled(),
|
||||||
@@ -418,6 +422,7 @@ private fun AndroidComposeUiTest<ComponentActivity>.setView(
|
|||||||
emojiPickerRenderer = NoOpEmojiPickerRenderer,
|
emojiPickerRenderer = NoOpEmojiPickerRenderer,
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
onAddAccountClick = onAddAccountClick,
|
onAddAccountClick = onAddAccountClick,
|
||||||
|
onSwitchToSession = onSwitchToSession,
|
||||||
onOpenAnalytics = onOpenAnalytics,
|
onOpenAnalytics = onOpenAnalytics,
|
||||||
onOpenLockScreenSettings = onOpenLockScreenSettings,
|
onOpenLockScreenSettings = onOpenLockScreenSettings,
|
||||||
onOpenAbout = onOpenAbout,
|
onOpenAbout = onOpenAbout,
|
||||||
|
|||||||
Reference in New Issue
Block a user