[Room details] Open room member details when clicking on user data in timeline (#482)
This commit is contained in:
parent
d7448c7acc
commit
b50350aaa0
15 changed files with 99 additions and 16 deletions
|
|
@ -39,6 +39,7 @@ import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
|
|
@ -119,11 +120,20 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
override fun onRoomDetailsClicked() {
|
override fun onRoomDetailsClicked() {
|
||||||
backstack.push(NavTarget.RoomDetails)
|
backstack.push(NavTarget.RoomDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUserDataClicked(userId: UserId) {
|
||||||
|
backstack.push(NavTarget.RoomMemberDetails(userId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
messagesEntryPoint.createNode(this, buildContext, callback)
|
messagesEntryPoint.createNode(this, buildContext, callback)
|
||||||
}
|
}
|
||||||
NavTarget.RoomDetails -> {
|
NavTarget.RoomDetails -> {
|
||||||
roomDetailsEntryPoint.createNode(this, buildContext, emptyList())
|
val inputs = RoomDetailsEntryPoint.Inputs(RoomDetailsEntryPoint.InitialTarget.RoomDetails)
|
||||||
|
roomDetailsEntryPoint.createNode(this, buildContext, inputs, emptyList())
|
||||||
|
}
|
||||||
|
is NavTarget.RoomMemberDetails -> {
|
||||||
|
val inputs = RoomDetailsEntryPoint.Inputs(RoomDetailsEntryPoint.InitialTarget.RoomMemberDetails(navTarget.userId))
|
||||||
|
roomDetailsEntryPoint.createNode(this, buildContext, inputs, emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,6 +144,9 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
object RoomDetails : NavTarget
|
object RoomDetails : NavTarget
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class RoomMemberDetails(val userId: UserId) : NavTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
private val timeline = inputs.room.timeline()
|
private val timeline = inputs.room.timeline()
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,12 @@ class RoomFlowNodeTest {
|
||||||
|
|
||||||
var nodeId: String? = null
|
var nodeId: String? = null
|
||||||
|
|
||||||
override fun createNode(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
override fun createNode(
|
||||||
|
parentNode: Node,
|
||||||
|
buildContext: BuildContext,
|
||||||
|
inputs: RoomDetailsEntryPoint.Inputs,
|
||||||
|
plugins: List<Plugin>
|
||||||
|
): Node {
|
||||||
return node(buildContext) {}.also {
|
return node(buildContext) {}.also {
|
||||||
nodeId = it.id
|
nodeId = it.id
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
changelog.d/480.feature
Normal file
1
changelog.d/480.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Open room member details when tapping on a user in the timeline
|
||||||
|
|
@ -20,6 +20,7 @@ import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
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.UserId
|
||||||
|
|
||||||
interface MessagesEntryPoint : FeatureEntryPoint {
|
interface MessagesEntryPoint : FeatureEntryPoint {
|
||||||
fun createNode(
|
fun createNode(
|
||||||
|
|
@ -30,5 +31,6 @@ interface MessagesEntryPoint : FeatureEntryPoint {
|
||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onRoomDetailsClicked()
|
fun onRoomDetailsClicked()
|
||||||
|
fun onUserDataClicked(userId: UserId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.libraries.architecture.BackstackNode
|
import io.element.android.libraries.architecture.BackstackNode
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
@ -89,6 +90,10 @@ class MessagesFlowNode @AssistedInject constructor(
|
||||||
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
|
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
|
||||||
backstack.push(NavTarget.AttachmentPreview(attachments.first()))
|
backstack.push(NavTarget.AttachmentPreview(attachments.first()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUserDataClicked(userId: UserId) {
|
||||||
|
callback?.onUserDataClicked(userId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
createNode<MessagesNode>(buildContext, listOf(callback))
|
createNode<MessagesNode>(buildContext, listOf(callback))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.features.messages.impl.attachments.Attachment
|
import io.element.android.features.messages.impl.attachments.Attachment
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@ContributesNode(RoomScope::class)
|
@ContributesNode(RoomScope::class)
|
||||||
|
|
@ -43,6 +44,7 @@ class MessagesNode @AssistedInject constructor(
|
||||||
fun onRoomDetailsClicked()
|
fun onRoomDetailsClicked()
|
||||||
fun onEventClicked(event: TimelineItem.Event)
|
fun onEventClicked(event: TimelineItem.Event)
|
||||||
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
|
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
|
||||||
|
fun onUserDataClicked(userId: UserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onRoomDetailsClicked() {
|
private fun onRoomDetailsClicked() {
|
||||||
|
|
@ -57,6 +59,10 @@ class MessagesNode @AssistedInject constructor(
|
||||||
callback?.onPreviewAttachments(attachments)
|
callback?.onPreviewAttachments(attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onUserDataClicked(userId: UserId) {
|
||||||
|
callback?.onUserDataClicked(userId)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
|
|
@ -66,6 +72,7 @@ class MessagesNode @AssistedInject constructor(
|
||||||
onRoomDetailsClicked = this::onRoomDetailsClicked,
|
onRoomDetailsClicked = this::onRoomDetailsClicked,
|
||||||
onEventClicked = this::onEventClicked,
|
onEventClicked = this::onEventClicked,
|
||||||
onPreviewAttachments = this::onPreviewAttachments,
|
onPreviewAttachments = this::onPreviewAttachments,
|
||||||
|
onUserDataClicked = this::onUserDataClicked,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -97,6 +98,7 @@ fun MessagesView(
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
onRoomDetailsClicked: () -> Unit,
|
onRoomDetailsClicked: () -> Unit,
|
||||||
onEventClicked: (event: TimelineItem.Event) -> Unit,
|
onEventClicked: (event: TimelineItem.Event) -> Unit,
|
||||||
|
onUserDataClicked: (UserId) -> Unit,
|
||||||
onPreviewAttachments: (ImmutableList<Attachment>) -> Unit,
|
onPreviewAttachments: (ImmutableList<Attachment>) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -203,6 +205,7 @@ fun MessagesView(
|
||||||
.consumeWindowInsets(padding),
|
.consumeWindowInsets(padding),
|
||||||
onMessageClicked = ::onMessageClicked,
|
onMessageClicked = ::onMessageClicked,
|
||||||
onMessageLongClicked = ::onMessageLongClicked,
|
onMessageLongClicked = ::onMessageLongClicked,
|
||||||
|
onUserDataClicked = onUserDataClicked,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = {
|
||||||
|
|
@ -240,6 +243,7 @@ fun MessagesViewContent(
|
||||||
state: MessagesState,
|
state: MessagesState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onMessageClicked: (TimelineItem.Event) -> Unit = {},
|
onMessageClicked: (TimelineItem.Event) -> Unit = {},
|
||||||
|
onUserDataClicked: (UserId) -> Unit = {},
|
||||||
onMessageLongClicked: (TimelineItem.Event) -> Unit = {},
|
onMessageLongClicked: (TimelineItem.Event) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -255,6 +259,7 @@ fun MessagesViewContent(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
onMessageClicked = onMessageClicked,
|
onMessageClicked = onMessageClicked,
|
||||||
onMessageLongClicked = onMessageLongClicked,
|
onMessageLongClicked = onMessageLongClicked,
|
||||||
|
onUserDataClicked = onUserDataClicked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
MessageComposerView(
|
MessageComposerView(
|
||||||
|
|
@ -354,6 +359,7 @@ private fun ContentToPreview(state: MessagesState) {
|
||||||
onBackPressed = {},
|
onBackPressed = {},
|
||||||
onRoomDetailsClicked = {},
|
onRoomDetailsClicked = {},
|
||||||
onEventClicked = {},
|
onEventClicked = {},
|
||||||
onPreviewAttachments = {}
|
onPreviewAttachments = {},
|
||||||
|
onUserDataClicked = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.timeline
|
||||||
|
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
|
|
@ -87,6 +88,7 @@ import io.element.android.libraries.designsystem.theme.LocalColors
|
||||||
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -95,6 +97,7 @@ import kotlinx.coroutines.launch
|
||||||
fun TimelineView(
|
fun TimelineView(
|
||||||
state: TimelineState,
|
state: TimelineState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
onUserDataClicked: (UserId) -> Unit = {},
|
||||||
onMessageClicked: (TimelineItem.Event) -> Unit = {},
|
onMessageClicked: (TimelineItem.Event) -> Unit = {},
|
||||||
onMessageLongClicked: (TimelineItem.Event) -> Unit = {},
|
onMessageLongClicked: (TimelineItem.Event) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
|
@ -120,6 +123,7 @@ fun TimelineView(
|
||||||
highlightedItem = state.highlightedEventId?.value,
|
highlightedItem = state.highlightedEventId?.value,
|
||||||
onClick = onMessageClicked,
|
onClick = onMessageClicked,
|
||||||
onLongClick = onMessageLongClicked,
|
onLongClick = onMessageLongClicked,
|
||||||
|
onUserDataClick = onUserDataClicked,
|
||||||
)
|
)
|
||||||
if (index == state.timelineItems.lastIndex) {
|
if (index == state.timelineItems.lastIndex) {
|
||||||
onReachedLoadMore()
|
onReachedLoadMore()
|
||||||
|
|
@ -139,6 +143,7 @@ fun TimelineView(
|
||||||
fun TimelineItemRow(
|
fun TimelineItemRow(
|
||||||
timelineItem: TimelineItem,
|
timelineItem: TimelineItem,
|
||||||
highlightedItem: String?,
|
highlightedItem: String?,
|
||||||
|
onUserDataClick: (UserId) -> Unit,
|
||||||
onClick: (TimelineItem.Event) -> Unit,
|
onClick: (TimelineItem.Event) -> Unit,
|
||||||
onLongClick: (TimelineItem.Event) -> Unit,
|
onLongClick: (TimelineItem.Event) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
|
|
@ -173,6 +178,7 @@ fun TimelineItemRow(
|
||||||
isHighlighted = highlightedItem == timelineItem.identifier(),
|
isHighlighted = highlightedItem == timelineItem.identifier(),
|
||||||
onClick = ::onClick,
|
onClick = ::onClick,
|
||||||
onLongClick = ::onLongClick,
|
onLongClick = ::onLongClick,
|
||||||
|
onUserDataClick = onUserDataClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -203,6 +209,7 @@ fun TimelineItemRow(
|
||||||
highlightedItem = highlightedItem,
|
highlightedItem = highlightedItem,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
|
onUserDataClick = onUserDataClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -230,15 +237,21 @@ fun TimelineItemEventRow(
|
||||||
isHighlighted: Boolean,
|
isHighlighted: Boolean,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
|
onUserDataClick: (UserId) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
|
||||||
|
fun onUserDataClicked() {
|
||||||
|
onUserDataClick(event.senderId)
|
||||||
|
}
|
||||||
|
|
||||||
val (parentAlignment, contentAlignment) = if (event.isMine) {
|
val (parentAlignment, contentAlignment) = if (event.isMine) {
|
||||||
Pair(Alignment.CenterEnd, Alignment.End)
|
Pair(Alignment.CenterEnd, Alignment.End)
|
||||||
} else {
|
} else {
|
||||||
Pair(Alignment.CenterStart, Alignment.Start)
|
Pair(Alignment.CenterStart, Alignment.Start)
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|
@ -257,6 +270,7 @@ fun TimelineItemEventRow(
|
||||||
Modifier
|
Modifier
|
||||||
.zIndex(1f)
|
.zIndex(1f)
|
||||||
.offset(y = 12.dp)
|
.offset(y = 12.dp)
|
||||||
|
.clickable(onClick = ::onUserDataClicked)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val bubbleState = BubbleState(
|
val bubbleState = BubbleState(
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("io.element.android-library")
|
id("io.element.android-library")
|
||||||
|
id("kotlin-parcelize")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,26 @@
|
||||||
|
|
||||||
package io.element.android.features.roomdetails.api
|
package io.element.android.features.roomdetails.api
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
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.architecture.NodeInputs
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
interface RoomDetailsEntryPoint : FeatureEntryPoint {
|
interface RoomDetailsEntryPoint : FeatureEntryPoint {
|
||||||
fun createNode(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node
|
|
||||||
|
sealed interface InitialTarget : Parcelable {
|
||||||
|
@Parcelize
|
||||||
|
object RoomDetails : InitialTarget
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class RoomMemberDetails(val roomMemberId: UserId) : InitialTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Inputs(val initialElement: InitialTarget) : NodeInputs
|
||||||
|
|
||||||
|
fun createNode(parentNode: Node, buildContext: BuildContext, inputs: Inputs, plugins: List<Plugin>): Node
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,25 @@ import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
||||||
|
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint.InitialTarget
|
||||||
|
import io.element.android.features.roomdetails.impl.RoomDetailsFlowNode.NavTarget
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultRoomDetailsEntryPoint @Inject constructor() : RoomDetailsEntryPoint {
|
class DefaultRoomDetailsEntryPoint @Inject constructor() : RoomDetailsEntryPoint {
|
||||||
override fun createNode(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
override fun createNode(
|
||||||
return parentNode.createNode<RoomDetailsFlowNode>(buildContext, plugins)
|
parentNode: Node,
|
||||||
|
buildContext: BuildContext,
|
||||||
|
inputs: RoomDetailsEntryPoint.Inputs,
|
||||||
|
plugins: List<Plugin>
|
||||||
|
): Node {
|
||||||
|
return parentNode.createNode<RoomDetailsFlowNode>(buildContext, plugins + inputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun InitialTarget.toNavTarget() = when (this) {
|
||||||
|
is InitialTarget.RoomDetails -> NavTarget.RoomDetails
|
||||||
|
is InitialTarget.RoomMemberDetails -> NavTarget.RoomMemberDetails(roomMemberId)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
||||||
import io.element.android.features.roomdetails.impl.invite.RoomInviteMembersNode
|
import io.element.android.features.roomdetails.impl.invite.RoomInviteMembersNode
|
||||||
import io.element.android.features.roomdetails.impl.members.RoomMemberListNode
|
import io.element.android.features.roomdetails.impl.members.RoomMemberListNode
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode
|
||||||
|
|
@ -44,7 +45,7 @@ class RoomDetailsFlowNode @AssistedInject constructor(
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
) : BackstackNode<RoomDetailsFlowNode.NavTarget>(
|
) : BackstackNode<RoomDetailsFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.RoomDetails,
|
initialElement = plugins.filterIsInstance<RoomDetailsEntryPoint.Inputs>().first().initialElement.toNavTarget(),
|
||||||
savedStateMap = buildContext.savedStateMap,
|
savedStateMap = buildContext.savedStateMap,
|
||||||
),
|
),
|
||||||
buildContext = buildContext,
|
buildContext = buildContext,
|
||||||
|
|
@ -95,7 +96,8 @@ class RoomDetailsFlowNode @AssistedInject constructor(
|
||||||
createNode<RoomInviteMembersNode>(buildContext)
|
createNode<RoomInviteMembersNode>(buildContext)
|
||||||
}
|
}
|
||||||
is NavTarget.RoomMemberDetails -> {
|
is NavTarget.RoomMemberDetails -> {
|
||||||
createNode<RoomMemberDetailsNode>(buildContext, listOf(RoomMemberDetailsNode.Inputs(navTarget.roomMemberId)))
|
val plugins = listOf(RoomMemberDetailsNode.RoomMemberDetailsInput(navTarget.roomMemberId))
|
||||||
|
createNode<RoomMemberDetailsNode>(buildContext, plugins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ class RoomMemberDetailsNode @AssistedInject constructor(
|
||||||
presenterFactory: RoomMemberDetailsPresenter.Factory,
|
presenterFactory: RoomMemberDetailsPresenter.Factory,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
data class Inputs(
|
data class RoomMemberDetailsInput(
|
||||||
val roomMemberId: UserId,
|
val roomMemberId: UserId
|
||||||
) : NodeInputs
|
) : NodeInputs
|
||||||
|
|
||||||
private val inputs = inputs<Inputs>()
|
private val inputs = inputs<RoomMemberDetailsInput>()
|
||||||
private val presenter = presenterFactory.create(inputs.roomMemberId)
|
private val presenter = presenterFactory.create(inputs.roomMemberId)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import io.element.android.libraries.core.bool.orFalse
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
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.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.ui.room.getRoomMember
|
import io.element.android.libraries.matrix.ui.room.getRoomMemberAsState
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ class RoomMemberDetailsPresenter @AssistedInject constructor(
|
||||||
override fun present(): RoomMemberDetailsState {
|
override fun present(): RoomMemberDetailsState {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
var confirmationDialog by remember { mutableStateOf<ConfirmationDialog?>(null) }
|
var confirmationDialog by remember { mutableStateOf<ConfirmationDialog?>(null) }
|
||||||
val roomMember by room.getRoomMember(roomMemberId)
|
val roomMember by room.getRoomMemberAsState(roomMemberId)
|
||||||
// the room member is not really live...
|
// the room member is not really live...
|
||||||
val isBlocked = remember {
|
val isBlocked = remember {
|
||||||
mutableStateOf(roomMember?.isIgnored.orFalse())
|
mutableStateOf(roomMember?.isIgnored.orFalse())
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,13 @@ import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MatrixRoom.getRoomMember(userId: UserId): State<RoomMember?> {
|
fun MatrixRoom.getRoomMemberAsState(userId: UserId): State<RoomMember?> {
|
||||||
val roomMembersState by membersStateFlow.collectAsState()
|
val roomMembersState by membersStateFlow.collectAsState()
|
||||||
return getRoomMember(roomMembersState = roomMembersState, userId = userId)
|
return getRoomMemberAsState(roomMembersState = roomMembersState, userId = userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getRoomMember(roomMembersState: MatrixRoomMembersState, userId: UserId): State<RoomMember?> {
|
fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserId): State<RoomMember?> {
|
||||||
val roomMembers = roomMembersState.roomMembers()
|
val roomMembers = roomMembersState.roomMembers()
|
||||||
return remember(roomMembers) {
|
return remember(roomMembers) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue