Save Draft only when app goes to background.

This commit is contained in:
Benoit Marty 2019-09-17 18:08:15 +02:00 committed by Benoit Marty
parent dfab88ed95
commit 562acc9702
3 changed files with 37 additions and 45 deletions

View File

@ -39,7 +39,7 @@ sealed class RoomDetailActions {
object AcceptInvite : RoomDetailActions()
object RejectInvite : RoomDetailActions()
data class EnterEditMode(val eventId: String) : RoomDetailActions()
data class EnterEditMode(val eventId: String, val draft: String) : RoomDetailActions()
data class EnterQuoteMode(val eventId: String, val draft: String) : RoomDetailActions()
data class EnterReplyMode(val eventId: String, val draft: String) : RoomDetailActions()
data class ExitSpecialMode(val draft: String) : RoomDetailActions()

View File

@ -53,7 +53,6 @@ import com.google.android.material.snackbar.Snackbar
import com.jaiselrahman.filepicker.activity.FilePickerActivity
import com.jaiselrahman.filepicker.config.Configurations
import com.jaiselrahman.filepicker.model.MediaFile
import com.jakewharton.rxbinding3.widget.afterTextChangeEvents
import com.otaliastudios.autocomplete.Autocomplete
import com.otaliastudios.autocomplete.AutocompleteCallback
import com.otaliastudios.autocomplete.CharPolicy
@ -107,7 +106,6 @@ import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.themes.ThemeUtils
import io.reactivex.rxkotlin.subscribeBy
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.*
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
@ -115,7 +113,6 @@ import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import org.commonmark.parser.Parser
import timber.log.Timber
import java.io.File
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -189,7 +186,6 @@ class RoomDetailFragment :
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
@Inject lateinit var vectorPreferences: VectorPreferences
override fun getLayoutResId() = R.layout.fragment_room_detail
override fun getMenuRes() = R.menu.menu_timeline
@ -199,6 +195,8 @@ class RoomDetailFragment :
@BindView(R.id.composerLayout)
lateinit var composerLayout: TextComposerView
private var lockSendButton = false
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
@ -350,7 +348,6 @@ class RoomDetailFragment :
// Do not update if this is the same text to avoid the cursor to move
if (text != composerLayout.composerEditText.text.toString()) {
// Ignore update to avoid saving a draft
filterComposerTextChange = true
composerLayout.composerEditText.setText(text)
composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
}
@ -366,6 +363,8 @@ class RoomDetailFragment :
super.onPause()
notificationDrawerManager.setCurrentRoom(null)
roomDetailViewModel.process(RoomDetailActions.SaveDraft(composerLayout.composerEditText.text.toString()))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -437,21 +436,7 @@ class RoomDetailFragment :
}
}
private var filterComposerTextChange = true
private fun setupComposer() {
composerLayout.composerEditText.afterTextChangeEvents()
.debounce(100, TimeUnit.MILLISECONDS)
.subscribeBy {
if (filterComposerTextChange) {
Timber.d("Draft: ignore text update")
filterComposerTextChange = false
return@subscribeBy
}
roomDetailViewModel.process(RoomDetailActions.SaveDraft(it.editable.toString()))
}
.disposeOnDestroy()
val elevation = 6f
val backgroundDrawable = ColorDrawable(ThemeUtils.getColor(requireContext(), R.attr.riotx_background))
Autocomplete.on<Command>(composerLayout.composerEditText)
@ -515,8 +500,13 @@ class RoomDetailFragment :
.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()))
}
}
@ -673,11 +663,11 @@ class RoomDetailFragment :
private fun renderSendMessageResult(sendMessageResult: SendMessageResult) {
when (sendMessageResult) {
is SendMessageResult.MessageSent -> {
// Nothing to do, the composer will be cleared with the draft update
updateComposerText("")
}
is SendMessageResult.SlashCommandHandled -> {
sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) }
// The composer will be cleared with the draft update
updateComposerText("")
}
is SendMessageResult.SlashCommandError -> {
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
@ -686,7 +676,7 @@ class RoomDetailFragment :
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
}
is SendMessageResult.SlashCommandResultOk -> {
// Ignore
updateComposerText("")
}
is SendMessageResult.SlashCommandResultError -> {
displayCommandError(sendMessageResult.throwable.localizedMessage)
@ -695,6 +685,8 @@ class RoomDetailFragment :
displayCommandError(getString(R.string.not_implemented))
}
}
lockSendButton = false
}
private fun displayCommandError(message: String) {
@ -939,7 +931,7 @@ class RoomDetailFragment :
roomDetailViewModel.process(RoomDetailActions.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
}
is SimpleAction.Edit -> {
roomDetailViewModel.process(RoomDetailActions.EnterEditMode(action.eventId))
roomDetailViewModel.process(RoomDetailActions.EnterEditMode(action.eventId, composerLayout.composerEditText.text.toString()))
}
is SimpleAction.Quote -> {
roomDetailViewModel.process(RoomDetailActions.EnterQuoteMode(action.eventId, composerLayout.composerEditText.text.toString()))

View File

@ -85,9 +85,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private var timeline = room.createTimeline(eventId, timelineSettings)
// Filter to avoid infinite loop when user enter text in the composer and call SaveDraft
private var filterDraftUpdate = false
// Slot to keep a pending action during permission request
var pendingAction: RoomDetailActions? = null
@ -151,9 +148,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
* Convert a send mode to a draft and save the draft
*/
private fun handleSaveDraft(action: RoomDetailActions.SaveDraft) {
// The text is changed, ignore the next update from DB
filterDraftUpdate = true
withState {
when (it.sendMode) {
is SendMode.REGULAR -> room.saveDraft(UserDraft.REGULAR(action.draft))
@ -167,14 +161,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private fun observeDrafts() {
room.rx().liveDrafts()
.subscribe {
Timber.d("Draft update!")
if (filterDraftUpdate) {
Timber.d(" --> Ignore")
return@subscribe
}
Timber.d(" --> SetState")
Timber.d("Draft update --> SetState")
setState {
val draft = it.lastOrNull() ?: UserDraft.REGULAR("")
copy(
@ -337,7 +324,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
}
is SendMode.EDIT -> {
//is original event a reply?
val inReplyTo = state.sendMode.timelineEvent.root.getClearContent().toModel<MessageContent>()?.relatesTo?.inReplyTo?.eventId
?: state.sendMode.timelineEvent.root.content.toModel<EncryptedEventContent>()?.relatesTo?.inReplyTo?.eventId
@ -396,7 +382,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
private fun popDraft() {
filterDraftUpdate = false
room.deleteDraft()
}
@ -513,20 +498,22 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
private fun handleEditAction(action: RoomDetailActions.EnterEditMode) {
saveCurrentDraft(action.draft)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
timelineEvent.root.eventId?.let {
filterDraftUpdate = false
room.saveDraft(UserDraft.EDIT(it, timelineEvent.getTextEditableContent() ?: ""))
}
}
}
private fun handleQuoteAction(action: RoomDetailActions.EnterQuoteMode) {
saveCurrentDraft(action.draft)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
withState { state ->
// Save a new draft and keep the previously entered text, if it was not an edit
timelineEvent.root.eventId?.let {
filterDraftUpdate = false
if (state.sendMode is SendMode.EDIT) {
room.saveDraft(UserDraft.QUOTE(it, ""))
} else {
@ -538,11 +525,12 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
private fun handleReplyAction(action: RoomDetailActions.EnterReplyMode) {
saveCurrentDraft(action.draft)
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
withState { state ->
// Save a new draft and keep the previously entered text, if it was not an edit
timelineEvent.root.eventId?.let {
filterDraftUpdate = false
if (state.sendMode is SendMode.EDIT) {
room.saveDraft(UserDraft.REPLY(it, ""))
} else {
@ -553,11 +541,23 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
}
private fun saveCurrentDraft(draft: String) {
// Save the draft with the current text if any
withState {
if (draft.isNotBlank()) {
when (it.sendMode) {
is SendMode.REGULAR -> room.saveDraft(UserDraft.REGULAR(draft))
is SendMode.REPLY -> room.saveDraft(UserDraft.REPLY(it.sendMode.timelineEvent.root.eventId!!, draft))
is SendMode.QUOTE -> room.saveDraft(UserDraft.QUOTE(it.sendMode.timelineEvent.root.eventId!!, draft))
is SendMode.EDIT -> room.saveDraft(UserDraft.EDIT(it.sendMode.timelineEvent.root.eventId!!, draft))
}
}
}
}
private fun handleExitSpecialMode(action: RoomDetailActions.ExitSpecialMode) {
withState { state ->
// For edit, just delete the current draft
filterDraftUpdate = false
if (state.sendMode is SendMode.EDIT) {
room.deleteDraft()
} else {