Timeline permalink : branch permalink on event of other room
This commit is contained in:
parent
1c06db1a78
commit
9b83cedac4
7 changed files with 41 additions and 16 deletions
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue