RoomDetail : enter/exit special mode without waiting for draft to update

This commit is contained in:
ganfra 2019-11-06 20:08:19 +01:00
parent 3af7ca9ab0
commit 54f93db632
4 changed files with 66 additions and 40 deletions

View File

@ -42,10 +42,10 @@ sealed class RoomDetailActions {
object AcceptInvite : RoomDetailActions() object AcceptInvite : RoomDetailActions()
object RejectInvite : RoomDetailActions() object RejectInvite : RoomDetailActions()
data class EnterEditMode(val eventId: String, val draft: String) : RoomDetailActions() data class EnterEditMode(val eventId: String, val text: String) : RoomDetailActions()
data class EnterQuoteMode(val eventId: String, val draft: String) : RoomDetailActions() data class EnterQuoteMode(val eventId: String, val text: String) : RoomDetailActions()
data class EnterReplyMode(val eventId: String, val draft: String) : RoomDetailActions() data class EnterReplyMode(val eventId: String, val text: String) : RoomDetailActions()
data class ExitSpecialMode(val draft: String) : RoomDetailActions() data class ExitSpecialMode(val text: String) : RoomDetailActions()
data class ResendMessage(val eventId: String) : RoomDetailActions() data class ResendMessage(val eventId: String) : RoomDetailActions()
data class RemoveFailedEcho(val eventId: String) : RoomDetailActions() data class RemoveFailedEcho(val eventId: String) : RoomDetailActions()

View File

@ -223,7 +223,6 @@ class RoomDetailFragment :
setupToolbar(roomToolbar) setupToolbar(roomToolbar)
setupRecyclerView() setupRecyclerView()
setupComposer() setupComposer()
setupAttachmentButton()
setupInviteView() setupInviteView()
setupNotificationView() setupNotificationView()
setupJumpToReadMarkerView() setupJumpToReadMarkerView()
@ -601,21 +600,30 @@ class RoomDetailFragment :
}) })
.build() .build()
composerLayout.sendButton.setOnClickListener {
if (lockSendButton) {
Timber.w("Send button is locked")
return@setOnClickListener
}
val textMessage = composerLayout.composerEditText.text.toString()
if (textMessage.isNotBlank()) {
lockSendButton = true
roomDetailViewModel.process(RoomDetailActions.SendMessage(textMessage, vectorPreferences.isMarkdownEnabled()))
}
}
composerLayout.composerRelatedMessageCloseButton.setOnClickListener {
roomDetailViewModel.process(RoomDetailActions.ExitSpecialMode(composerLayout.composerEditText.text.toString()))
}
composerLayout.callback = object : TextComposerView.Callback { composerLayout.callback = object : TextComposerView.Callback {
override fun onAddAttachment() {
if (!::attachmentTypeSelector.isInitialized) {
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@RoomDetailFragment)
}
attachmentTypeSelector.show(composerLayout.attachmentButton, keyboardStateUtils.isKeyboardShowing)
}
override fun onSendMessage(text: String) {
if (lockSendButton) {
Timber.w("Send button is locked")
return
}
if (text.isNotBlank()) {
lockSendButton = true
roomDetailViewModel.process(RoomDetailActions.SendMessage(text, vectorPreferences.isMarkdownEnabled()))
}
}
override fun onCloseRelatedMessage() {
roomDetailViewModel.process(RoomDetailActions.ExitSpecialMode(composerLayout.text.toString()))
}
override fun onRichContentSelected(contentUri: Uri): Boolean { override fun onRichContentSelected(contentUri: Uri): Boolean {
// We need WRITE_EXTERNAL permission // We need WRITE_EXTERNAL permission
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this@RoomDetailFragment, PERMISSION_REQUEST_CODE_INCOMING_URI)) { return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this@RoomDetailFragment, PERMISSION_REQUEST_CODE_INCOMING_URI)) {
@ -638,15 +646,6 @@ class RoomDetailFragment :
return isHandled return isHandled
} }
private fun setupAttachmentButton() {
composerLayout.attachmentButton.setOnClickListener {
if (!::attachmentTypeSelector.isInitialized) {
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this)
}
attachmentTypeSelector.show(composerLayout.attachmentButton, keyboardStateUtils.isKeyboardShowing)
}
}
private fun setupInviteView() { private fun setupInviteView() {
inviteView.callback = this inviteView.callback = this
} }
@ -1114,13 +1113,13 @@ class RoomDetailFragment :
roomDetailViewModel.process(RoomDetailActions.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add)) roomDetailViewModel.process(RoomDetailActions.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
} }
is SimpleAction.Edit -> { is SimpleAction.Edit -> {
roomDetailViewModel.process(RoomDetailActions.EnterEditMode(action.eventId, composerLayout.composerEditText.text.toString())) roomDetailViewModel.process(RoomDetailActions.EnterEditMode(action.eventId, composerLayout.text.toString()))
} }
is SimpleAction.Quote -> { is SimpleAction.Quote -> {
roomDetailViewModel.process(RoomDetailActions.EnterQuoteMode(action.eventId, composerLayout.composerEditText.text.toString())) roomDetailViewModel.process(RoomDetailActions.EnterQuoteMode(action.eventId, composerLayout.text.toString()))
} }
is SimpleAction.Reply -> { is SimpleAction.Reply -> {
roomDetailViewModel.process(RoomDetailActions.EnterReplyMode(action.eventId, composerLayout.composerEditText.text.toString())) roomDetailViewModel.process(RoomDetailActions.EnterReplyMode(action.eventId, composerLayout.text.toString()))
} }
is SimpleAction.CopyPermalink -> { is SimpleAction.CopyPermalink -> {
val permalink = PermalinkFactory.createPermalink(roomDetailArgs.roomId, action.eventId) val permalink = PermalinkFactory.createPermalink(roomDetailArgs.roomId, action.eventId)

View File

@ -520,17 +520,18 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
} }
private fun handleEditAction(action: RoomDetailActions.EnterEditMode) { private fun handleEditAction(action: RoomDetailActions.EnterEditMode) {
saveCurrentDraft(action.draft) saveCurrentDraft(action.text)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
timelineEvent.root.eventId?.let { timelineEvent.root.eventId?.let {
room.saveDraft(UserDraft.EDIT(it, timelineEvent.getTextEditableContent() ?: "")) room.saveDraft(UserDraft.EDIT(it, timelineEvent.getTextEditableContent() ?: ""))
} }
setState { copy(sendMode = SendMode.EDIT(timelineEvent, action.text)) }
} }
} }
private fun handleQuoteAction(action: RoomDetailActions.EnterQuoteMode) { private fun handleQuoteAction(action: RoomDetailActions.EnterQuoteMode) {
saveCurrentDraft(action.draft) saveCurrentDraft(action.text)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
withState { state -> withState { state ->
@ -539,16 +540,16 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
if (state.sendMode is SendMode.EDIT) { if (state.sendMode is SendMode.EDIT) {
room.saveDraft(UserDraft.QUOTE(it, "")) room.saveDraft(UserDraft.QUOTE(it, ""))
} else { } else {
room.saveDraft(UserDraft.QUOTE(it, action.draft)) room.saveDraft(UserDraft.QUOTE(it, action.text))
} }
} }
setState { copy(sendMode = SendMode.QUOTE(timelineEvent, action.text)) }
} }
} }
} }
private fun handleReplyAction(action: RoomDetailActions.EnterReplyMode) { private fun handleReplyAction(action: RoomDetailActions.EnterReplyMode) {
saveCurrentDraft(action.draft) saveCurrentDraft(action.text)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
withState { state -> withState { state ->
// Save a new draft and keep the previously entered text, if it was not an edit // Save a new draft and keep the previously entered text, if it was not an edit
@ -556,9 +557,10 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
if (state.sendMode is SendMode.EDIT) { if (state.sendMode is SendMode.EDIT) {
room.saveDraft(UserDraft.REPLY(it, "")) room.saveDraft(UserDraft.REPLY(it, ""))
} else { } else {
room.saveDraft(UserDraft.REPLY(it, action.draft)) room.saveDraft(UserDraft.REPLY(it, action.text))
} }
} }
setState { copy(sendMode = SendMode.REPLY(timelineEvent, action.text)) }
} }
} }
} }
@ -584,7 +586,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
room.deleteDraft() room.deleteDraft()
} else { } else {
// Save a new draft and keep the previously entered text // Save a new draft and keep the previously entered text
room.saveDraft(UserDraft.REGULAR(action.draft)) room.saveDraft(UserDraft.REGULAR(action.text))
} }
} }
} }

View File

@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail.composer
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.text.Editable
import android.util.AttributeSet import android.util.AttributeSet
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton import android.widget.ImageButton
@ -31,6 +32,9 @@ import androidx.transition.TransitionManager
import butterknife.BindView import butterknife.BindView
import butterknife.ButterKnife import butterknife.ButterKnife
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.features.home.room.detail.RoomDetailActions
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
import timber.log.Timber
/** /**
* Encapsulate the timeline composer UX. * Encapsulate the timeline composer UX.
@ -39,7 +43,11 @@ import im.vector.riotx.R
class TextComposerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, class TextComposerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) { defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
interface Callback : ComposerEditText.Callback interface Callback : ComposerEditText.Callback {
fun onCloseRelatedMessage()
fun onSendMessage(text: String)
fun onAddAttachment()
}
var callback: Callback? = null var callback: Callback? = null
@ -62,15 +70,32 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
private val animationDuration = 100L private val animationDuration = 100L
val text: Editable?
get() = composerEditText.text
init { init {
inflate(context, R.layout.merge_composer_layout, this) inflate(context, R.layout.merge_composer_layout, this)
ButterKnife.bind(this) ButterKnife.bind(this)
collapse(false) collapse(false)
composerEditText.callback = object : Callback, ComposerEditText.Callback { composerEditText.callback = object : ComposerEditText.Callback {
override fun onRichContentSelected(contentUri: Uri): Boolean { override fun onRichContentSelected(contentUri: Uri): Boolean {
return callback?.onRichContentSelected(contentUri) ?: false return callback?.onRichContentSelected(contentUri) ?: false
} }
} }
composerRelatedMessageCloseButton.setOnClickListener {
collapse()
callback?.onCloseRelatedMessage()
}
sendButton.setOnClickListener {
val textMessage = text?.toString() ?: ""
callback?.onSendMessage(textMessage)
}
attachmentButton.setOnClickListener {
callback?.onAddAttachment()
}
} }
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) { fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {