diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 2b3ddc51..62ffefea 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -33,6 +33,7 @@ import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.TextView import android.widget.Toast +import androidx.annotation.DrawableRes import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModelProviders @@ -225,79 +226,57 @@ class RoomDetailFragment : } } - roomDetailViewModel.selectSubscribe( - RoomDetailViewState::sendMode, - RoomDetailViewState::selectedEvent, - RoomDetailViewState::roomId) { mode, event, roomId -> + roomDetailViewModel.selectSubscribe(RoomDetailViewState::sendMode) { mode -> when (mode) { - SendMode.REGULAR -> { - commandAutocompletePolicy.enabled = true - val uid = session.sessionParams.credentials.userId - val meMember = session.getRoom(roomId)?.getRoomMember(uid) - avatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) - composerLayout.collapse() - } - SendMode.EDIT, - SendMode.QUOTE, - SendMode.REPLY -> { - commandAutocompletePolicy.enabled = false - if (event == null) { - //we should ignore? can this happen? - Timber.e("Enter edit mode with no event selected") - return@selectSubscribe - } - //switch to expanded bar - composerLayout.composerRelatedMessageTitle.apply { - text = event.getDisambiguatedDisplayName() - setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.senderId))) - } - - //TODO this is used at several places, find way to refactor? - val messageContent: MessageContent? = - event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.getClearContent().toModel() - val nonFormattedBody = messageContent?.body ?: "" - var formattedBody: CharSequence? = null - if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) { - val parser = Parser.builder().build() - val document = parser.parse(messageContent.formattedBody - ?: messageContent.body) - formattedBody = Markwon.builder(requireContext()) - .usePlugin(HtmlPlugin.create()).build().render(document) - } - composerLayout.composerRelatedMessageContent.text = formattedBody - ?: nonFormattedBody - - - if (mode == SendMode.EDIT) { - //TODO if it's a reply we should trim the top part of message - composerLayout.composerEditText.setText(nonFormattedBody) - composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_edit)) - } else if (mode == SendMode.QUOTE) { - composerLayout.composerEditText.setText("") - composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_quote)) - } else if (mode == SendMode.REPLY) { - composerLayout.composerEditText.setText("") - composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_reply)) - } - - avatarRenderer.render(event.senderAvatar, event.root.senderId - ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) - - composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length) - composerLayout.expand { - focusComposerAndShowKeyboard() - } - composerLayout.composerRelatedMessageCloseButton.setOnClickListener { - composerLayout.composerEditText.setText("") - roomDetailViewModel.resetSendMode() - } - - } + SendMode.REGULAR -> exitSpecialMode() + is SendMode.EDIT -> enterSpecialMode(mode.timelineEvent, R.drawable.ic_edit, true) + is SendMode.QUOTE -> enterSpecialMode(mode.timelineEvent, R.drawable.ic_quote, false) + is SendMode.REPLY -> enterSpecialMode(mode.timelineEvent, R.drawable.ic_reply, false) } } } + private fun exitSpecialMode() { + commandAutocompletePolicy.enabled = true + composerLayout.collapse() + } + + private fun enterSpecialMode(event: TimelineEvent, @DrawableRes iconRes: Int, useText: Boolean) { + commandAutocompletePolicy.enabled = false + //switch to expanded bar + composerLayout.composerRelatedMessageTitle.apply { + text = event.getDisambiguatedDisplayName() + setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.senderId))) + } + + //TODO this is used at several places, find way to refactor? + val messageContent: MessageContent? = + event.annotations?.editSummary?.aggregatedContent?.toModel() + ?: event.root.getClearContent().toModel() + val nonFormattedBody = messageContent?.body ?: "" + var formattedBody: CharSequence? = null + if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) { + val parser = Parser.builder().build() + val document = parser.parse(messageContent.formattedBody + ?: messageContent.body) + formattedBody = Markwon.builder(requireContext()) + .usePlugin(HtmlPlugin.create()).build().render(document) + } + composerLayout.composerRelatedMessageContent.text = formattedBody + ?: nonFormattedBody + + composerLayout.composerEditText.setText(if (useText) nonFormattedBody else "") + composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes)) + + avatarRenderer.render(event.senderAvatar, event.root.senderId + ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) + + composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length) + composerLayout.expand { + focusComposerAndShowKeyboard() + } + } + override fun onResume() { super.onResume() @@ -422,6 +401,10 @@ class RoomDetailFragment : roomDetailViewModel.process(RoomDetailActions.SendMessage(textMessage, VectorPreferences.isMarkdownEnabled(requireContext()))) } } + composerLayout.composerRelatedMessageCloseButton.setOnClickListener { + composerLayout.composerEditText.setText("") + roomDetailViewModel.resetSendMode() + } } private fun setupAttachmentButton() { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 708a705c..b7240ce2 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -124,11 +124,10 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } - fun enterEditMode(event: TimelineEvent) { + private fun enterEditMode(event: TimelineEvent) { setState { copy( - sendMode = SendMode.EDIT, - selectedEvent = event + sendMode = SendMode.EDIT(event) ) } } @@ -136,8 +135,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro fun resetSendMode() { setState { copy( - sendMode = SendMode.REGULAR, - selectedEvent = null + sendMode = SendMode.REGULAR ) } } @@ -165,7 +163,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro private fun handleSendMessage(action: RoomDetailActions.SendMessage) { withState { state -> when (state.sendMode) { - SendMode.REGULAR -> { + SendMode.REGULAR -> { val slashCommandResult = CommandParser.parseSplashCommand(action.text) when (slashCommandResult) { @@ -231,30 +229,29 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } } - SendMode.EDIT -> { + is SendMode.EDIT -> { val messageContent: MessageContent? = - state.selectedEvent?.annotations?.editSummary?.aggregatedContent.toModel() - ?: state.selectedEvent?.root?.getClearContent().toModel() + state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() + ?: state.sendMode.timelineEvent.root.getClearContent().toModel() val nonFormattedBody = messageContent?.body ?: "" if (nonFormattedBody != action.text) { - room.editTextMessage(state.selectedEvent?.root?.eventId + room.editTextMessage(state.sendMode.timelineEvent.root.eventId ?: "", action.text, action.autoMarkdown) } else { Timber.w("Same message content, do not send edition") } setState { copy( - sendMode = SendMode.REGULAR, - selectedEvent = null + sendMode = SendMode.REGULAR ) } _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent)) } - SendMode.QUOTE -> { + is SendMode.QUOTE -> { val messageContent: MessageContent? = - state.selectedEvent?.annotations?.editSummary?.aggregatedContent.toModel() - ?: state.selectedEvent?.root?.getClearContent().toModel() + state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() + ?: state.sendMode.timelineEvent.root.getClearContent().toModel() val textMsg = messageContent?.body val finalText = legacyRiotQuoteText(textMsg, action.text) @@ -271,19 +268,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } setState { copy( - sendMode = SendMode.REGULAR, - selectedEvent = null + sendMode = SendMode.REGULAR ) } _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent)) } - SendMode.REPLY -> { - state.selectedEvent?.let { + is SendMode.REPLY -> { + state.sendMode.timelineEvent.let { room.replyToMessage(it.root, action.text, action.autoMarkdown) setState { copy( - sendMode = SendMode.REGULAR, - selectedEvent = null + sendMode = SendMode.REGULAR ) } _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent)) @@ -434,8 +429,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro room.getTimeLineEvent(action.eventId)?.let { setState { copy( - sendMode = SendMode.QUOTE, - selectedEvent = it + sendMode = SendMode.QUOTE(it) ) } } @@ -445,8 +439,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro room.getTimeLineEvent(action.eventId)?.let { setState { copy( - sendMode = SendMode.REPLY, - selectedEvent = it + sendMode = SendMode.REPLY(it) ) } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt index c32a79da..63171491 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt @@ -32,11 +32,11 @@ import im.vector.matrix.android.api.session.user.model.User * * Depending on the state the bottom toolbar will change (icons/preview/actions...) */ -enum class SendMode { - REGULAR, - QUOTE, - EDIT, - REPLY +sealed class SendMode { + object REGULAR : SendMode() + data class QUOTE(val timelineEvent: TimelineEvent) : SendMode() + data class EDIT(val timelineEvent: TimelineEvent) : SendMode() + data class REPLY(val timelineEvent: TimelineEvent) : SendMode() } data class RoomDetailViewState( @@ -46,7 +46,6 @@ data class RoomDetailViewState( val asyncInviter: Async = Uninitialized, val asyncRoomSummary: Async = Uninitialized, val sendMode: SendMode = SendMode.REGULAR, - val selectedEvent: TimelineEvent? = null, val isEncrypted: Boolean = false ) : MvRxState {