Timeline permalink : branch permalink on event of other room

This commit is contained in:
ganfra 2024-04-23 18:02:12 +02:00
parent 1c06db1a78
commit 9b83cedac4
7 changed files with 41 additions and 16 deletions

View file

@ -282,7 +282,7 @@ class LoggedInFlowNode @AssistedInject constructor(
is PermalinkData.RoomLink -> { is PermalinkData.RoomLink -> {
backstack.push( backstack.push(
NavTarget.Room( NavTarget.Room(
data.roomIdOrAlias, roomIdOrAlias = data.roomIdOrAlias,
initialElement = RoomNavigationTarget.Messages(data.eventId), initialElement = RoomNavigationTarget.Messages(data.eventId),
// TODO Use the viaParameters // TODO Use the viaParameters
) )

View file

@ -80,7 +80,7 @@ class RoomFlowNode @AssistedInject constructor(
data class Inputs( data class Inputs(
val roomIdOrAlias: RoomIdOrAlias, val roomIdOrAlias: RoomIdOrAlias,
val roomDescription: Optional<RoomDescription>, val roomDescription: Optional<RoomDescription>,
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), val initialElement: RoomNavigationTarget,
) : NodeInputs ) : NodeInputs
private val inputs: Inputs = inputs() private val inputs: Inputs = inputs()
@ -166,7 +166,10 @@ class RoomFlowNode @AssistedInject constructor(
} }
is NavTarget.JoinedRoom -> { is NavTarget.JoinedRoom -> {
val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>() val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>()
val inputs = JoinedRoomFlowNode.Inputs(navTarget.roomId, initialElement = inputs.initialElement) val inputs = JoinedRoomFlowNode.Inputs(
roomId = navTarget.roomId,
initialElement = inputs.initialElement
)
createNode<JoinedRoomFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback) createNode<JoinedRoomFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback)
} }
} }

View file

@ -69,7 +69,7 @@ class JoinedRoomFlowNode @AssistedInject constructor(
) { ) {
data class Inputs( data class Inputs(
val roomId: RoomId, val roomId: RoomId,
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), val initialElement: RoomNavigationTarget,
) : NodeInputs ) : NodeInputs
private val inputs: Inputs = inputs() private val inputs: Inputs = inputs()
@ -106,7 +106,10 @@ class JoinedRoomFlowNode @AssistedInject constructor(
val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>() val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>()
val awaitRoomState = loadingRoomStateStateFlow.value val awaitRoomState = loadingRoomStateStateFlow.value
if (awaitRoomState is LoadingRoomState.Loaded) { 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<JoinedRoomLoadedFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback) createNode<JoinedRoomLoadedFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback)
} else { } else {
loadingNode(buildContext, this::navigateUp) loadingNode(buildContext, this::navigateUp)

View file

@ -84,7 +84,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
data class Inputs( data class Inputs(
val room: MatrixRoom, val room: MatrixRoom,
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(), val initialElement: RoomNavigationTarget,
) : NodeInputs ) : NodeInputs
private val inputs: Inputs = inputs() private val inputs: Inputs = inputs()

View file

@ -32,7 +32,7 @@ class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint {
return object : MessagesEntryPoint.NodeBuilder { return object : MessagesEntryPoint.NodeBuilder {
override fun params(params: MessagesEntryPoint.Params): MessagesEntryPoint.NodeBuilder { override fun params(params: MessagesEntryPoint.Params): MessagesEntryPoint.NodeBuilder {
plugins += MessagesNode.Inputs(focusedEventId = params.focusedEventId) plugins += MessagesFlowNode.Inputs(focusedEventId = params.focusedEventId)
return this return this
} }

View file

@ -54,6 +54,7 @@ import io.element.android.libraries.architecture.BackstackWithOverlayBox
import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.createNode 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.Overlay
import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.architecture.overlay.operation.show
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
@ -81,7 +82,7 @@ class MessagesFlowNode @AssistedInject constructor(
private val createPollEntryPoint: CreatePollEntryPoint, private val createPollEntryPoint: CreatePollEntryPoint,
) : BaseFlowNode<MessagesFlowNode.NavTarget>( ) : BaseFlowNode<MessagesFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.Messages(plugins.filterIsInstance<Inputs>().firstOrNull()?.focusedEventId), initialElement = NavTarget.Messages,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
), ),
overlay = Overlay( overlay = Overlay(
@ -91,15 +92,14 @@ class MessagesFlowNode @AssistedInject constructor(
plugins = plugins plugins = plugins
) { ) {
data class Inputs(val focusedEventId: EventId?) : NodeInputs data class Inputs(val focusedEventId: EventId?) : NodeInputs
private val inputs = inputs<Inputs>()
sealed interface NavTarget : Parcelable { sealed interface NavTarget : Parcelable {
@Parcelize @Parcelize
data object Empty : NavTarget data object Empty : NavTarget
@Parcelize @Parcelize
data class Messages( data object Messages: NavTarget
val focusedEventId: EventId? = null,
) : NavTarget
@Parcelize @Parcelize
data class MediaViewer( data class MediaViewer(
@ -191,10 +191,10 @@ class MessagesFlowNode @AssistedInject constructor(
ElementCallActivity.start(context, inputs) ElementCallActivity.start(context, inputs)
} }
} }
val params = MessagesNode.Inputs( val inputs = MessagesNode.Inputs(
focusedEventId = navTarget.focusedEventId, focusedEventId = inputs.focusedEventId,
) )
createNode<MessagesNode>(buildContext, listOf(callback, params)) createNode<MessagesNode>(buildContext, listOf(callback, inputs))
} }
is NavTarget.MediaViewer -> { is NavTarget.MediaViewer -> {
val inputs = MediaViewerNode.Inputs( val inputs = MediaViewerNode.Inputs(

View file

@ -19,6 +19,11 @@ package io.element.android.features.messages.impl
import android.content.Context import android.content.Context
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider 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.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import com.bumble.appyx.core.lifecycle.subscribe 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.openUrlInExternalApp
import io.element.android.libraries.androidutils.system.toast import io.element.android.libraries.androidutils.system.toast
import io.element.android.libraries.architecture.NodeInputs 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.core.bool.orFalse
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
@ -69,9 +75,10 @@ class MessagesNode @AssistedInject constructor(
private val presenter = presenterFactory.create(this) private val presenter = presenterFactory.create(this)
private val callback = plugins<Callback>().firstOrNull() private val callback = plugins<Callback>().firstOrNull()
// TODO Handle navigation to the Event
data class Inputs(val focusedEventId: EventId?) : NodeInputs data class Inputs(val focusedEventId: EventId?) : NodeInputs
private val inputs = inputs<Inputs>()
interface Callback : Plugin { interface Callback : Plugin {
fun onRoomDetailsClicked() fun onRoomDetailsClicked()
fun onEventClicked(event: TimelineItem.Event): Boolean fun onEventClicked(event: TimelineItem.Event): Boolean
@ -87,7 +94,8 @@ class MessagesNode @AssistedInject constructor(
fun onJoinCallClicked(roomId: RoomId) fun onJoinCallClicked(roomId: RoomId)
} }
init { override fun onBuilt() {
super.onBuilt()
lifecycle.subscribe( lifecycle.subscribe(
onCreate = { onCreate = {
analyticsService.capture(room.toAnalyticsViewRoom()) analyticsService.capture(room.toAnalyticsViewRoom())
@ -197,6 +205,17 @@ class MessagesNode @AssistedInject constructor(
onJoinCallClicked = this::onJoinCallClicked, onJoinCallClicked = this::onJoinCallClicked,
modifier = modifier, 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
}
} }
} }
} }