diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt similarity index 91% rename from features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt rename to features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt index cebf95d4ba..0acaddf336 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt @@ -20,20 +20,27 @@ import org.matrix.rustcomponents.sdk.MessageFormat import org.matrix.rustcomponents.sdk.MessageType import org.matrix.rustcomponents.sdk.TimelineKey -class MessageTimelineItemStateMapper( +class MessageTimelineItemStateFactory( private val client: MatrixClient, private val room: MatrixRoom, private val dispatcher: CoroutineDispatcher, ) { - - suspend fun map(timelineItems: List): List = + suspend fun create( + timelineItems: List, + highlightedEventId: String? = null, + ): List = withContext(dispatcher) { val messagesTimelineItemState = ArrayList() for (index in timelineItems.indices.reversed()) { val currentTimelineItem = timelineItems[index] val timelineItemState = when (currentTimelineItem) { is MatrixTimelineItem.Event -> { - buildMessageEvent(currentTimelineItem, index, timelineItems) + buildMessageEvent( + currentTimelineItem, + index, + timelineItems, + highlightedEventId + ) } is MatrixTimelineItem.Virtual -> MessagesTimelineItemState.Virtual( "virtual_item_$index" @@ -48,7 +55,8 @@ class MessageTimelineItemStateMapper( private suspend fun buildMessageEvent( currentTimelineItem: MatrixTimelineItem.Event, index: Int, - timelineItems: List + timelineItems: List, + highlightedEventId: String?, ): MessagesTimelineItemState.MessageEvent { val currentSender = currentTimelineItem.event.sender() val groupPosition = @@ -68,6 +76,7 @@ class MessageTimelineItemStateMapper( 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 80cfa45589..cab6bc82dc 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 @@ -41,6 +41,7 @@ import io.element.android.x.features.messages.model.* import io.element.android.x.features.messages.model.content.* import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel import io.element.android.x.features.messages.textcomposer.MessageComposerViewState +import io.element.android.x.textcomposer.MessageComposerMode import io.element.android.x.textcomposer.TextComposer import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch @@ -72,6 +73,7 @@ fun MessagesScreen( val timelineItems by viewModel.collectAsState(MessagesViewState::timelineItems) val hasMoreToLoad by viewModel.collectAsState(MessagesViewState::hasMoreToLoad) val snackBarContent by viewModel.collectAsState(MessagesViewState::snackbarContent) + val composerMode by viewModel.collectAsState(MessagesViewState::composerMode) val composerFullScreen by composerViewModel.collectAsState(MessageComposerViewState::isFullScreen) val composerCanSendMessage by composerViewModel.collectAsState(MessageComposerViewState::isSendButtonVisible) val composerText by composerViewModel.collectAsState(MessageComposerViewState::text) @@ -87,6 +89,8 @@ fun MessagesScreen( composerFullScreen = composerFullScreen, onComposerFullScreenChange = composerViewModel::onComposerFullScreenChange, onComposerTextChange = composerViewModel::updateText, + composerMode = composerMode, + onCloseSpecialMode = viewModel::setNormalMode, composerCanSendMessage = composerCanSendMessage, composerText = composerText, onClick = { @@ -107,6 +111,16 @@ fun MessagesScreen( onActionClicked = { viewModel.handleItemAction(it) coroutineScope.launch { + val targetEvent = viewModel.getTargetEvent() + when (it) { + is MessagesItemAction.Edit -> { + // Entering Edit mode, update the text in the composer. + val newComposerText = + (targetEvent?.content as? MessagesTimelineItemTextBasedContent)?.body.orEmpty() + composerViewModel.updateText(newComposerText) + } + else -> Unit + } actionsSheetState.hide() } } @@ -133,6 +147,8 @@ fun MessagesScreenContent( composerFullScreen: Boolean, onComposerFullScreenChange: () -> Unit, onComposerTextChange: (CharSequence) -> Unit, + composerMode: MessageComposerMode, + onCloseSpecialMode: () -> Unit, composerCanSendMessage: Boolean, composerText: StableCharSequence?, snackbarHostState: SnackbarHostState, @@ -155,6 +171,8 @@ fun MessagesScreenContent( onSendMessage = onSendMessage, onClick = onClick, onLongClick = onLongClick, + composerMode = composerMode, + onCloseSpecialMode = onCloseSpecialMode, composerFullScreen = composerFullScreen, onComposerFullScreenChange = onComposerFullScreenChange, onComposerTextChange = onComposerTextChange, @@ -174,6 +192,8 @@ fun MessagesContent( onSendMessage: (String) -> Unit, onClick: (MessagesTimelineItemState.MessageEvent) -> Unit, onLongClick: (MessagesTimelineItemState.MessageEvent) -> Unit, + composerMode: MessageComposerMode, + onCloseSpecialMode: () -> Unit, composerFullScreen: Boolean, onComposerFullScreenChange: () -> Unit, onComposerTextChange: (CharSequence) -> Unit, @@ -202,6 +222,8 @@ fun MessagesContent( onSendMessage = onSendMessage, fullscreen = composerFullScreen, onFullscreenToggle = onComposerFullScreenChange, + composerMode = composerMode, + onCloseSpecialMode = onCloseSpecialMode, onComposerTextChange = onComposerTextChange, composerCanSendMessage = composerCanSendMessage, composerText = composerText?.charSequence?.toString(), @@ -363,6 +385,7 @@ fun MessageEventRow( groupPosition = messageEvent.groupPosition, isMine = messageEvent.isMine, interactionSource = interactionSource, + isHighlighted = messageEvent.isHighlighted, onClick = onClick, onLongClick = onLongClick, modifier = Modifier 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 430ceb6d6a..ec92c1e843 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 @@ -10,15 +10,15 @@ import io.element.android.x.features.messages.model.MessagesItemActionsSheetStat import io.element.android.x.features.messages.model.MessagesTimelineItemState import io.element.android.x.features.messages.model.MessagesViewState import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent +import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixInstance import io.element.android.x.matrix.media.MediaResolver 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.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber @@ -28,7 +28,7 @@ class MessagesViewModel( private val client: MatrixClient, private val room: MatrixRoom, private val timeline: MatrixTimeline, - private val messageTimelineItemStateMapper: MessageTimelineItemStateMapper, + private val messageTimelineItemStateFactory: MessageTimelineItemStateFactory, private val initialState: MessagesViewState ) : MavericksViewModel(initialState) { @@ -42,13 +42,13 @@ class MessagesViewModel( val matrix = MatrixInstance.getInstance() val client = matrix.activeClient() val room = client.getRoom(state.roomId) ?: return null - val messageTimelineItemStateMapper = - MessageTimelineItemStateMapper(client, room, Dispatchers.Default) + val messageTimelineItemStateFactory = + MessageTimelineItemStateFactory(client, room, Dispatchers.Default) return MessagesViewModel( client, room, room.timeline(), - messageTimelineItemStateMapper, + messageTimelineItemStateFactory, state ) } @@ -66,25 +66,72 @@ class MessagesViewModel( } fun sendMessage(text: String) { - viewModelScope.launch { - timeline.sendMessage(text) + withState { state -> + viewModelScope.launch { + when (state.composerMode) { + is MessageComposerMode.Normal -> timeline.sendMessage(text) + is MessageComposerMode.Edit -> timeline.editMessage( + state.composerMode.eventId, + text + ) + is MessageComposerMode.Quote -> TODO() + is MessageComposerMode.Reply -> timeline.replyMessage( + state.composerMode.eventId, + text + ) + } + // Reset composer + setNormalMode() + } } } + suspend fun getTargetEvent(): MessagesTimelineItemState.MessageEvent? { + val currentState = awaitState() + return currentState.itemActionsSheetState.invoke()?.targetItem + } + fun handleItemAction(action: MessagesItemAction) { viewModelScope.launch(Dispatchers.Default) { val currentState = awaitState() Timber.v("Handle $action for ${currentState.itemActionsSheetState}") - val targetEvent = - currentState.itemActionsSheetState.invoke()?.targetItem ?: return@launch + val targetEvent = getTargetEvent() + ?: return@launch when (action) { MessagesItemAction.Copy -> notImplementedYet() MessagesItemAction.Forward -> notImplementedYet() MessagesItemAction.Redact -> handleActionRedact(targetEvent) + MessagesItemAction.Edit -> handleActionEdit(targetEvent) + MessagesItemAction.Reply -> handleActionReply(targetEvent) } } } + fun setNormalMode() { + setComposerMode(MessageComposerMode.Normal("")) + } + + private fun handleActionEdit(targetEvent: MessagesTimelineItemState.MessageEvent) { + setComposerMode( + MessageComposerMode.Edit( + targetEvent.id, + (targetEvent.content as? MessagesTimelineItemTextBasedContent)?.body.orEmpty() + ) + ) + } + + private fun handleActionReply(targetEvent: MessagesTimelineItemState.MessageEvent) { + setComposerMode(MessageComposerMode.Reply(targetEvent.safeSenderName, targetEvent.id, "")) + } + + private fun setComposerMode(mode: MessageComposerMode) { + setState { + copy( + composerMode = mode + ) + } + } + private fun notImplementedYet() { setSnackbarContent("Not implemented yet!") } @@ -110,10 +157,12 @@ class MessagesViewModel( emptyList() } else { mutableListOf( + MessagesItemAction.Reply, MessagesItemAction.Forward, MessagesItemAction.Copy, ).also { if (messagesTimelineItemState.isMine) { + it.add(MessagesItemAction.Edit) it.add(MessagesItemAction.Redact) } } @@ -140,8 +189,20 @@ class MessagesViewModel( } }.launchIn(viewModelScope) - timeline.timelineItems() - .map(messageTimelineItemStateMapper::map) + 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) + } .execute { copy(timelineItems = it) } diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt index 81cc00153c..47bf5f3674 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape @@ -25,6 +24,7 @@ fun MessageEventBubble( groupPosition: MessagesItemGroupPosition, isMine: Boolean, interactionSource: MutableInteractionSource, + isHighlighted: Boolean, modifier: Modifier = Modifier, onClick: () -> Unit, onLongClick: () -> Unit, @@ -65,17 +65,25 @@ fun MessageEventBubble( } } - val backgroundBubbleColor = if (isMine) { + val backgroundBubbleColor = if (isHighlighted) { if (LocalIsDarkTheme.current) { - SystemGrey5Dark + MessageHighlightDark } else { - SystemGrey5Light + MessageHighlightLight } } else { - if (LocalIsDarkTheme.current) { - SystemGrey6Dark + if (isMine) { + if (LocalIsDarkTheme.current) { + SystemGrey5Dark + } else { + SystemGrey5Light + } } else { - SystemGrey6Light + if (LocalIsDarkTheme.current) { + SystemGrey6Dark + } else { + SystemGrey6Light + } } } val bubbleShape = bubbleShape() diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesItemAction.kt b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesItemAction.kt index 740740fdcc..0c040831a1 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesItemAction.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesItemAction.kt @@ -13,4 +13,6 @@ sealed class MessagesItemAction( object Forward : MessagesItemAction("Forward", VectorIcons.ArrowForward) object Copy : MessagesItemAction("Copy", VectorIcons.Copy) object Redact : MessagesItemAction("Redact", VectorIcons.Delete, destructive = true) + object Reply : MessagesItemAction("Reply", VectorIcons.Reply) + object Edit : MessagesItemAction("Edit", VectorIcons.Edit) } \ No newline at end of file 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 e194e9a1a4..5e24423059 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,6 +16,7 @@ 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 6ca5352db1..d77dc08c81 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 @@ -4,6 +4,7 @@ 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 data class MessagesViewState( val roomId: String, @@ -13,6 +14,8 @@ 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 composerMode: MessageComposerMode = MessageComposerMode.Normal(""), ) : MavericksState { @Suppress("unused") diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt index 33925b8fbc..4ad0a1e99a 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt @@ -34,3 +34,8 @@ val Melon = Color(0xFFFF812D) val ElementGreen = Color(0xFF0DBD8B) val ElementOrange = Color(0xFFD9B072) val Vermilion = Color(0xFFFF5B55) + +// TODO Update color +val MessageHighlightLight = Azure +// TODO Update color +val MessageHighlightDark = Azure diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt index 26881ddcef..bd1d941e3e 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt @@ -6,4 +6,6 @@ object VectorIcons { val Copy = R.drawable.ic_content_copy val ArrowForward = R.drawable.ic_content_arrow_forward val Delete = R.drawable.ic_baseline_delete_outline_24 + val Reply = R.drawable.ic_baseline_reply_24 + val Edit = R.drawable.ic_baseline_edit_24 } \ No newline at end of file diff --git a/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml b/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml new file mode 100644 index 0000000000..1c9bd3e6bd --- /dev/null +++ b/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml b/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml new file mode 100644 index 0000000000..c5fba99883 --- /dev/null +++ b/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt index c343fc2da0..940c3018cf 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt @@ -82,6 +82,22 @@ class MatrixRoom( } } + suspend fun editMessage(originalEventId: String, message: String): Result = withContext(coroutineDispatchers.io) { + val transactionId = genTransactionId() + val content = messageEventContentFromMarkdown(message) + runCatching { + room.edit(/* TODO use content */ message, originalEventId, transactionId) + } + } + + suspend fun replyMessage(eventId: String, message: String): Result = withContext(coroutineDispatchers.io) { + val transactionId = genTransactionId() + val content = messageEventContentFromMarkdown(message) + runCatching { + room.sendReply(/* TODO use content */ message, eventId, transactionId) + } + } + suspend fun redactEvent(eventId: String, reason: String? = null, ) = withContext(coroutineDispatchers.io) { val transactionId = genTransactionId() runCatching { diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt index f4a5e27c8d..7007640fcd 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt @@ -124,6 +124,14 @@ class MatrixTimeline( return matrixRoom.sendMessage(message) } + suspend fun editMessage(originalEventId: String, message: String): Result { + return matrixRoom.editMessage(originalEventId, message = message) + } + + suspend fun replyMessage(inReplyToEventId: String, message: String): Result { + return matrixRoom.replyMessage(inReplyToEventId, message) + } + override fun onUpdate(update: TimelineDiff) { coroutineScope.launch { updateTimelineItems { 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 86e35d5ad0..835abd0100 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 @@ -19,8 +19,18 @@ package io.element.android.x.textcomposer sealed interface MessageComposerMode { data class Normal(val content: CharSequence?) : MessageComposerMode - sealed class Special(open val event: Any /* TODO set correct type here */, open val defaultContent: CharSequence) : MessageComposerMode - data class Edit(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent) - class Quote(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent) - class Reply(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent) + sealed class Special(open val eventId: String, open val defaultContent: CharSequence) : + MessageComposerMode + + data class Edit(override val eventId: String, override val defaultContent: CharSequence) : + Special(eventId, defaultContent) + + class Quote(override val eventId: String, override val defaultContent: CharSequence) : + Special(eventId, defaultContent) + + class Reply( + val senderName: String, + override val eventId: String, + override val defaultContent: CharSequence + ) : Special(eventId, defaultContent) } diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt index 99e300096a..6a0f5e7e23 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt @@ -133,7 +133,7 @@ class RichTextComposerLayout @JvmOverloads constructor( if (isFullScreen) R.drawable.ic_composer_collapse else R.drawable.ic_composer_full_screen ) - views.bottomSheetHandle.isVisible = isFullScreen + views.bottomSheetHandle.isVisible = false // EAx: always gone, we do not have a bottom sheet here. // isFullScreen if (manageKeyboard) { if (isFullScreen) { editText.showKeyboard(true) @@ -171,7 +171,7 @@ class RichTextComposerLayout @JvmOverloads constructor( views.richTextComposerEditText.maxLines = maxLines views.plainTextComposerEditText.maxLines = maxLines - views.bottomSheetHandle.isVisible = true + views.bottomSheetHandle.isVisible = false // EAx: always gone, we do not have a bottom sheet here. } init { @@ -506,10 +506,7 @@ class RichTextComposerLayout @JvmOverloads constructor( views.composerModeIconView.setImageResource(R.drawable.ic_quote) } is MessageComposerMode.Reply -> { - // TODO We need sender info - // val senderInfo = mode.event.senderInfo - val userName = - "TODO Sender name" // senderInfo.displayName ?: senderInfo.disambiguatedDisplayName + val userName = mode.senderName views.composerModeTitleView.text = resources.getString(R.string.replying_to, userName) views.composerModeIconView.setImageResource(R.drawable.ic_reply) diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt index 50a344cbcd..093cdc858e 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt @@ -26,6 +26,8 @@ fun TextComposer( modifier: Modifier = Modifier, fullscreen: Boolean, onFullscreenToggle: () -> Unit, + composerMode: MessageComposerMode, + onCloseSpecialMode: () -> Unit, onComposerTextChange: (CharSequence) -> Unit, composerCanSendMessage: Boolean, composerText: String?, @@ -50,6 +52,7 @@ fun TextComposer( } override fun onCloseRelatedMessage() { + onCloseSpecialMode() } override fun onSendMessage(text: CharSequence) { @@ -70,7 +73,7 @@ fun TextComposer( } setFullScreen(fullscreen, true) (this as MessageComposerView).apply { - setup(isInDarkMode) + setup(isInDarkMode, composerMode) } } }, @@ -83,6 +86,7 @@ fun TextComposer( // Example of Compose -> View communication val messageComposerView = (view as MessageComposerView) view.setFullScreen(fullscreen, false) + // TODO messageComposerView.renderComposerMode(composerMode) messageComposerView.sendButton.isInvisible = !composerCanSendMessage messageComposerView.setTextIfDifferent(composerText ?: "") } @@ -107,7 +111,7 @@ private fun FakeComposer(modifier: Modifier) { } } -private fun MessageComposerView.setup(isDarkMode: Boolean) { +private fun MessageComposerView.setup(isDarkMode: Boolean, composerMode: MessageComposerMode) { val editTextColor = if (isDarkMode) { Color.WHITE } else { @@ -118,6 +122,7 @@ private fun MessageComposerView.setup(isDarkMode: Boolean) { editText.setHint(ElementR.string.room_message_placeholder) emojiButton?.isVisible = true sendButton.isVisible = true + // TODO renderComposerMode(composerMode) } @Preview @@ -128,6 +133,8 @@ fun TextComposerPreview() { fullscreen = false, onFullscreenToggle = { }, onComposerTextChange = {}, + composerMode = MessageComposerMode.Normal(""), + onCloseSpecialMode = {}, composerCanSendMessage = true, composerText = "Message", ) diff --git a/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml b/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml index 88f96c528e..d099c72cab 100644 --- a/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml +++ b/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml @@ -5,8 +5,19 @@ android:id="@+id/composerLayout" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:background="@drawable/bg_composer_rich_bottom_sheet"> + android:orientation="vertical"> + + + +