From 6dab7aa555e4eac5e91c6da6ba054bc8e2dfa696 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 2 Dec 2022 14:37:25 +0100 Subject: [PATCH] Timeline: extract highlightedEventId on viewState instead of individual timeline item --- .../MessageTimelineItemStateFactory.kt | 4 ---- .../x/features/messages/MessagesScreen.kt | 21 ++++++++++++---- .../x/features/messages/MessagesViewModel.kt | 24 +++++++------------ .../model/MessagesTimelineItemState.kt | 1 - .../messages/model/MessagesViewState.kt | 4 +++- .../x/textcomposer/MessageComposerMode.kt | 12 ++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt index 0acaddf336..61a3a40978 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt @@ -27,7 +27,6 @@ class MessageTimelineItemStateFactory( ) { suspend fun create( timelineItems: List, - highlightedEventId: String? = null, ): List = withContext(dispatcher) { val messagesTimelineItemState = ArrayList() @@ -39,7 +38,6 @@ class MessageTimelineItemStateFactory( currentTimelineItem, index, timelineItems, - highlightedEventId ) } is MatrixTimelineItem.Virtual -> MessagesTimelineItemState.Virtual( @@ -56,7 +54,6 @@ class MessageTimelineItemStateFactory( currentTimelineItem: MatrixTimelineItem.Event, index: Int, timelineItems: List, - highlightedEventId: String?, ): MessagesTimelineItemState.MessageEvent { val currentSender = currentTimelineItem.event.sender() val groupPosition = @@ -76,7 +73,6 @@ class MessageTimelineItemStateFactory( senderAvatar = senderAvatarData, content = currentTimelineItem.computeContent(), isMine = currentTimelineItem.event.isOwn(), - isHighlighted = currentTimelineItem.event.eventId().orEmpty() == highlightedEventId, groupPosition = groupPosition, reactionsState = currentTimelineItem.computeReactionsState() ) diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt index 90b16aebf4..f68403dd03 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt @@ -53,10 +53,10 @@ private val COMPOSER_HEIGHT = 112.dp @Composable fun MessagesScreen( roomId: String, - onBackPressed: () -> Unit + onBackPressed: () -> Unit, + viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }), + composerViewModel: MessageComposerViewModel = mavericksViewModel(argsFactory = { roomId }) ) { - val viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }) - val composerViewModel: MessageComposerViewModel = mavericksViewModel(argsFactory = { roomId }) fun onSendMessage(textMessage: String) { viewModel.sendMessage(textMessage) @@ -74,11 +74,13 @@ fun MessagesScreen( val hasMoreToLoad by viewModel.collectAsState(MessagesViewState::hasMoreToLoad) val snackBarContent by viewModel.collectAsState(MessagesViewState::snackbarContent) val composerMode by viewModel.collectAsState(MessagesViewState::composerMode) + val highlightedEventId by viewModel.collectAsState(MessagesViewState::highlightedEventId) val composerFullScreen by composerViewModel.collectAsState(MessageComposerViewState::isFullScreen) val composerCanSendMessage by composerViewModel.collectAsState(MessageComposerViewState::isSendButtonVisible) val composerText by composerViewModel.collectAsState(MessageComposerViewState::text) val snackbarHostState = remember { SnackbarHostState() } MessagesScreenContent( + roomTitle = roomTitle, roomAvatar = roomAvatar, timelineItems = timelineItems().orEmpty(), @@ -90,6 +92,7 @@ fun MessagesScreen( onComposerFullScreenChange = composerViewModel::onComposerFullScreenChange, onComposerTextChange = composerViewModel::updateText, composerMode = composerMode, + highlightedEventId = highlightedEventId, onCloseSpecialMode = viewModel::setNormalMode, composerCanSendMessage = composerCanSendMessage, composerText = composerText, @@ -148,6 +151,7 @@ fun MessagesScreenContent( onComposerFullScreenChange: () -> Unit, onComposerTextChange: (CharSequence) -> Unit, composerMode: MessageComposerMode, + highlightedEventId: String?, onCloseSpecialMode: () -> Unit, composerCanSendMessage: Boolean, composerText: StableCharSequence?, @@ -171,6 +175,7 @@ fun MessagesScreenContent( onSendMessage = onSendMessage, onClick = onClick, onLongClick = onLongClick, + highlightedEventId = highlightedEventId, composerMode = composerMode, onCloseSpecialMode = onCloseSpecialMode, composerFullScreen = composerFullScreen, @@ -193,6 +198,7 @@ fun MessagesContent( onClick: (MessagesTimelineItemState.MessageEvent) -> Unit, onLongClick: (MessagesTimelineItemState.MessageEvent) -> Unit, composerMode: MessageComposerMode, + highlightedEventId: String?, onCloseSpecialMode: () -> Unit, composerFullScreen: Boolean, onComposerFullScreenChange: () -> Unit, @@ -211,6 +217,7 @@ fun MessagesContent( TimelineItems( lazyListState = lazyListState, timelineItems = timelineItems, + highlightedEventId = highlightedEventId, hasMoreToLoad = hasMoreToLoad, onReachedLoadMore = onReachedLoadMore, modifier = Modifier.weight(1f), @@ -279,6 +286,7 @@ fun MessagesTopAppBar( fun TimelineItems( lazyListState: LazyListState, timelineItems: List, + highlightedEventId: String?, modifier: Modifier = Modifier, hasMoreToLoad: Boolean = false, onClick: (MessagesTimelineItemState.MessageEvent) -> Unit = {}, @@ -300,6 +308,7 @@ fun TimelineItems( ) { timelineItem -> TimelineItemRow( timelineItem = timelineItem, + isHighlighted = timelineItem.key() == highlightedEventId, onClick = onClick, onLongClick = onLongClick ) @@ -337,6 +346,7 @@ private fun MessagesTimelineItemState.contentType(): Int { @Composable fun TimelineItemRow( timelineItem: MessagesTimelineItemState, + isHighlighted: Boolean, onClick: (MessagesTimelineItemState.MessageEvent) -> Unit, onLongClick: (MessagesTimelineItemState.MessageEvent) -> Unit, ) { @@ -344,6 +354,7 @@ fun TimelineItemRow( is MessagesTimelineItemState.Virtual -> return is MessagesTimelineItemState.MessageEvent -> MessageEventRow( messageEvent = timelineItem, + isHighlighted = isHighlighted, onClick = { onClick(timelineItem) }, onLongClick = { onLongClick(timelineItem) } ) @@ -353,6 +364,7 @@ fun TimelineItemRow( @Composable fun MessageEventRow( messageEvent: MessagesTimelineItemState.MessageEvent, + isHighlighted: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, modifier: Modifier = Modifier @@ -385,7 +397,7 @@ fun MessageEventRow( groupPosition = messageEvent.groupPosition, isMine = messageEvent.isMine, interactionSource = interactionSource, - isHighlighted = messageEvent.isHighlighted, + isHighlighted = isHighlighted, onClick = onClick, onLongClick = onLongClick, modifier = Modifier @@ -584,6 +596,7 @@ fun TimelineItemsPreview( groupPosition = MessagesItemGroupPosition.Last ), ), + highlightedEventId = null, hasMoreToLoad = true, ) } diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt index ec92c1e843..bfc430e2b3 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt @@ -18,7 +18,9 @@ import io.element.android.x.matrix.room.MatrixRoom import io.element.android.x.matrix.timeline.MatrixTimeline import io.element.android.x.textcomposer.MessageComposerMode import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import timber.log.Timber @@ -127,7 +129,8 @@ class MessagesViewModel( private fun setComposerMode(mode: MessageComposerMode) { setState { copy( - composerMode = mode + composerMode = mode, + highlightedEventId = mode.relatedEventId ) } } @@ -189,20 +192,9 @@ class MessagesViewModel( } }.launchIn(viewModelScope) - combine( - timeline.timelineItems(), - stateFlow.map { - when (it.composerMode) { - is MessageComposerMode.Normal -> null - is MessageComposerMode.Edit -> it.composerMode.eventId - is MessageComposerMode.Quote -> null - is MessageComposerMode.Reply -> it.composerMode.eventId - } - } - .distinctUntilChanged() - ) { timelineItems, highlightedEventId -> - messageTimelineItemStateFactory.create(timelineItems, highlightedEventId) - } + timeline + .timelineItems() + .map(messageTimelineItemStateFactory::create) .execute { copy(timelineItems = it) } diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt index 5e24423059..e194e9a1a4 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt @@ -16,7 +16,6 @@ sealed interface MessagesTimelineItemState { val content: MessagesTimelineItemContent, val sentTime: String = "", val isMine: Boolean = false, - val isHighlighted: Boolean = false, val groupPosition: MessagesItemGroupPosition = MessagesItemGroupPosition.None, val reactionsState: MessagesItemReactionState ) : MessagesTimelineItemState { diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt index d77dc08c81..aad0ee57f2 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt @@ -1,11 +1,13 @@ package io.element.android.x.features.messages.model +import androidx.compose.runtime.Stable import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.textcomposer.MessageComposerMode +@Stable data class MessagesViewState( val roomId: String, val roomName: String? = null, @@ -14,7 +16,7 @@ data class MessagesViewState( val hasMoreToLoad: Boolean = true, val itemActionsSheetState: Async = Uninitialized, val snackbarContent: String? = null, - // TODO Highlight item in reply / edit in the timeline + val highlightedEventId: String? = null, val composerMode: MessageComposerMode = MessageComposerMode.Normal(""), ) : MavericksState { diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt index 835abd0100..617eeef499 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt @@ -33,4 +33,16 @@ sealed interface MessageComposerMode { override val eventId: String, override val defaultContent: CharSequence ) : Special(eventId, defaultContent) + + + val relatedEventId: String? + get() = when (this) { + is Normal -> null + is Edit -> eventId + is Quote -> eventId + is Reply -> eventId + } + + } +