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 83cfd5f1f3..ecff658963 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -282,7 +282,7 @@ class LoggedInFlowNode @AssistedInject constructor( is PermalinkData.RoomLink -> { backstack.push( NavTarget.Room( - data.roomIdOrAlias, + roomIdOrAlias = data.roomIdOrAlias, initialElement = RoomNavigationTarget.Messages(data.eventId), // TODO Use the viaParameters ) 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 6d6405c0e8..f397713d08 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 @@ -80,7 +80,7 @@ class RoomFlowNode @AssistedInject constructor( data class Inputs( val roomIdOrAlias: RoomIdOrAlias, val roomDescription: Optional, - val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), + val initialElement: RoomNavigationTarget, ) : NodeInputs private val inputs: Inputs = inputs() @@ -166,7 +166,10 @@ class RoomFlowNode @AssistedInject constructor( } is NavTarget.JoinedRoom -> { val roomFlowNodeCallback = plugins() - val inputs = JoinedRoomFlowNode.Inputs(navTarget.roomId, initialElement = inputs.initialElement) + val inputs = JoinedRoomFlowNode.Inputs( + roomId = navTarget.roomId, + initialElement = inputs.initialElement + ) createNode(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback) } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomFlowNode.kt index ae8d03be33..49bcb53048 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomFlowNode.kt @@ -69,7 +69,7 @@ class JoinedRoomFlowNode @AssistedInject constructor( ) { data class Inputs( val roomId: RoomId, - val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), + val initialElement: RoomNavigationTarget, ) : NodeInputs private val inputs: Inputs = inputs() @@ -106,7 +106,10 @@ class JoinedRoomFlowNode @AssistedInject constructor( val roomFlowNodeCallback = plugins() val awaitRoomState = loadingRoomStateStateFlow.value if (awaitRoomState is LoadingRoomState.Loaded) { - val inputs = JoinedRoomLoadedFlowNode.Inputs(awaitRoomState.room, initialElement = inputs.initialElement) + val inputs = JoinedRoomLoadedFlowNode.Inputs( + room = awaitRoomState.room, + initialElement = inputs.initialElement + ) createNode(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback) } else { loadingNode(buildContext, this::navigateUp) 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 5f9a6b6eb3..142b658e5e 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 @@ -84,7 +84,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( data class Inputs( val room: MatrixRoom, - val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), + val initialElement: RoomNavigationTarget, ) : NodeInputs private val inputs: Inputs = inputs() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt index 73ab29bfeb..0f6a6358d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt @@ -32,7 +32,7 @@ class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint { return object : MessagesEntryPoint.NodeBuilder { override fun params(params: MessagesEntryPoint.Params): MessagesEntryPoint.NodeBuilder { - plugins += MessagesNode.Inputs(focusedEventId = params.focusedEventId) + plugins += MessagesFlowNode.Inputs(focusedEventId = params.focusedEventId) return this } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index f92214b679..c77907a855 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -54,6 +54,7 @@ import io.element.android.libraries.architecture.BackstackWithOverlayBox 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.architecture.overlay.Overlay import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.di.ApplicationContext @@ -81,7 +82,7 @@ class MessagesFlowNode @AssistedInject constructor( private val createPollEntryPoint: CreatePollEntryPoint, ) : BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.Messages(plugins.filterIsInstance().firstOrNull()?.focusedEventId), + initialElement = NavTarget.Messages, savedStateMap = buildContext.savedStateMap, ), overlay = Overlay( @@ -91,15 +92,14 @@ class MessagesFlowNode @AssistedInject constructor( plugins = plugins ) { data class Inputs(val focusedEventId: EventId?) : NodeInputs + private val inputs = inputs() sealed interface NavTarget : Parcelable { @Parcelize data object Empty : NavTarget @Parcelize - data class Messages( - val focusedEventId: EventId? = null, - ) : NavTarget + data object Messages: NavTarget @Parcelize data class MediaViewer( @@ -191,10 +191,10 @@ class MessagesFlowNode @AssistedInject constructor( ElementCallActivity.start(context, inputs) } } - val params = MessagesNode.Inputs( - focusedEventId = navTarget.focusedEventId, + val inputs = MessagesNode.Inputs( + focusedEventId = inputs.focusedEventId, ) - createNode(buildContext, listOf(callback, params)) + createNode(buildContext, listOf(callback, inputs)) } is NavTarget.MediaViewer -> { val inputs = MediaViewerNode.Inputs( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 70e077eb04..634aca1733 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -19,6 +19,11 @@ package io.element.android.features.messages.impl import android.content.Context import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import com.bumble.appyx.core.lifecycle.subscribe @@ -37,6 +42,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.androidutils.system.openUrlInExternalApp import io.element.android.libraries.androidutils.system.toast import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.RoomScope @@ -69,9 +75,10 @@ class MessagesNode @AssistedInject constructor( private val presenter = presenterFactory.create(this) private val callback = plugins().firstOrNull() - // TODO Handle navigation to the Event data class Inputs(val focusedEventId: EventId?) : NodeInputs + private val inputs = inputs() + interface Callback : Plugin { fun onRoomDetailsClicked() fun onEventClicked(event: TimelineItem.Event): Boolean @@ -87,7 +94,8 @@ class MessagesNode @AssistedInject constructor( fun onJoinCallClicked(roomId: RoomId) } - init { + override fun onBuilt() { + super.onBuilt() lifecycle.subscribe( onCreate = { analyticsService.capture(room.toAnalyticsViewRoom()) @@ -197,6 +205,17 @@ class MessagesNode @AssistedInject constructor( onJoinCallClicked = this::onJoinCallClicked, modifier = modifier, ) + + var focusedEventId by rememberSaveable { + mutableStateOf(inputs.focusedEventId) + } + LaunchedEffect(Unit) { + focusedEventId?.also { eventId -> + state.timelineState.eventSink(TimelineEvents.FocusOnEvent(eventId)) + } + // Reset the focused event id to null to avoid refocusing when restoring node. + focusedEventId = null + } } } }