Cleaner code: add TimelineEvent to special modes

This commit is contained in:
Benoit Marty 2019-07-10 17:05:32 +02:00
parent 7e8cd07e1e
commit 9a57a02996
3 changed files with 74 additions and 99 deletions

View File

@ -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() {

View File

@ -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)
)
}
}

View File

@ -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<User> = Uninitialized,
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
val sendMode: SendMode = SendMode.REGULAR,
val selectedEvent: TimelineEvent? = null,
val isEncrypted: Boolean = false
) : MvRxState {