diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index 9fb04a2314..eb1df5643e 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -62,7 +62,6 @@ import io.element.android.features.roomdirectory.api.RoomDescription import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.share.api.ShareEntryPoint -import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.features.startchat.api.StartChatEntryPoint import io.element.android.features.userprofile.api.UserProfileEntryPoint import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint @@ -256,7 +255,7 @@ class LoggedInFlowNode( val serverNames: List = emptyList(), val trigger: JoinedRoom.Trigger? = null, val roomDescription: RoomDescription? = null, - val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), + val initialElement: RoomNavigationTarget = RoomNavigationTarget.Root(), val targetId: UUID = UUID.randomUUID(), ) : NavTarget @@ -358,7 +357,7 @@ class LoggedInFlowNode( roomIdOrAlias = data.roomIdOrAlias, serverNames = data.viaParameters, trigger = JoinedRoom.Trigger.Timeline, - initialElement = RoomNavigationTarget.Messages(data.eventId), + initialElement = RoomNavigationTarget.Root(data.eventId), ) if (pushToBackstack) { backstack.push(target) @@ -377,11 +376,6 @@ class LoggedInFlowNode( backstack.push(NavTarget.Settings(PreferencesEntryPoint.InitialTarget.NotificationSettings)) } } - val spaceCallback = object : SpaceEntryPoint.Callback { - override fun onOpenRoom(roomId: RoomId, viaParameters: List) { - backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), serverNames = viaParameters)) - } - } val inputs = RoomFlowNode.Inputs( roomIdOrAlias = navTarget.roomIdOrAlias, roomDescription = Optional.ofNullable(navTarget.roomDescription), @@ -389,7 +383,7 @@ class LoggedInFlowNode( trigger = Optional.ofNullable(navTarget.trigger), initialElement = navTarget.initialElement ) - createNode(buildContext, plugins = listOf(inputs, joinedRoomCallback, spaceCallback)) + createNode(buildContext, plugins = listOf(inputs, joinedRoomCallback)) } is NavTarget.UserProfile -> { val callback = object : UserProfileEntryPoint.Callback { @@ -421,7 +415,7 @@ class LoggedInFlowNode( } override fun navigateTo(roomId: RoomId, eventId: EventId) { - backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), initialElement = RoomNavigationTarget.Messages(eventId))) + backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), initialElement = RoomNavigationTarget.Root(eventId))) } } val inputs = PreferencesEntryPoint.Params(navTarget.initialElement) @@ -516,9 +510,7 @@ class LoggedInFlowNode( roomIdOrAlias = roomIdOrAlias, serverNames = serverNames, trigger = trigger, - initialElement = RoomNavigationTarget.Messages( - focusedEventId = eventId - ) + initialElement = RoomNavigationTarget.Root(eventId = eventId) ) backstack.accept(AttachRoomOperation(roomNavTarget, clearBackstack)) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt index 01683c01e7..64bf4b2fd2 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt @@ -9,7 +9,6 @@ package io.element.android.appnav.room import android.os.Parcelable import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.lifecycleScope import com.bumble.appyx.core.modality.BuildContext @@ -37,7 +36,6 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.withPreviousValue import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient @@ -49,11 +47,11 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.ui.room.LoadingRoomState import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -130,7 +128,6 @@ class RoomFlowNode( private fun subscribeToRoomInfoFlow(roomId: RoomId, serverNames: List) { val roomInfoFlow = client.getRoomInfoFlow(roomId) - val isSpaceFlow = roomInfoFlow.map { it.getOrNull()?.isSpace.orFalse() }.distinctUntilChanged() // This observes the local membership changes for the room val membershipUpdateFlow = membershipObserver.updates @@ -143,14 +140,10 @@ class RoomFlowNode( .map { it.getOrNull()?.currentUserMembership } .distinctUntilChanged() .withPreviousValue() - combine(currentMembershipFlow, isSpaceFlow) { (previousMembership, membership), isSpace -> + currentMembershipFlow.onEach { (previousMembership, membership) -> Timber.d("Room membership: $membership") if (membership == CurrentUserMembership.JOINED) { - if (isSpace) { - backstack.newRoot(NavTarget.JoinedSpace(spaceId = roomId)) - } else { - backstack.newRoot(NavTarget.JoinedRoom(roomId)) - } + backstack.newRoot(NavTarget.JoinedRoom(roomId)) } else { val leavingFromCurrentDevice = membership == CurrentUserMembership.LEFT && diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomNavigationTarget.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomNavigationTarget.kt index ab1589898b..d4b97d100a 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomNavigationTarget.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomNavigationTarget.kt @@ -13,7 +13,7 @@ import kotlinx.parcelize.Parcelize sealed interface RoomNavigationTarget : Parcelable { @Parcelize - data class Messages(val focusedEventId: EventId? = null) : RoomNavigationTarget + data class Root(val eventId: EventId? = null) : RoomNavigationTarget @Parcelize data object Details : RoomNavigationTarget diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt index f0f8dff3e7..93e0c64a7f 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt @@ -22,8 +22,11 @@ import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.appnav.di.RoomGraphFactory import io.element.android.appnav.room.RoomNavigationTarget +import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode.Inputs +import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode.NavTarget import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint +import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs @@ -51,6 +54,7 @@ class JoinedRoomLoadedFlowNode( @Assisted plugins: List, private val messagesEntryPoint: MessagesEntryPoint, private val roomDetailsEntryPoint: RoomDetailsEntryPoint, + private val spaceEntryPoint: SpaceEntryPoint, private val appNavigationStateService: AppNavigationStateService, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, @@ -59,11 +63,7 @@ class JoinedRoomLoadedFlowNode( roomGraphFactory: RoomGraphFactory, ) : BaseFlowNode( backstack = BackStack( - initialElement = when (val input = plugins.filterIsInstance().first().initialElement) { - is RoomNavigationTarget.Messages -> NavTarget.Messages(input.focusedEventId) - RoomNavigationTarget.Details -> NavTarget.RoomDetails - RoomNavigationTarget.NotificationSettings -> NavTarget.RoomNotificationSettings - }, + initialElement = initialElement(plugins), savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, @@ -154,9 +154,28 @@ class JoinedRoomLoadedFlowNode( NavTarget.RoomNotificationSettings -> { createRoomDetailsNode(buildContext, RoomDetailsEntryPoint.InitialTarget.RoomNotificationSettings) } + NavTarget.Space -> { + createSpaceNode(buildContext) + } } } + private fun createSpaceNode(buildContext: BuildContext): Node { + val callback = object : SpaceEntryPoint.Callback { + override fun onOpenRoom(roomId: RoomId, viaParameters: List) { + callbacks.forEach { it.onOpenRoom(roomId, viaParameters) } + } + + override fun onOpenDetails() { + backstack.push(NavTarget.RoomDetails) + } + } + return spaceEntryPoint.nodeBuilder(this, buildContext) + .inputs(SpaceEntryPoint.Inputs(roomId = inputs.room.roomId)) + .callback(callback) + .build() + } + private fun createMessagesNode( buildContext: BuildContext, navTarget: NavTarget.Messages, @@ -188,6 +207,9 @@ class JoinedRoomLoadedFlowNode( } sealed interface NavTarget : Parcelable { + @Parcelize + data object Space : NavTarget + @Parcelize data class Messages(val focusedEventId: EventId? = null) : NavTarget @@ -206,3 +228,18 @@ class JoinedRoomLoadedFlowNode( BackstackView() } } + +private fun initialElement(plugins: List): NavTarget { + val input = plugins.filterIsInstance().single() + return when (input.initialElement) { + is RoomNavigationTarget.Root -> { + if (input.room.roomInfoFlow.value.isSpace) { + NavTarget.Space + } else { + NavTarget.Messages(input.initialElement.eventId) + } + } + RoomNavigationTarget.Details -> NavTarget.RoomDetails + RoomNavigationTarget.NotificationSettings -> NavTarget.RoomNotificationSettings + } +} diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomNodeView.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomNodeView.kt index 95463fdc3f..deedf5f867 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomNodeView.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomNodeView.kt @@ -19,8 +19,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule -import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight @@ -76,7 +74,6 @@ private fun LoadingRoomTopBar( BackButton(onClick = onBackClick) }, title = { - IconTitlePlaceholdersRowMolecule(iconSize = AvatarSize.TimelineRoom.dp) }, ) } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt index dfb2638dc1..f8a18fa24a 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt @@ -22,12 +22,14 @@ import io.element.android.appnav.room.RoomNavigationTarget import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint +import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.libraries.architecture.childNode import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom +import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.services.appnavstate.api.ActiveRoomsHolder import io.element.android.services.appnavstate.test.FakeAppNavigationStateService import kotlinx.coroutines.test.TestScope @@ -98,16 +100,40 @@ class JoinedRoomLoadedFlowNodeTest { } } + private class FakeSpaceEntryPoint : SpaceEntryPoint { + var nodeId: String? = null + + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): SpaceEntryPoint.NodeBuilder { + return object : SpaceEntryPoint.NodeBuilder { + override fun inputs(inputs: SpaceEntryPoint.Inputs): SpaceEntryPoint.NodeBuilder { + return this + } + + override fun callback(callback: SpaceEntryPoint.Callback): SpaceEntryPoint.NodeBuilder { + return this + } + + override fun build(): Node { + return node(buildContext) {}.also { + nodeId = it.id + } + } + } + } + } + private fun TestScope.createJoinedRoomLoadedFlowNode( plugins: List, messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(), roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(), + spaceEntryPoint: SpaceEntryPoint = FakeSpaceEntryPoint(), activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(), ) = JoinedRoomLoadedFlowNode( buildContext = BuildContext.root(savedStateMap = null), plugins = plugins, messagesEntryPoint = messagesEntryPoint, roomDetailsEntryPoint = roomDetailsEntryPoint, + spaceEntryPoint = spaceEntryPoint, appNavigationStateService = FakeAppNavigationStateService(), sessionCoroutineScope = this, roomGraphFactory = FakeRoomGraphFactory(), @@ -116,11 +142,11 @@ class JoinedRoomLoadedFlowNodeTest { ) @Test - fun `given a room flow node when initialized then it loads messages entry point`() = runTest { + fun `given a room flow node when initialized then it loads messages entry point if room is not space`() = runTest { // GIVEN - val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {}, initialRoomInfo = aRoomInfo(isSpace = false))) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() - val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) + val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Root()) val roomFlowNode = createJoinedRoomLoadedFlowNode( plugins = listOf(inputs), messagesEntryPoint = fakeMessagesEntryPoint, @@ -135,13 +161,33 @@ class JoinedRoomLoadedFlowNodeTest { assertThat(messagesNode.id).isEqualTo(fakeMessagesEntryPoint.nodeId) } + @Test + fun `given a room flow node when initialized then it loads space entry point if room is space`() = runTest { + // GIVEN + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {}, initialRoomInfo = aRoomInfo(isSpace = true))) + val spaceEntryPoint = FakeSpaceEntryPoint() + val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Root()) + val roomFlowNode = createJoinedRoomLoadedFlowNode( + plugins = listOf(inputs), + spaceEntryPoint = spaceEntryPoint, + ) + // WHEN + val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper() + + // THEN + assertThat(roomFlowNode.backstack.activeElement).isEqualTo(JoinedRoomLoadedFlowNode.NavTarget.Space) + roomFlowNodeTestHelper.assertChildHasLifecycle(JoinedRoomLoadedFlowNode.NavTarget.Space, Lifecycle.State.CREATED) + val spaceNode = roomFlowNode.childNode(JoinedRoomLoadedFlowNode.NavTarget.Space)!! + assertThat(spaceNode.id).isEqualTo(spaceEntryPoint.nodeId) + } + @Test fun `given a room flow node when callback on room details is triggered then it loads room details entry point`() = runTest { // GIVEN val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint() - val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) + val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Root()) val roomFlowNode = createJoinedRoomLoadedFlowNode( plugins = listOf(inputs), messagesEntryPoint = fakeMessagesEntryPoint, @@ -162,7 +208,7 @@ class JoinedRoomLoadedFlowNodeTest { val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint() - val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) + val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Root()) val activeRoomsHolder = ActiveRoomsHolder() val roomFlowNode = createJoinedRoomLoadedFlowNode( plugins = listOf(inputs), @@ -185,7 +231,7 @@ class JoinedRoomLoadedFlowNodeTest { val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint() - val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) + val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Root()) val activeRoomsHolder = ActiveRoomsHolder().apply { addRoom(room) } diff --git a/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt b/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt index bdea93f3ef..a5f1134bf3 100644 --- a/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt +++ b/features/space/api/src/main/kotlin/io/element/android/features/space/api/SpaceEntryPoint.kt @@ -32,5 +32,6 @@ interface SpaceEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onOpenRoom(roomId: RoomId, viaParameters: List) + fun onOpenDetails() } } diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt index 78472c7b31..833186958b 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt @@ -31,12 +31,12 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.DependencyInjectionGraphOwner -import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceService import kotlinx.parcelize.Parcelize -@ContributesNode(SessionScope::class) +@ContributesNode(RoomScope::class) @AssistedInject class SpaceFlowNode( @Assisted val buildContext: BuildContext, @@ -84,6 +84,10 @@ class SpaceFlowNode( callback.onOpenRoom(roomId, viaParameters) } + override fun onOpenDetails() { + callback.onOpenDetails() + } + override fun onLeaveSpace() { backstack.push(NavTarget.Leave) } diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt index b1dac522b4..c484d43a70 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt @@ -11,12 +11,12 @@ import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.GraphExtension import dev.zacsweers.metro.Provides import io.element.android.libraries.architecture.NodeFactoriesBindings -import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.spaces.SpaceRoomList @GraphExtension(SpaceFlowScope::class) interface SpaceFlowGraph : NodeFactoriesBindings { - @ContributesTo(SessionScope::class) + @ContributesTo(RoomScope::class) @GraphExtension.Factory interface Factory { fun create(@Provides spaceRoomList: SpaceRoomList): SpaceFlowGraph diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt index 52c3472182..5266ba9f46 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt @@ -41,6 +41,7 @@ class SpaceNode( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onOpenRoom(roomId: RoomId, viaParameters: List) + fun onOpenDetails() fun onLeaveSpace() } @@ -76,6 +77,9 @@ class SpaceNode( onRoomClick = { spaceRoom -> callback.onOpenRoom(spaceRoom.roomId, spaceRoom.via) }, + onDetailsClick = { + callback.onOpenDetails() + }, onShareSpace = { onShareRoom(context) }, diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt index cbcae289e0..b32f9b73e1 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt @@ -7,6 +7,7 @@ package io.element.android.features.space.impl.root +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -15,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -25,6 +27,7 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics @@ -74,6 +77,7 @@ fun SpaceView( onRoomClick: (spaceRoom: SpaceRoom) -> Unit, onShareSpace: () -> Unit, onLeaveSpaceClick: () -> Unit, + onDetailsClick: () -> Unit, modifier: Modifier = Modifier, acceptDeclineInviteView: @Composable () -> Unit, ) { @@ -85,6 +89,7 @@ fun SpaceView( onBackClick = onBackClick, onLeaveSpaceClick = onLeaveSpaceClick, onShareSpace = onShareSpace, + onDetailsClick = onDetailsClick ) }, content = { padding -> @@ -249,6 +254,7 @@ private fun SpaceViewTopBar( currentSpace: SpaceRoom?, onBackClick: () -> Unit, onLeaveSpaceClick: () -> Unit, + onDetailsClick: () -> Unit, onShareSpace: () -> Unit, modifier: Modifier = Modifier, ) { @@ -259,9 +265,14 @@ private fun SpaceViewTopBar( }, title = { if (currentSpace != null) { + val roundedCornerShape = RoundedCornerShape(8.dp) SpaceAvatarAndNameRow( name = currentSpace.displayName, avatarData = currentSpace.getAvatarData(AvatarSize.TimelineRoom), + modifier = Modifier + .clip(roundedCornerShape) + // TODO enable when screen ready for space + .clickable(enabled = false, onClick = onDetailsClick) ) } }, @@ -391,6 +402,7 @@ internal fun SpaceViewPreview( onShareSpace = {}, onLeaveSpaceClick = {}, acceptDeclineInviteView = {}, + onDetailsClick = {}, onBackClick = {}, ) } diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt index 17823ba72b..13e24259dc 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt @@ -45,6 +45,7 @@ class DefaultSpaceEntryPointTest { } val callback = object : SpaceEntryPoint.Callback { override fun onOpenRoom(roomId: RoomId, viaParameters: List) = lambdaError() + override fun onOpenDetails() = lambdaError() } val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null)) .inputs(nodeInputs) diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt index 2702133780..f8797916e4 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt @@ -139,6 +139,7 @@ private fun AndroidComposeTestRule.setSpace onRoomClick: (SpaceRoom) -> Unit = EnsureNeverCalledWithParam(), onShareSpace: () -> Unit = EnsureNeverCalled(), onLeaveSpaceClick: () -> Unit = EnsureNeverCalled(), + onDetailsClick: () -> Unit = EnsureNeverCalled(), acceptDeclineInviteView: @Composable () -> Unit = {}, ) { setContent { @@ -148,6 +149,7 @@ private fun AndroidComposeTestRule.setSpace onRoomClick = onRoomClick, onShareSpace = onShareSpace, onLeaveSpaceClick = onLeaveSpaceClick, + onDetailsClick = onDetailsClick, acceptDeclineInviteView = acceptDeclineInviteView, ) } diff --git a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_0_en.png index 58d3ffea16..13b726fefb 100644 --- a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9583a29e680bee98819258e5b7356dd8677144957d5869da72c47685d986e87 -size 6494 +oid sha256:071914fc3e7bbc2fc6ef8a1b4544b9126c05dd08b2123666d320223582423226 +size 5632 diff --git a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_1_en.png index ef5c3290e1..db2c45090b 100644 --- a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c19a8b26c9187c9bfd630242b15370ec8f0b874f9d3913ce53c743c0e0bdcd -size 8574 +oid sha256:5e9df6017bd0771e1337f82b75d13a0a8a572156e6900ae72f208e9bb2aaddb7 +size 7717 diff --git a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_0_en.png index 05eb8b590c..1dddbda28f 100644 --- a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74ad11143fc70164f67a8326cb87ce90a2c8730317540810ea138e39fc9093fa -size 6306 +oid sha256:811bd4534f4f16530cea1489b62d393e2fe7bf1b18b859a924333cd9d309f8dd +size 5566 diff --git a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_1_en.png index 04b13d3533..53f10d4bd4 100644 --- a/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/appnav.room.joined_LoadingRoomNodeView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bde612ade7298aeef44bbc480ee9d742ccb8c94108e21dcae9e804c744032a08 -size 8308 +oid sha256:030971f2c5f8c19f47fed2fa207c6d84d536c603fa7705ea6c288736684b7868 +size 7553 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png index 8e0e2b04ab..0f62df3d20 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba78cafc20c3d865fec9c7ab92f90e2565f233b224f99fb0665ad0d0c3c2be4e -size 34607 +oid sha256:c55277089a4447b618a0e8c058718ecf9d3da6d437322f0e23e5fd70019f6b00 +size 34585 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png index 0e81c563f9..bb1c9d1947 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe62bb5d157ba1b4c7a4e4f443f4b1b3e7d68bc0ac59ce7edb6fbc99e2abbdf7 -size 34795 +oid sha256:241f5500cb7212fac174466bbe7855ccf39de3e3764a83202388b947d90ae807 +size 34770 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png index e692443bf6..6f624546ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88db0bd5d05963761bd3b3a5a97834f8937a9a0e10723238f2c104c5d03eb81a -size 35089 +oid sha256:92785cf3a4010779b0fbcd58be3437a22808b0a2f02a19a5cfd50eb3bd58ed26 +size 35058 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png index 9a129e53f4..8b5b2f5f27 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e8b65396dedff81056157620e2390c8d69954ee288266b575ac61aba16c2bec -size 62590 +oid sha256:de26882f13bac98b2cb5365d98e06e781d516d179adb8328cf22cf524e6fd79e +size 62568 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png index 2ac2e539b3..cfa8381d77 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8e1fb3b8b62ea8583a5bc9a18f39dbe71684e7d019bf63b22b873851b219209 -size 63270 +oid sha256:a121fdb9473512b0264e48294df1799a7a6bf9b469df973fbe41f31bbf98f1d0 +size 63248 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png index 0a12faa0bd..f20b7c4048 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e60857b4c0d801d3a6ad7f7383b8ff8428157763ca46d30c2a559a4957cb71e -size 59706 +oid sha256:a3506b4f646408262450ae51b612f86c1171ed972c1d7ea8871c4dc090556c7a +size 59702 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png index d27c35077e..e8f00148a3 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53b3736b922b746a996f71aa38b3937ebc16e37eb40bb57cd1991d6f9d98ea33 -size 34022 +oid sha256:f2407444889af236ef21a90c47a5d3e05df8b15b9cc9483e84377e3af8794772 +size 33996 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png index 2dcc62b1d5..6f012ad603 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f2d6b368d4a8eaa8f3a396ba6edf8252d52b0e7ebd3b3f416c60050d3cd3c57 -size 34170 +oid sha256:fee41efefc2ca1d6670d8455ac756c6b314aab54510eab8a4e597f1cc1edf3f8 +size 34141 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png index bebf4c51f7..24f916eac9 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b0b347f48ac09d05a2348383580d26e3725af2ef48558be86541afa239f3b06 -size 34485 +oid sha256:ea955839cbd1aeba5de2780cee413628c7d46383398b10125cd3a900fb41d5a5 +size 34459 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png index f932a63f92..153b68c3d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ff5ca08d441240de9e5adc35e41bceeb0f462979777345da4b2865e9a80012e -size 61405 +oid sha256:cba2c99744aeb2a869ae2ed700d7241b1d0b6ed979b16d2be9774ddbc5f8f28a +size 61381 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png index bcc1e494e8..f36d90e33c 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f35b63ac49c799a5b3b5ad47652fe0f199efbbd2a285f782170c1edcd9ae723 -size 61955 +oid sha256:b32d65accabc357208efeb2ec61374182479541299ade28184f82938e59bfdd5 +size 61932 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png index 4367883548..66a7762467 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f470577ca0f0de530db1ab0d531f5b14630f9082cc4c34ad4e3fcbc1ab9ee530 -size 57954 +oid sha256:7c161ff55e8a235fe403e53ee179b299fd2563d85ef64bfe6d0dd9295228685b +size 57925