Loading app/core/src/main/java/com/fsck/k9/message/ReplyActionStrategy.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line package com.fsck.k9.message import com.fsck.k9.Account import com.fsck.k9.helper.ReplyToParser import com.fsck.k9.mail.Message /** * Figures out which reply actions are available to the user. */ class ReplyActionStrategy(private val replyRoParser: ReplyToParser) { fun getReplyActions(account: Account, message: Message): ReplyActions { val recipientsToReplyTo = replyRoParser.getRecipientsToReplyTo(message, account) val recipientsToReplyAllTo = replyRoParser.getRecipientsToReplyAllTo(message, account) val replyToAllCount = recipientsToReplyAllTo.to.size + recipientsToReplyAllTo.cc.size return if (replyToAllCount <= 1) { if (recipientsToReplyTo.to.isEmpty()) { ReplyActions(defaultAction = null) } else { ReplyActions(defaultAction = ReplyAction.REPLY) } } else { ReplyActions(defaultAction = ReplyAction.REPLY_ALL, additionalActions = listOf(ReplyAction.REPLY)) } } } data class ReplyActions( val defaultAction: ReplyAction?, val additionalActions: List<ReplyAction> = emptyList() ) enum class ReplyAction { REPLY, REPLY_ALL } app/core/src/test/java/com/fsck/k9/message/ReplyActionStrategyTest.kt 0 → 100644 +111 −0 Original line number Diff line number Diff line package com.fsck.k9.message import com.fsck.k9.Account import com.fsck.k9.Identity import com.fsck.k9.helper.ReplyToParser import com.fsck.k9.mail.buildMessage import com.google.common.truth.Truth.assertThat import org.junit.Test private const val IDENTITY_EMAIL_ADDRESS = "myself@domain.example" class ReplyActionStrategyTest { private val account = createAccount() private val replyActionStrategy = ReplyActionStrategy(ReplyToParser()) @Test fun `message sent to only our identity`() { val message = buildMessage { header("From", "sender@domain.example") header("To", IDENTITY_EMAIL_ADDRESS) } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY) assertThat(replyActions.additionalActions).isEmpty() } @Test fun `message sent to our identity and others`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "$IDENTITY_EMAIL_ADDRESS, other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (CC)`() { val message = buildMessage { header("From", "sender@domain.example") header("Cc", "$IDENTITY_EMAIL_ADDRESS, other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (To+CC)`() { val message = buildMessage { header("From", "sender@domain.example") header("To", IDENTITY_EMAIL_ADDRESS) header("Cc", "other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (CC+To)`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "other@domain.example") header("Cc", IDENTITY_EMAIL_ADDRESS) } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message where neither sender nor recipient addresses belong to account`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "recipient@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message without any sender or recipient headers`() { val message = buildMessage {} val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isNull() assertThat(replyActions.additionalActions).isEmpty() } private fun createAccount(): Account { return Account("00000000-0000-4000-0000-000000000000").apply { identities += Identity(name = "Myself", email = IDENTITY_EMAIL_ADDRESS) } } } app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageHeaderOnMenuItemClickListener.kt 0 → 100644 +5 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messageview fun interface MessageHeaderOnMenuItemClickListener { fun onMenuItemClick(itemId: Int) } app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageTopView.java +2 −2 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -226,7 +226,7 @@ public class MessageTopView extends LinearLayout { mHeaderContainer.setOnFlagListener(listener); } public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { public void setOnMenuItemClickListener(MessageHeaderOnMenuItemClickListener listener) { mHeaderContainer.setOnMenuItemClickListener(listener); } Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt +2 −6 Original line number Diff line number Diff line Loading @@ -158,9 +158,7 @@ class MessageViewFragment : onToggleFlagged() } messageTopView.setOnMenuItemClickListener { item -> onReplyMenuItemClicked(item.itemId) } messageTopView.setOnMenuItemClickListener(::onReplyMenuItemClicked) messageTopView.setOnDownloadButtonClickListener { onDownloadButtonClicked() Loading Loading @@ -381,7 +379,7 @@ class MessageViewFragment : messageTopView.setSubject(displaySubject) } private fun onReplyMenuItemClicked(itemId: Int): Boolean { private fun onReplyMenuItemClicked(itemId: Int) { when (itemId) { R.id.reply -> onReply() R.id.reply_all -> onReplyAll() Loading @@ -390,8 +388,6 @@ class MessageViewFragment : R.id.share -> onSendAlternate() else -> error("Missing handler for reply menu item $itemId") } return true } private fun onDownloadButtonClicked() { Loading Loading
app/core/src/main/java/com/fsck/k9/message/ReplyActionStrategy.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line package com.fsck.k9.message import com.fsck.k9.Account import com.fsck.k9.helper.ReplyToParser import com.fsck.k9.mail.Message /** * Figures out which reply actions are available to the user. */ class ReplyActionStrategy(private val replyRoParser: ReplyToParser) { fun getReplyActions(account: Account, message: Message): ReplyActions { val recipientsToReplyTo = replyRoParser.getRecipientsToReplyTo(message, account) val recipientsToReplyAllTo = replyRoParser.getRecipientsToReplyAllTo(message, account) val replyToAllCount = recipientsToReplyAllTo.to.size + recipientsToReplyAllTo.cc.size return if (replyToAllCount <= 1) { if (recipientsToReplyTo.to.isEmpty()) { ReplyActions(defaultAction = null) } else { ReplyActions(defaultAction = ReplyAction.REPLY) } } else { ReplyActions(defaultAction = ReplyAction.REPLY_ALL, additionalActions = listOf(ReplyAction.REPLY)) } } } data class ReplyActions( val defaultAction: ReplyAction?, val additionalActions: List<ReplyAction> = emptyList() ) enum class ReplyAction { REPLY, REPLY_ALL }
app/core/src/test/java/com/fsck/k9/message/ReplyActionStrategyTest.kt 0 → 100644 +111 −0 Original line number Diff line number Diff line package com.fsck.k9.message import com.fsck.k9.Account import com.fsck.k9.Identity import com.fsck.k9.helper.ReplyToParser import com.fsck.k9.mail.buildMessage import com.google.common.truth.Truth.assertThat import org.junit.Test private const val IDENTITY_EMAIL_ADDRESS = "myself@domain.example" class ReplyActionStrategyTest { private val account = createAccount() private val replyActionStrategy = ReplyActionStrategy(ReplyToParser()) @Test fun `message sent to only our identity`() { val message = buildMessage { header("From", "sender@domain.example") header("To", IDENTITY_EMAIL_ADDRESS) } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY) assertThat(replyActions.additionalActions).isEmpty() } @Test fun `message sent to our identity and others`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "$IDENTITY_EMAIL_ADDRESS, other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (CC)`() { val message = buildMessage { header("From", "sender@domain.example") header("Cc", "$IDENTITY_EMAIL_ADDRESS, other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (To+CC)`() { val message = buildMessage { header("From", "sender@domain.example") header("To", IDENTITY_EMAIL_ADDRESS) header("Cc", "other@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message sent to our identity and others (CC+To)`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "other@domain.example") header("Cc", IDENTITY_EMAIL_ADDRESS) } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message where neither sender nor recipient addresses belong to account`() { val message = buildMessage { header("From", "sender@domain.example") header("To", "recipient@domain.example") } val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isEqualTo(ReplyAction.REPLY_ALL) assertThat(replyActions.additionalActions).containsExactly(ReplyAction.REPLY) } @Test fun `message without any sender or recipient headers`() { val message = buildMessage {} val replyActions = replyActionStrategy.getReplyActions(account, message) assertThat(replyActions.defaultAction).isNull() assertThat(replyActions.additionalActions).isEmpty() } private fun createAccount(): Account { return Account("00000000-0000-4000-0000-000000000000").apply { identities += Identity(name = "Myself", email = IDENTITY_EMAIL_ADDRESS) } } }
app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageHeaderOnMenuItemClickListener.kt 0 → 100644 +5 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messageview fun interface MessageHeaderOnMenuItemClickListener { fun onMenuItemClick(itemId: Int) }
app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageTopView.java +2 −2 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -226,7 +226,7 @@ public class MessageTopView extends LinearLayout { mHeaderContainer.setOnFlagListener(listener); } public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { public void setOnMenuItemClickListener(MessageHeaderOnMenuItemClickListener listener) { mHeaderContainer.setOnMenuItemClickListener(listener); } Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt +2 −6 Original line number Diff line number Diff line Loading @@ -158,9 +158,7 @@ class MessageViewFragment : onToggleFlagged() } messageTopView.setOnMenuItemClickListener { item -> onReplyMenuItemClicked(item.itemId) } messageTopView.setOnMenuItemClickListener(::onReplyMenuItemClicked) messageTopView.setOnDownloadButtonClickListener { onDownloadButtonClicked() Loading Loading @@ -381,7 +379,7 @@ class MessageViewFragment : messageTopView.setSubject(displaySubject) } private fun onReplyMenuItemClicked(itemId: Int): Boolean { private fun onReplyMenuItemClicked(itemId: Int) { when (itemId) { R.id.reply -> onReply() R.id.reply_all -> onReplyAll() Loading @@ -390,8 +388,6 @@ class MessageViewFragment : R.id.share -> onSendAlternate() else -> error("Missing handler for reply menu item $itemId") } return true } private fun onDownloadButtonClicked() { Loading