Add deleting messages (#290)

This commit is contained in:
Kacper Ziubryniewicz 2019-03-31 22:01:04 +02:00 committed by Rafał Borcz
parent f2855d598d
commit 2bff468e56
17 changed files with 195 additions and 32 deletions

View File

@ -58,4 +58,8 @@ class MessageRemote @Inject constructor(private val api: Api) {
} }
) )
} }
fun deleteMessage(message: Message): Single<Boolean> {
return api.deleteMessages(listOf(Pair(message.realId, message.folderId)))
}
} }

View File

@ -9,6 +9,7 @@ import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
import java.net.UnknownHostException import java.net.UnknownHostException
import javax.inject.Inject import javax.inject.Inject
@ -89,4 +90,20 @@ class MessageRepository @Inject constructor(
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
} }
fun deleteMessage(message: Message): Maybe<Boolean> {
return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.deleteMessage(message)
else Single.error(UnknownHostException())
}
.filter { it }
.doOnSuccess {
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
id = message.id
content = message.content
}))
else local.deleteMessages(listOf(message))
}
}
} }

View File

@ -7,6 +7,7 @@ import android.view.View.INVISIBLE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.view.ViewGroup import android.view.ViewGroup
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.message.MessageFolder.SENT import io.github.wulkanowy.data.repositories.message.MessageFolder.SENT
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
@ -75,12 +76,20 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView {
messageProgress.visibility = if (show) VISIBLE else INVISIBLE messageProgress.visibility = if (show) VISIBLE else INVISIBLE
} }
fun onDeleteMessage(message: Message) {
presenter.onDeleteMessage(message)
}
fun onChildFragmentLoaded() { fun onChildFragmentLoaded() {
presenter.onChildViewLoaded() presenter.onChildViewLoaded()
} }
override fun notifyChildMessageDeleted(tabId: Int) {
(pagerAdapter.getFragmentInstance(tabId) as? MessageTabFragment)?.onParentDeleteMessage()
}
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) { override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
(pagerAdapter.getFragmentInstance(index) as? MessageView.MessageChildView)?.onParentLoadData(forceRefresh) (pagerAdapter.getFragmentInstance(index) as? MessageTabFragment)?.onParentLoadData(forceRefresh)
} }
override fun openSendMessage() { override fun openSendMessage() {

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message package io.github.wulkanowy.ui.modules.message
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.SchedulersProvider
@ -43,6 +44,15 @@ class MessagePresenter @Inject constructor(
} }
} }
fun onDeleteMessage(message: Message) {
view?.notifyChildMessageDeleted(
when (message.removed) {
true -> 2
else -> message.folderId - 1
}
)
}
fun onSendMessageButtonClicked() { fun onSendMessageButtonClicked() {
view?.openSendMessage() view?.openSendMessage()
} }

View File

@ -14,10 +14,7 @@ interface MessageView : BaseView {
fun notifyChildLoadData(index: Int, forceRefresh: Boolean) fun notifyChildLoadData(index: Int, forceRefresh: Boolean)
fun notifyChildMessageDeleted(tabId: Int)
fun openSendMessage() fun openSendMessage()
interface MessageChildView {
fun onParentLoadData(forceRefresh: Boolean)
}
} }

View File

@ -13,7 +13,9 @@ import android.view.ViewGroup
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.ui.base.session.BaseSessionFragment import io.github.wulkanowy.ui.base.session.BaseSessionFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
import kotlinx.android.synthetic.main.fragment_message_preview.* import kotlinx.android.synthetic.main.fragment_message_preview.*
import javax.inject.Inject import javax.inject.Inject
@ -26,6 +28,7 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
private var menuReplyButton: MenuItem? = null private var menuReplyButton: MenuItem? = null
private var menuForwardButton: MenuItem? = null private var menuForwardButton: MenuItem? = null
private var menuDeleteButton: MenuItem? = null
override val titleStringId: Int override val titleStringId: Int
get() = R.string.message_title get() = R.string.message_title
@ -33,6 +36,9 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
override val noSubjectString: String override val noSubjectString: String
get() = getString(R.string.message_no_subject) get() = getString(R.string.message_no_subject)
override val deleteMessageSuccessString: String
get() = getString(R.string.message_delete_success)
companion object { companion object {
const val MESSAGE_ID_KEY = "message_id" const val MESSAGE_ID_KEY = "message_id"
@ -62,6 +68,7 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
inflater?.inflate(R.menu.action_menu_message_preview, menu) inflater?.inflate(R.menu.action_menu_message_preview, menu)
menuReplyButton = menu?.findItem(R.id.messagePreviewMenuReply) menuReplyButton = menu?.findItem(R.id.messagePreviewMenuReply)
menuForwardButton = menu?.findItem(R.id.messagePreviewMenuForward) menuForwardButton = menu?.findItem(R.id.messagePreviewMenuForward)
menuDeleteButton = menu?.findItem(R.id.messagePreviewMenuDelete)
presenter.onCreateOptionsMenu() presenter.onCreateOptionsMenu()
} }
@ -69,6 +76,7 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
return when (item?.itemId) { return when (item?.itemId) {
R.id.messagePreviewMenuReply -> presenter.onReply() R.id.messagePreviewMenuReply -> presenter.onReply()
R.id.messagePreviewMenuForward -> presenter.onForward() R.id.messagePreviewMenuForward -> presenter.onForward()
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
else -> false else -> false
} }
} }
@ -97,9 +105,22 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
messagePreviewProgress.visibility = if (show) VISIBLE else GONE messagePreviewProgress.visibility = if (show) VISIBLE else GONE
} }
override fun showContent(show: Boolean) {
messagePreviewContentContainer.visibility = if (show) VISIBLE else GONE
}
override fun showOptions(show: Boolean) { override fun showOptions(show: Boolean) {
menuReplyButton?.isVisible = show menuReplyButton?.isVisible = show
menuForwardButton?.isVisible = show menuForwardButton?.isVisible = show
menuDeleteButton?.isVisible = show
}
override fun setDeletedOptionsLabels() {
menuDeleteButton?.setTitle(R.string.message_delete_forever)
}
override fun setNotDeletedOptionsLabels() {
menuDeleteButton?.setTitle(R.string.message_move_to_bin)
} }
override fun showMessageError() { override fun showMessageError() {
@ -114,6 +135,14 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message)) } context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message)) }
} }
override fun popView() {
(activity as MainActivity).popView()
}
override fun notifyParentMessageDeleted(message: Message) {
fragmentManager?.fragments?.forEach { if (it is MessageFragment) it.onDeleteMessage(message) }
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putInt(MESSAGE_ID_KEY, presenter.messageId) outState.putInt(MESSAGE_ID_KEY, presenter.messageId)

View File

@ -47,7 +47,7 @@ class MessagePreviewPresenter @Inject constructor(
setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString) setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString)
setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")) setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
setContent(it.content.orEmpty()) setContent(it.content.orEmpty())
showOptions(true) initOptions()
if (it.recipient.isNotBlank()) setRecipient(it.recipient) if (it.recipient.isNotBlank()) setRecipient(it.recipient)
else setSender(it.sender) else setSender(it.sender)
@ -76,7 +76,56 @@ class MessagePreviewPresenter @Inject constructor(
} else false } else false
} }
private fun deleteMessage() {
message?.let { message ->
disposable.add(messageRepository.deleteMessage(message)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doOnSubscribe {
view?.run {
showContent(false)
showProgress(true)
showOptions(false)
}
}
.doFinally {
view?.showProgress(false)
}
.subscribe({
view?.run {
notifyParentMessageDeleted(message)
showMessage(deleteMessageSuccessString)
popView()
}
}, { error ->
view?.showMessageError()
errorHandler.dispatch(error)
}, {
view?.showMessageError()
})
)
}
}
fun onMessageDelete(): Boolean {
deleteMessage()
return true
}
private fun initOptions() {
view?.apply {
showOptions(message != null)
message?.let {
when (it.removed) {
true -> setDeletedOptionsLabels()
false -> setNotDeletedOptionsLabels()
}
}
}
}
fun onCreateOptionsMenu() { fun onCreateOptionsMenu() {
view?.showOptions(message != null) initOptions()
} }
} }

View File

@ -7,6 +7,8 @@ interface MessagePreviewView : BaseSessionView {
val noSubjectString: String val noSubjectString: String
val deleteMessageSuccessString: String
fun setSubject(subject: String) fun setSubject(subject: String)
fun setRecipient(recipient: String) fun setRecipient(recipient: String)
@ -19,11 +21,21 @@ interface MessagePreviewView : BaseSessionView {
fun showProgress(show: Boolean) fun showProgress(show: Boolean)
fun showContent(show: Boolean)
fun showOptions(show: Boolean) fun showOptions(show: Boolean)
fun setDeletedOptionsLabels()
fun setNotDeletedOptionsLabels()
fun showMessageError() fun showMessageError()
fun openMessageReply(message: Message?) fun openMessageReply(message: Message?)
fun openMessageForward(message: Message?) fun openMessageForward(message: Message?)
fun popView()
fun notifyParentMessageDeleted(message: Message)
} }

View File

@ -62,7 +62,7 @@ class SendMessageActivity : BaseActivity(), SendMessageView {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
messageContainer = sendMessageContainer messageContainer = sendMessageContainer
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message, intent.getSerializableExtra(EXTRA_REPLY) as Boolean) presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message, intent.getSerializableExtra(EXTRA_REPLY) as? Boolean)
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {

View File

@ -30,7 +30,7 @@ class SendMessagePresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper private val analytics: FirebaseAnalyticsHelper
) : BasePresenter<SendMessageView>(errorHandler) { ) : BasePresenter<SendMessageView>(errorHandler) {
fun onAttachView(view: SendMessageView, message: Message?, reply: Boolean) { fun onAttachView(view: SendMessageView, message: Message?, reply: Boolean?) {
super.onAttachView(view) super.onAttachView(view)
Timber.i("Send message view is attached") Timber.i("Send message view is attached")
loadData(message, reply) loadData(message, reply)
@ -38,13 +38,13 @@ class SendMessagePresenter @Inject constructor(
message?.let { message?.let {
setSubject(when (reply) { setSubject(when (reply) {
true -> "RE: " true -> "RE: "
false -> "FE: " else -> "FW: "
} + message.subject) } + message.subject)
if (preferencesRepository.fillMessageContent || !reply) { if (preferencesRepository.fillMessageContent || reply != true) {
setContent( setContent(
when (reply) { when (reply) {
true -> "\n\n" true -> "\n\n"
false -> "" else -> ""
} + when (message.sender.isNotEmpty()) { } + when (message.sender.isNotEmpty()) {
true -> "Od: ${message.sender}\n" true -> "Od: ${message.sender}\n"
false -> "Do: ${message.recipient}\n" false -> "Do: ${message.recipient}\n"
@ -59,7 +59,7 @@ class SendMessagePresenter @Inject constructor(
return true return true
} }
private fun loadData(message: Message?, reply: Boolean) { private fun loadData(message: Message?, reply: Boolean?) {
var reportingUnit: ReportingUnit? = null var reportingUnit: ReportingUnit? = null
var recipients: List<Recipient> = emptyList() var recipients: List<Recipient> = emptyList()
var selectedRecipient: List<Recipient> = emptyList() var selectedRecipient: List<Recipient> = emptyList()
@ -76,7 +76,7 @@ class SendMessagePresenter @Inject constructor(
recipients = it recipients = it
} }
.flatMapCompletable { .flatMapCompletable {
if (message == null || !reply) Completable.complete() if (message == null || reply != true) Completable.complete()
else recipientRepository.getMessageRecipients(student, message) else recipientRepository.getMessageRecipients(student, message)
.doOnSuccess { .doOnSuccess {
Timber.i("Loaded message recipients to reply result: Success, fetched %d recipients", it.size) Timber.i("Loaded message recipients to reply result: Success, fetched %d recipients", it.size)

View File

@ -17,13 +17,12 @@ import io.github.wulkanowy.ui.base.session.BaseSessionFragment
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.message.MessageItem import io.github.wulkanowy.ui.modules.message.MessageItem
import io.github.wulkanowy.ui.modules.message.MessageView
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
import io.github.wulkanowy.utils.setOnItemClickListener import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_message_tab.* import kotlinx.android.synthetic.main.fragment_message_tab.*
import javax.inject.Inject import javax.inject.Inject
class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.MessageChildView { class MessageTabFragment : BaseSessionFragment(), MessageTabView {
@Inject @Inject
lateinit var presenter: MessageTabPresenter lateinit var presenter: MessageTabPresenter
@ -115,10 +114,14 @@ class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.Me
(parentFragment as? MessageFragment)?.onChildFragmentLoaded() (parentFragment as? MessageFragment)?.onChildFragmentLoaded()
} }
override fun onParentLoadData(forceRefresh: Boolean) { fun onParentLoadData(forceRefresh: Boolean) {
presenter.onParentViewLoadData(forceRefresh) presenter.onParentViewLoadData(forceRefresh)
} }
fun onParentDeleteMessage() {
presenter.onDeleteMessage()
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putString(MessageTabFragment.MESSAGE_TAB_FOLDER_ID, presenter.folder.name) outState.putString(MessageTabFragment.MESSAGE_TAB_FOLDER_ID, presenter.folder.name)

View File

@ -34,7 +34,29 @@ class MessageTabPresenter @Inject constructor(
onParentViewLoadData(true) onParentViewLoadData(true)
} }
fun onDeleteMessage() {
loadData(false)
}
fun onParentViewLoadData(forceRefresh: Boolean) { fun onParentViewLoadData(forceRefresh: Boolean) {
loadData(forceRefresh)
}
fun onMessageItemSelected(item: AbstractFlexibleItem<*>) {
if (item is MessageItem) {
Timber.i("Select message ${item.message.realId} item")
view?.run {
openMessage(item.message.realId)
if (item.message.unread) {
item.message.unread = false
updateItem(item)
updateMessage(item.message)
}
}
}
}
private fun loadData(forceRefresh: Boolean) {
Timber.i("Loading $folder message data started") Timber.i("Loading $folder message data started")
disposable.apply { disposable.apply {
clear() clear()
@ -67,20 +89,6 @@ class MessageTabPresenter @Inject constructor(
} }
} }
fun onMessageItemSelected(item: AbstractFlexibleItem<*>) {
if (item is MessageItem) {
Timber.i("Select message ${item.message.realId} item")
view?.run {
openMessage(item.message.realId)
if (item.message.unread) {
item.message.unread = false
updateItem(item)
updateMessage(item.message)
}
}
}
}
private fun updateMessage(message: Message) { private fun updateMessage(message: Message) {
Timber.i("Attempt to update message ${message.realId}") Timber.i("Attempt to update message ${message.realId}")
disposable.add(messageRepository.updateMessage(message) disposable.add(messageRepository.updateMessage(message)

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
</vector>

View File

@ -10,6 +10,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/messagePreviewContentContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"

View File

@ -13,4 +13,10 @@
android:orderInCategory="1" android:orderInCategory="1"
android:title="@string/message_forward" android:title="@string/message_forward"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/messagePreviewMenuDelete"
android:icon="@drawable/ic_message_delete_24dp"
android:orderInCategory="1"
android:title="@string/message_delete"
app:showAsAction="ifRoom" />
</menu> </menu>

View File

@ -141,6 +141,10 @@
<string name="message_date">Data: %s</string> <string name="message_date">Data: %s</string>
<string name="message_reply">Odpowiedz</string> <string name="message_reply">Odpowiedz</string>
<string name="message_forward">Prześlij dalej</string> <string name="message_forward">Prześlij dalej</string>
<string name="message_delete">Usuń</string>
<string name="message_move_to_bin">Przenieś do kosza</string>
<string name="message_delete_forever">Usuń trwale</string>
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
<string name="message_subject">Temat</string> <string name="message_subject">Temat</string>
<string name="message_content">Treść</string> <string name="message_content">Treść</string>
<string name="message_send_successful">Wiadomość wysłana pomyślnie</string> <string name="message_send_successful">Wiadomość wysłana pomyślnie</string>

View File

@ -135,6 +135,10 @@
<string name="message_date">Date: %s</string> <string name="message_date">Date: %s</string>
<string name="message_reply">Reply</string> <string name="message_reply">Reply</string>
<string name="message_forward">Forward</string> <string name="message_forward">Forward</string>
<string name="message_delete">Delete</string>
<string name="message_move_to_bin">Move to trash</string>
<string name="message_delete_forever">Delete permanently</string>
<string name="message_delete_success">Message deleted successfully</string>
<string name="message_subject">Subject</string> <string name="message_subject">Subject</string>
<string name="message_content">Content</string> <string name="message_content">Content</string>
<string name="message_send_successful">Message sent successfully</string> <string name="message_send_successful">Message sent successfully</string>