feature (room upgrade) : manage navigation and clean code.
This commit is contained in:
parent
94e678a905
commit
e8bc54cf9e
13 changed files with 69 additions and 54 deletions
|
|
@ -9,6 +9,7 @@ package io.element.android.features.messages.impl
|
|||
|
||||
import io.element.android.features.messages.impl.attachments.Attachment
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -19,4 +20,5 @@ interface MessagesNavigator {
|
|||
fun onReportContentClick(eventId: EventId, senderId: UserId)
|
||||
fun onEditPollClick(eventId: EventId)
|
||||
fun onPreviewAttachment(attachments: ImmutableList<Attachment>)
|
||||
fun onNavigateToRoom(roomId: RoomId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ 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.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom
|
||||
|
|
@ -71,6 +72,7 @@ import kotlinx.coroutines.launch
|
|||
class MessagesNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
@ApplicationContext private val context: Context,
|
||||
@SessionCoroutineScope
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val room: BaseRoom,
|
||||
|
|
@ -144,15 +146,6 @@ class MessagesNode @AssistedInject constructor(
|
|||
callbacks.forEach { it.onUserDataClick(userId) }
|
||||
}
|
||||
|
||||
private fun onRoomDataClick(
|
||||
activity: Activity,
|
||||
eventSink: (TimelineEvents) -> Unit,
|
||||
roomId: RoomId
|
||||
) {
|
||||
val roomLink = PermalinkData.RoomLink(roomId.toRoomIdOrAlias())
|
||||
handleRoomLinkClick(activity, roomLink, eventSink)
|
||||
}
|
||||
|
||||
private fun onLinkClick(
|
||||
activity: Activity,
|
||||
darkTheme: Boolean,
|
||||
|
|
@ -167,7 +160,7 @@ class MessagesNode @AssistedInject constructor(
|
|||
callbacks.forEach { it.onUserDataClick(permalink.userId) }
|
||||
}
|
||||
is PermalinkData.RoomLink -> {
|
||||
handleRoomLinkClick(activity, permalink, eventSink)
|
||||
handleRoomLinkClick(permalink, eventSink)
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
if (customTab) {
|
||||
|
|
@ -183,7 +176,6 @@ class MessagesNode @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleRoomLinkClick(
|
||||
context: Context,
|
||||
roomLink: PermalinkData.RoomLink,
|
||||
eventSink: (TimelineEvents) -> Unit,
|
||||
) {
|
||||
|
|
@ -193,7 +185,7 @@ class MessagesNode @AssistedInject constructor(
|
|||
eventSink(TimelineEvents.FocusOnEvent(eventId))
|
||||
} else {
|
||||
// Click on the same room, ignore
|
||||
context.toast("Already viewing this room!")
|
||||
context.sameRoomToast()
|
||||
}
|
||||
} else {
|
||||
callbacks.forEach { it.onPermalinkClick(roomLink) }
|
||||
|
|
@ -220,6 +212,15 @@ class MessagesNode @AssistedInject constructor(
|
|||
callbacks.forEach { it.onPreviewAttachments(attachments) }
|
||||
}
|
||||
|
||||
override fun onNavigateToRoom(roomId: RoomId) {
|
||||
if (roomId == room.roomId) {
|
||||
context.sameRoomToast()
|
||||
} else {
|
||||
val permalinkData = PermalinkData.RoomLink(roomId.toRoomIdOrAlias())
|
||||
callbacks.forEach { it.onPermalinkClick(permalinkData) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onViewAllPinnedMessagesClick() {
|
||||
callbacks.forEach { it.onViewAllPinnedEvents() }
|
||||
}
|
||||
|
|
@ -240,6 +241,10 @@ class MessagesNode @AssistedInject constructor(
|
|||
callbacks.forEach { it.onViewKnockRequests() }
|
||||
}
|
||||
|
||||
private fun Context.sameRoomToast() {
|
||||
context.toast("Already viewing this room!")
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val activity = requireNotNull(LocalActivity.current)
|
||||
|
|
@ -260,19 +265,18 @@ class MessagesNode @AssistedInject constructor(
|
|||
onRoomDetailsClick = this::onRoomDetailsClick,
|
||||
onEventContentClick = this::onEventClick,
|
||||
onUserDataClick = this::onUserDataClick,
|
||||
onRoomDataClick = {roomId -> onRoomDataClick(activity, state.timelineState.eventSink, roomId) },
|
||||
onLinkClick = { url, customTab -> onLinkClick(activity, isDark, url, state.timelineState.eventSink, customTab) },
|
||||
onSendLocationClick = this::onSendLocationClick,
|
||||
onCreatePollClick = this::onCreatePollClick,
|
||||
onJoinCallClick = this::onJoinCallClick,
|
||||
onViewAllPinnedMessagesClick = this::onViewAllPinnedMessagesClick,
|
||||
modifier = modifier,
|
||||
knockRequestsBannerView = {
|
||||
knockRequestsBannerRenderer.View(
|
||||
modifier = Modifier,
|
||||
onViewRequestsClick = this::onViewKnockRequestsClick
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
roomMemberModerationRenderer.Render(
|
||||
state = state.roomMemberModerationState,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ fun MessagesView(
|
|||
onRoomDetailsClick: () -> Unit,
|
||||
onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean,
|
||||
onUserDataClick: (UserId) -> Unit,
|
||||
onRoomDataClick: (RoomId) -> Unit,
|
||||
onLinkClick: (String, Boolean) -> Unit,
|
||||
onSendLocationClick: () -> Unit,
|
||||
onCreatePollClick: () -> Unit,
|
||||
|
|
@ -210,11 +209,10 @@ fun MessagesView(
|
|||
MessagesViewContent(
|
||||
state = state,
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding),
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding),
|
||||
onContentClick = ::onContentClick,
|
||||
onMessageLongClick = ::onMessageLongClick,
|
||||
onRoomSuccessorClicked = onRoomDataClick,
|
||||
onUserDataClick = {
|
||||
hidingKeyboard {
|
||||
state.eventSink(MessagesEvents.OnUserClicked(it))
|
||||
|
|
@ -305,7 +303,6 @@ private fun MessagesViewContent(
|
|||
state: MessagesState,
|
||||
onContentClick: (TimelineItem.Event) -> Unit,
|
||||
onUserDataClick: (MatrixUser) -> Unit,
|
||||
onRoomSuccessorClicked: (RoomId) -> Unit,
|
||||
onLinkClick: (Link, Boolean) -> Unit,
|
||||
onReactionClick: (key: String, TimelineItem.Event) -> Unit,
|
||||
onReactionLongClick: (key: String, TimelineItem.Event) -> Unit,
|
||||
|
|
@ -323,9 +320,9 @@ private fun MessagesViewContent(
|
|||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding()
|
||||
.imePadding(),
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding()
|
||||
.imePadding(),
|
||||
) {
|
||||
AttachmentsBottomSheet(
|
||||
state = state.composerState,
|
||||
|
|
@ -417,7 +414,9 @@ private fun MessagesViewContent(
|
|||
MessagesViewComposerBottomSheetContents(
|
||||
subcomposing = subcomposing,
|
||||
state = state,
|
||||
onRoomSuccessorClicked = onRoomSuccessorClicked,
|
||||
onRoomSuccessorClick = { roomId ->
|
||||
state.timelineState.eventSink(TimelineEvents.NavigateToRoom(roomId = roomId))
|
||||
},
|
||||
onLinkClick = { url, customTab -> onLinkClick(Link(url), customTab) },
|
||||
)
|
||||
},
|
||||
|
|
@ -432,12 +431,12 @@ private fun MessagesViewContent(
|
|||
private fun MessagesViewComposerBottomSheetContents(
|
||||
subcomposing: Boolean,
|
||||
state: MessagesState,
|
||||
onRoomSuccessorClicked: (RoomId) -> Unit,
|
||||
onRoomSuccessorClick: (RoomId) -> Unit,
|
||||
onLinkClick: (String, Boolean) -> Unit,
|
||||
) {
|
||||
when {
|
||||
state.successorRoom != null -> {
|
||||
SuccessorRoomBanner(roomSuccessor = state.successorRoom, onRoomSuccessorClicked = onRoomSuccessorClicked)
|
||||
SuccessorRoomBanner(roomSuccessor = state.successorRoom, onRoomSuccessorClick = onRoomSuccessorClick)
|
||||
}
|
||||
state.userEventPermissions.canSendMessage -> {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
|
|
@ -508,8 +507,8 @@ private fun MessagesViewTopBar(
|
|||
val roundedCornerShape = RoundedCornerShape(8.dp)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(roundedCornerShape)
|
||||
.clickable { onRoomDetailsClick() },
|
||||
.clip(roundedCornerShape)
|
||||
.clickable { onRoomDetailsClick() },
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
|
|
@ -605,17 +604,17 @@ private fun CantSendMessageBanner() {
|
|||
|
||||
@Composable
|
||||
private fun SuccessorRoomBanner(
|
||||
modifier: Modifier = Modifier,
|
||||
roomSuccessor: SuccessorRoom,
|
||||
onRoomSuccessorClicked: (RoomId) -> Unit
|
||||
onRoomSuccessorClick: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ComposerAlertMolecule(
|
||||
avatar = null,
|
||||
content = "This room has been replaced and is no longer active".toAnnotatedString(),
|
||||
onSubmitClick = { onRoomSuccessorClicked(roomSuccessor.roomId)},
|
||||
content = stringResource(R.string.screen_room_timeline_tombstoned_room_message).toAnnotatedString(),
|
||||
onSubmitClick = { onRoomSuccessorClick(roomSuccessor.roomId) },
|
||||
modifier = modifier,
|
||||
isCritical = false,
|
||||
submitText = "Jump to new room"
|
||||
submitText = stringResource(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +627,6 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
|
|||
onRoomDetailsClick = {},
|
||||
onEventContentClick = { _, _ -> false },
|
||||
onUserDataClick = {},
|
||||
onRoomDataClick = { },
|
||||
onLinkClick = { _, _ -> },
|
||||
onSendLocationClick = {},
|
||||
onCreatePollClick = {},
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ internal fun MessagesViewWithIdentityChangePreview(
|
|||
onCreatePollClick = {},
|
||||
onJoinCallClick = {},
|
||||
onViewAllPinnedMessagesClick = {},
|
||||
onRoomDataClick = {},
|
||||
knockRequestsBannerView = {}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.messages.impl.timeline
|
|||
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
|
||||
import kotlin.time.Duration
|
||||
|
|
@ -30,6 +31,7 @@ sealed interface TimelineEvents {
|
|||
data class ComputeVerifiedUserSendFailure(val event: TimelineItem.Event) : EventFromTimelineItem
|
||||
data class ShowShieldDialog(val messageShield: MessageShield) : EventFromTimelineItem
|
||||
data class LoadMore(val direction: Timeline.PaginationDirection) : EventFromTimelineItem
|
||||
data class NavigateToRoom(val roomId: RoomId) : EventFromTimelineItem
|
||||
|
||||
/**
|
||||
* Events coming from a poll item.
|
||||
|
|
|
|||
|
|
@ -178,6 +178,9 @@ class TimelinePresenter @AssistedInject constructor(
|
|||
is TimelineEvents.ComputeVerifiedUserSendFailure -> {
|
||||
resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvents.ComputeForMessage(event.event))
|
||||
}
|
||||
is TimelineEvents.NavigateToRoom -> {
|
||||
navigator.onNavigateToRoom(event.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,15 @@ fun TimelineItemVirtualRow(
|
|||
when (virtual.model) {
|
||||
is TimelineItemDaySeparatorModel -> TimelineItemDaySeparatorView(virtual.model)
|
||||
TimelineItemReadMarkerModel -> TimelineItemReadMarkerView()
|
||||
TimelineItemRoomBeginningModel -> TimelineItemRoomBeginningView(predecessorRoom = timelineRoomInfo.predecessorRoom, roomName = timelineRoomInfo.name)
|
||||
TimelineItemRoomBeginningModel -> {
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = timelineRoomInfo.predecessorRoom,
|
||||
roomName = timelineRoomInfo.name,
|
||||
onPredecessorRoomClick = { roomId ->
|
||||
eventSink(TimelineEvents.NavigateToRoom(roomId))
|
||||
},
|
||||
)
|
||||
}
|
||||
is TimelineItemLoadingIndicatorModel -> {
|
||||
TimelineLoadingMoreIndicator(virtual.model.direction)
|
||||
val latestEventSink by rememberUpdatedState(eventSink)
|
||||
|
|
|
|||
|
|
@ -31,28 +31,28 @@ import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
|||
|
||||
@Composable
|
||||
fun TimelineItemRoomBeginningView(
|
||||
predecessorRoom: PredecessorRoom?,
|
||||
roomName: String?,
|
||||
predecessorRoom: PredecessorRoom?,
|
||||
onPredecessorRoomClick: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier =modifier.fillMaxWidth()
|
||||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
if(predecessorRoom != null) {
|
||||
if (predecessorRoom != null) {
|
||||
ComposerAlertMolecule(
|
||||
avatar = null,
|
||||
content = "This room is a continuation of another room".toAnnotatedString(),
|
||||
onSubmitClick = { },
|
||||
modifier = modifier,
|
||||
content = stringResource(R.string.screen_room_timeline_upgraded_room_message).toAnnotatedString(),
|
||||
onSubmitClick = { onPredecessorRoomClick(predecessorRoom.roomId) },
|
||||
isCritical = false,
|
||||
submitText = "See old messages"
|
||||
submitText = stringResource(R.string.screen_room_timeline_upgraded_room_action)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val text = if (roomName == null) {
|
||||
|
|
@ -70,22 +70,24 @@ fun TimelineItemRoomBeginningView(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TimelineItemRoomBeginningViewPreview() = ElementPreview {
|
||||
Column(verticalArrangement = spacedBy(16.dp)){
|
||||
Column(verticalArrangement = spacedBy(16.dp)) {
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = null,
|
||||
roomName = null,
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = null,
|
||||
roomName = "Room Name",
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = PredecessorRoom(RoomId("!roomId:matrix.org"),EventId("\$eventId:matrix.org") ),
|
||||
predecessorRoom = PredecessorRoom(RoomId("!roomId:matrix.org"), EventId("\$eventId:matrix.org")),
|
||||
roomName = "Room Name",
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ import androidx.compose.ui.unit.dp
|
|||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.toAnnotatedString
|
||||
|
|
@ -71,7 +69,7 @@ fun ComposerAlertMolecule(
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
if(avatar != null) {
|
||||
if (avatar != null) {
|
||||
Avatar(avatarData = avatar)
|
||||
}
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ interface BaseRoom : Closeable {
|
|||
* @param reason - The reason the room is being reported.
|
||||
*/
|
||||
suspend fun reportRoom(reason: String?): Result<Unit>
|
||||
|
||||
/**
|
||||
* Destroy the room and release all resources associated to it.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.UserId
|
|||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.impl.room.history.map
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
|
|
@ -29,7 +28,6 @@ import uniffi.matrix_sdk_base.EncryptionState
|
|||
import org.matrix.rustcomponents.sdk.Membership as RustMembership
|
||||
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
import org.matrix.rustcomponents.sdk.SuccessorRoom as RustSuccessorRoom
|
||||
|
||||
class RoomInfoMapper {
|
||||
fun map(rustRoomInfo: RustRoomInfo): RoomInfo = rustRoomInfo.let {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue