diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/BlockSenderDialogState.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/BlockSenderDialogState.kt
new file mode 100644
index 0000000000..4e582da105
--- /dev/null
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/BlockSenderDialogState.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2025 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.maildetail.presentation.model
+
+import ch.protonmail.android.mailcontact.domain.model.ContactId
+
+sealed interface BlockSenderDialogState {
+
+ object Hidden : BlockSenderDialogState
+
+ sealed interface Shown : BlockSenderDialogState {
+ data class ShowConfirmation(
+ val messageId: MessageIdUiModel?,
+ val email: String,
+ val contactId: ContactId?
+ ) : Shown
+ }
+}
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailOperation.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailOperation.kt
index 8cd62e3f22..b6f77d0567 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailOperation.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailOperation.kt
@@ -27,6 +27,7 @@ import ch.protonmail.android.mailattachments.domain.model.OpenAttachmentIntentVa
import ch.protonmail.android.mailcommon.presentation.model.AvatarUiModel
import ch.protonmail.android.mailcommon.presentation.model.BottomBarEvent
import ch.protonmail.android.mailcommon.presentation.model.BottomSheetOperation
+import ch.protonmail.android.mailcontact.domain.model.ContactId
import ch.protonmail.android.mailconversation.domain.entity.HiddenMessagesBanner
import ch.protonmail.android.maildetail.domain.model.OpenProtonCalendarIntentValues
import ch.protonmail.android.maildetail.presentation.R
@@ -39,6 +40,7 @@ import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOpe
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation.AffectingMessageBar
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation.AffectingMessages
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation.AffectingReportPhishingDialog
+import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation.AffectingBlockSenderDialog
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation.AffectingHiddenMessagesBanner
import ch.protonmail.android.maillabel.domain.model.LabelId
import ch.protonmail.android.maillabel.domain.model.SystemLabelId
@@ -63,6 +65,8 @@ sealed interface ConversationDetailOperation {
sealed interface AffectingHiddenMessagesBanner
sealed interface AffectingMarkAsLegitimateDialog
sealed interface AffectingEditScheduleMessageDialog
+ sealed interface AffectingBlockSenderDialog
+
}
sealed interface ConversationDetailEvent : ConversationDetailOperation {
@@ -350,8 +354,13 @@ sealed interface ConversationDetailViewAction : ConversationDetailOperation {
data class UnblockSender(val messageId: MessageIdUiModel?, val email: String) :
ConversationDetailViewAction, AffectingBottomSheet
- data class BlockSender(val messageId: MessageIdUiModel?, val email: String) :
- ConversationDetailViewAction, AffectingBottomSheet
+ data class BlockSender(val messageId: MessageIdUiModel?, val email: String, val contactId: ContactId?) :
+ ConversationDetailViewAction, AffectingBottomSheet, AffectingBlockSenderDialog
+ object BlockSenderDismissed : ConversationDetailViewAction, AffectingBlockSenderDialog
+ data class BlockSenderConfirmed(
+ val messageId: MessageIdUiModel?,
+ val email: String
+ ) : ConversationDetailViewAction, AffectingBlockSenderDialog
data object EditScheduleSendMessageDismissed :
ConversationDetailViewAction, AffectingEditScheduleMessageDialog
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailState.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailState.kt
index aabb3f1ae4..3cf8279151 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailState.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/model/ConversationDetailState.kt
@@ -46,7 +46,8 @@ data class ConversationDetailState(
val reportPhishingDialogState: ReportPhishingDialogState,
val hiddenMessagesBannerState: HiddenMessagesBannerState,
val markAsLegitimateDialogState: MarkAsLegitimateDialogState,
- val editScheduledMessageDialogState: EditScheduledMessageDialogState
+ val editScheduledMessageDialogState: EditScheduledMessageDialogState,
+ val blockSenderDialogState: BlockSenderDialogState
) {
companion object {
@@ -71,7 +72,8 @@ data class ConversationDetailState(
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
}
}
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/previewdata/ConversationDetailsPreviewData.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/previewdata/ConversationDetailsPreviewData.kt
index 57a3d8835f..b1a707e015 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/previewdata/ConversationDetailsPreviewData.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/previewdata/ConversationDetailsPreviewData.kt
@@ -30,6 +30,7 @@ import ch.protonmail.android.mailcommon.presentation.model.contentDescription
import ch.protonmail.android.mailcommon.presentation.model.description
import ch.protonmail.android.mailcommon.presentation.model.iconDrawable
import ch.protonmail.android.mailcommon.presentation.sample.TextMessageSample
+import ch.protonmail.android.maildetail.presentation.model.BlockSenderDialogState
import ch.protonmail.android.maildetail.presentation.model.ConversationDeleteState
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailMetadataState
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailState
@@ -97,7 +98,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val SuccessWithRandomMessageIds = ConversationDetailState(
@@ -154,7 +156,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val FailedLoadingConversation = ConversationDetailState(
@@ -177,7 +180,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val FailedLoadingMessages = ConversationDetailState(
@@ -200,7 +204,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val FailedLoadingBottomBar = ConversationDetailState(
@@ -223,7 +228,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val Loading = ConversationDetailState(
@@ -246,7 +252,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
val NotLoggedIn = ConversationDetailState(
@@ -269,7 +276,8 @@ object ConversationDetailsPreviewData {
reportPhishingDialogState = ReportPhishingDialogState.Hidden,
hiddenMessagesBannerState = HiddenMessagesBannerState.Hidden,
markAsLegitimateDialogState = MarkAsLegitimateDialogState.Hidden,
- editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden
+ editScheduledMessageDialogState = EditScheduledMessageDialogState.Hidden,
+ blockSenderDialogState = BlockSenderDialogState.Hidden
)
}
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducer.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducer.kt
new file mode 100644
index 0000000000..f165620538
--- /dev/null
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducer.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2025 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.maildetail.presentation.reducer
+
+import ch.protonmail.android.maildetail.presentation.model.BlockSenderDialogState
+import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation
+import ch.protonmail.android.maildetail.presentation.model.ConversationDetailViewAction
+import javax.inject.Inject
+
+class ConversationBlockSenderDialogReducer @Inject constructor() {
+
+ internal fun newStateFrom(operation: ConversationDetailOperation.AffectingBlockSenderDialog) = when (operation) {
+ is ConversationDetailViewAction.BlockSenderDismissed,
+ is ConversationDetailViewAction.BlockSenderConfirmed -> BlockSenderDialogState.Hidden
+ is ConversationDetailViewAction.BlockSender -> BlockSenderDialogState.Shown.ShowConfirmation(
+ messageId = operation.messageId,
+ email = operation.email,
+ contactId = operation.contactId
+ )
+ }
+}
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducer.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducer.kt
index d53f4d3724..a377bf3bd7 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducer.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducer.kt
@@ -27,6 +27,7 @@ import ch.protonmail.android.mailcommon.presentation.reducer.BottomBarReducer
import ch.protonmail.android.maildetail.domain.model.OpenProtonCalendarIntentValues
import ch.protonmail.android.maildetail.presentation.R
import ch.protonmail.android.maildetail.presentation.mapper.ActionResultMapper
+import ch.protonmail.android.maildetail.presentation.model.BlockSenderDialogState
import ch.protonmail.android.maildetail.presentation.model.ConversationDeleteState
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ConversationBottomBarEvent
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ConversationBottomSheetEvent
@@ -85,6 +86,7 @@ class ConversationDetailReducer @Inject constructor(
private val bottomSheetReducer: BottomSheetReducer,
private val deleteDialogReducer: ConversationDeleteDialogReducer,
private val reportPhishingDialogReducer: ConversationReportPhishingDialogReducer,
+ private val blockSenderDialogReducer: ConversationBlockSenderDialogReducer,
private val hiddenMessagesBannerReducer: HiddenMessagesBannerReducer,
private val markAsLegitimateDialogReducer: MarkAsLegitimateDialogReducer,
private val editScheduledMessageDialogReducer: EditScheduledMessageDialogReducer,
@@ -114,7 +116,8 @@ class ConversationDetailReducer @Inject constructor(
reportPhishingDialogState = currentState.toNewReportPhishingDialogState(operation),
hiddenMessagesBannerState = currentState.toNewHiddenMessagesBannerState(operation),
markAsLegitimateDialogState = currentState.toNewMarkAsLegitimateDialogState(operation),
- editScheduledMessageDialogState = currentState.toNewEditScheduleMessageDialogState(operation)
+ editScheduledMessageDialogState = currentState.toNewEditScheduleMessageDialogState(operation),
+ blockSenderDialogState = currentState.toNewBlockSenderDialogState(operation)
)
}
@@ -380,6 +383,16 @@ class ConversationDetailReducer @Inject constructor(
}
}
+ private fun ConversationDetailState.toNewBlockSenderDialogState(
+ operation: ConversationDetailOperation
+ ): BlockSenderDialogState {
+ return if (operation is ConversationDetailOperation.AffectingBlockSenderDialog) {
+ blockSenderDialogReducer.newStateFrom(operation)
+ } else {
+ blockSenderDialogState
+ }
+ }
+
private fun ConversationDetailState.toNewHiddenMessagesBannerState(
operation: ConversationDetailOperation
): HiddenMessagesBannerState {
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/ConversationDetailScreen.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/ConversationDetailScreen.kt
index a065e86d9d..2c8972f7fa 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/ConversationDetailScreen.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/ConversationDetailScreen.kt
@@ -116,6 +116,7 @@ import ch.protonmail.android.maildetail.presentation.model.MessageIdUiModel
import ch.protonmail.android.maildetail.presentation.model.MoreActionsBottomSheetEntryPoint
import ch.protonmail.android.maildetail.presentation.model.ParticipantUiModel
import ch.protonmail.android.maildetail.presentation.previewdata.ConversationDetailsPreviewProvider
+import ch.protonmail.android.maildetail.presentation.ui.dialog.BlockSenderDialog
import ch.protonmail.android.maildetail.presentation.ui.dialog.EditScheduleSendDialog
import ch.protonmail.android.maildetail.presentation.ui.dialog.MarkAsLegitimateDialog
import ch.protonmail.android.maildetail.presentation.ui.dialog.ReportPhishingDialog
@@ -242,6 +243,13 @@ fun ConversationDetailScreen(
onDismiss = { viewModel.submit(ConversationDetailViewAction.EditScheduleSendMessageDismissed) }
)
+ BlockSenderDialog(
+ state = state.blockSenderDialogState,
+ onConfirm = { messageId, email ->
+ viewModel.submit(ConversationDetailViewAction.BlockSenderConfirmed(messageId, email))
+ },
+ onDismiss = { viewModel.submit(ConversationDetailViewAction.BlockSenderDismissed) }
+ )
ProtonModalBottomSheetLayout(
showBottomSheet = showBottomSheet,
@@ -435,10 +443,12 @@ fun ConversationDetailScreen(
viewModel.submit(ConversationDetailViewAction.DismissBottomSheet)
actions.onComposeNewMessage(it.address)
},
- onBlockClicked = { participant, messageId ->
+ onBlockClicked = { participant, messageId, contactId ->
viewModel.submit(
ConversationDetailViewAction.BlockSender(
- messageId?.let { MessageIdUiModel(it.id) }, participant.address
+ messageId = messageId?.let { MessageIdUiModel(it.id) },
+ email = participant.address,
+ contactId = contactId
)
)
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/dialog/BlockSenderDialog.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/dialog/BlockSenderDialog.kt
new file mode 100644
index 0000000000..738cc903c6
--- /dev/null
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/ui/dialog/BlockSenderDialog.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2022 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.maildetail.presentation.ui.dialog
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import ch.protonmail.android.maildetail.presentation.R
+import ch.protonmail.android.design.compose.component.ProtonAlertDialog
+import ch.protonmail.android.design.compose.component.ProtonAlertDialogButton
+import ch.protonmail.android.design.compose.component.ProtonAlertDialogText
+import ch.protonmail.android.design.compose.theme.ProtonTheme
+import ch.protonmail.android.mailcontact.domain.model.ContactId
+import ch.protonmail.android.maildetail.presentation.model.BlockSenderDialogState
+import ch.protonmail.android.maildetail.presentation.model.MessageIdUiModel
+
+@Composable
+fun BlockSenderDialog(
+ state: BlockSenderDialogState,
+ onDismiss: () -> Unit,
+ onConfirm: (MessageIdUiModel?, String) -> Unit
+) {
+ if (state is BlockSenderDialogState.Shown) {
+ when (state) {
+ is BlockSenderDialogState.Shown.ShowConfirmation -> BlockSenderDialog(
+ email = state.email,
+ contactId = state.contactId,
+ onDismiss = onDismiss,
+ onConfirm = { onConfirm(state.messageId, state.email) }
+ )
+ }
+ }
+}
+
+@Composable
+private fun BlockSenderDialog(
+ email: String,
+ contactId: ContactId?,
+ onDismiss: () -> Unit,
+ onConfirm: () -> Unit
+) {
+ ProtonAlertDialog(
+ onDismissRequest = onDismiss,
+ confirmButton = {
+ ProtonAlertDialogButton(
+ titleResId = R.string.contact_actions_block_contact_dialog_button_block,
+ textColor = ProtonTheme.colors.notificationError
+ ) { onConfirm() }
+ },
+ dismissButton = {
+ ProtonAlertDialogButton(R.string.contact_actions_block_contact_dialog_button_cancel) { onDismiss() }
+ },
+ title = stringResource(
+ id = contactId?.let { R.string.contact_actions_block_contact }
+ ?: R.string.contact_actions_block_address
+ ),
+ text = {
+ ProtonAlertDialogText(
+ text = stringResource(
+ id = R.string.contact_actions_block_contact_dialog_text,
+ email
+ )
+ )
+ }
+ )
+}
diff --git a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModel.kt b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModel.kt
index 15676f2374..c8c89484e7 100644
--- a/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModel.kt
+++ b/mail-detail/presentation/src/main/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModel.kt
@@ -387,6 +387,8 @@ class ConversationDetailViewModel @Inject constructor(
is ScrollRequestCompleted,
is ConversationDetailViewAction.ReportPhishing,
is ConversationDetailViewAction.ReportPhishingDismissed,
+ is ConversationDetailViewAction.BlockSender,
+ is ConversationDetailViewAction.BlockSenderDismissed,
is ConversationDetailViewAction.MarkMessageAsLegitimate,
is ConversationDetailViewAction.MarkMessageAsLegitimateDismissed,
is ConversationDetailViewAction.EditScheduleSendMessageDismissed,
@@ -429,7 +431,7 @@ class ConversationDetailViewModel @Inject constructor(
handleMarkMessageAsLegitimateConfirmed(action)
is ConversationDetailViewAction.UnblockSender -> handleUnblockSender(action)
- is ConversationDetailViewAction.BlockSender -> handleBlockSender(action)
+ is ConversationDetailViewAction.BlockSenderConfirmed -> handleBlockSenderConfirmed(action)
is ConversationDetailViewAction.EditScheduleSendMessageConfirmed -> handleEditScheduleSendMessage(action)
is ConversationDetailViewAction.PrintMessage -> handlePrintMessage(action.context, action.messageId)
is ConversationDetailViewAction.RetryRsvpEventLoading ->
@@ -1693,19 +1695,20 @@ class ConversationDetailViewModel @Inject constructor(
}
}
- private fun handleBlockSender(action: ConversationDetailViewAction.BlockSender) = viewModelScope.launch {
+ private fun handleBlockSenderConfirmed(action: ConversationDetailViewAction.BlockSenderConfirmed) =
viewModelScope.launch {
- blockSender(
- userId = primaryUserId.first(),
- email = action.email
- ).fold(
- ifLeft = { Timber.e("Failed to block sender in message ${action.messageId?.id}") },
- ifRight = { action.messageId?.let { setOrRefreshMessageBody(it) } }
- )
+ viewModelScope.launch {
+ blockSender(
+ userId = primaryUserId.first(),
+ email = action.email
+ ).fold(
+ ifLeft = { Timber.e("Failed to block sender in message ${action.messageId?.id}") },
+ ifRight = { action.messageId?.let { setOrRefreshMessageBody(it) } }
+ )
- emitNewStateFrom(action)
+ emitNewStateFrom(action)
+ }
}
- }
private fun handleGetRsvpEvent(messageId: MessageId, refresh: Boolean) {
viewModelScope.launch {
diff --git a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducerTest.kt b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducerTest.kt
new file mode 100644
index 0000000000..c969c6cde4
--- /dev/null
+++ b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationBlockSenderDialogReducerTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2025 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.maildetail.presentation.reducer
+
+import ch.protonmail.android.maildetail.presentation.model.BlockSenderDialogState
+import ch.protonmail.android.maildetail.presentation.model.ConversationDetailOperation
+import ch.protonmail.android.maildetail.presentation.model.ConversationDetailViewAction
+import ch.protonmail.android.maildetail.presentation.model.MessageIdUiModel
+import ch.protonmail.android.testdata.contact.ContactIdSample
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class ConversationBlockSenderDialogReducerTest(
+ private val testName: String,
+ private val testInput: TestInput
+) {
+
+ private val blockSenderDialogReducer = ConversationBlockSenderDialogReducer()
+
+ @Test
+ fun `should produce the expected new state`() = with(testInput) {
+ val actualState = blockSenderDialogReducer.newStateFrom(operation)
+
+ assertEquals(testName, expectedState, actualState)
+ }
+
+ companion object {
+
+ private val transitions = listOf(
+ TestInput(
+ operation = ConversationDetailViewAction.BlockSenderDismissed,
+ expectedState = BlockSenderDialogState.Hidden
+ ),
+ TestInput(
+ operation = ConversationDetailViewAction.BlockSenderConfirmed(
+ MessageIdUiModel("msg-123"), "test@example.com"
+ ),
+ expectedState = BlockSenderDialogState.Hidden
+ ),
+ TestInput(
+ operation = ConversationDetailViewAction.BlockSender(
+ messageId = MessageIdUiModel("HtmlInvoice"),
+ email = "test@example.com",
+ contactId = ContactIdSample.Doe
+ ),
+ expectedState = BlockSenderDialogState.Shown.ShowConfirmation(
+ messageId = MessageIdUiModel("HtmlInvoice"),
+ email = "test@example.com",
+ contactId = ContactIdSample.Doe
+ )
+ )
+ )
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data(): Collection> {
+ return transitions.map {
+ val testName = """
+ Operation: ${it.operation}
+ Expected State: ${it.expectedState}
+ """.trimIndent()
+ arrayOf(testName, it)
+ }
+ }
+
+ data class TestInput(
+ val operation: ConversationDetailOperation.AffectingBlockSenderDialog,
+ val expectedState: BlockSenderDialogState
+ )
+ }
+}
diff --git a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducerTest.kt b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducerTest.kt
index bc31d4a39f..2d10cc096e 100644
--- a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducerTest.kt
+++ b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/reducer/ConversationDetailReducerTest.kt
@@ -78,6 +78,7 @@ class ConversationDetailReducerTest(
private val bottomSheetReducer = mockk(relaxed = true)
private val deleteDialogReducer = mockk(relaxed = true)
private val reportPhishingDialogReducer = mockk(relaxed = true)
+ private val blockSenderDialogReducer = mockk(relaxed = true)
private val trashedMessagesBannerReducer = mockk(relaxed = true)
private val markAsLegitimateDialogReducer = mockk(relaxed = true)
private val editScheduledMessageDialogReducer = mockk(relaxed = true)
@@ -88,6 +89,7 @@ class ConversationDetailReducerTest(
bottomSheetReducer = bottomSheetReducer,
deleteDialogReducer = deleteDialogReducer,
reportPhishingDialogReducer = reportPhishingDialogReducer,
+ blockSenderDialogReducer = blockSenderDialogReducer,
hiddenMessagesBannerReducer = trashedMessagesBannerReducer,
markAsLegitimateDialogReducer = markAsLegitimateDialogReducer,
editScheduledMessageDialogReducer = editScheduledMessageDialogReducer,
@@ -181,6 +183,12 @@ class ConversationDetailReducerTest(
verify { reportPhishingDialogReducer wasNot Called }
}
+ if (reducesBlockSenderDialog) {
+ verify { blockSenderDialogReducer.newStateFrom(any()) }
+ } else {
+ verify { blockSenderDialogReducer wasNot Called }
+ }
+
if (reducesMarkAsLegitimateDialog) {
verify { markAsLegitimateDialogReducer.newStateFrom(any()) }
} else {
@@ -210,6 +218,7 @@ class ConversationDetailReducerTest(
val reducesDeleteDialog: Boolean,
val reducesTrashedMessagesBanner: Boolean,
val reducesReportPhishingDialog: Boolean,
+ val reducesBlockSenderDialog: Boolean,
val reducesMarkAsLegitimateDialog: Boolean,
val reducesEditScheduleSendDialog: Boolean
) {
@@ -278,6 +287,13 @@ class ConversationDetailReducerTest(
MessageId(messageId.id)
) affects listOf(ReportPhishingDialog),
ConversationDetailViewAction.ReportPhishingDismissed affects listOf(ReportPhishingDialog),
+ ConversationDetailViewAction.BlockSender(
+ MessageIdUiModel(messageId.id), participant.participantAddress, null
+ ) affects listOf(BottomSheet, BlockSenderDialog),
+ ConversationDetailViewAction.BlockSenderConfirmed(
+ MessageIdUiModel(messageId.id), participant.participantAddress
+ ) affects listOf(BlockSenderDialog),
+ ConversationDetailViewAction.BlockSenderDismissed affects listOf(BlockSenderDialog),
ConversationDetailViewAction.MarkMessageAsLegitimate(
MessageId(messageId.id), isPhishing = true
) affects listOf(MarkAsLegitimateDialog),
@@ -401,6 +417,7 @@ private infix fun ConversationDetailOperation.affects(entities: List) =
reducesDeleteDialog = entities.contains(DeleteDialog),
reducesTrashedMessagesBanner = entities.contains(HiddenMessagesBanner),
reducesReportPhishingDialog = entities.contains(ReportPhishingDialog),
+ reducesBlockSenderDialog = entities.contains(BlockSenderDialog),
reducesMarkAsLegitimateDialog = entities.contains(MarkAsLegitimateDialog),
reducesEditScheduleSendDialog = entities.contains(EditScheduleSendDialog)
)
@@ -422,6 +439,7 @@ private data object MessageScroll : Entity
private data object DeleteDialog : Entity
private data object HiddenMessagesBanner : Entity
private data object ReportPhishingDialog : Entity
+private data object BlockSenderDialog : Entity
private data object MarkAsLegitimateDialog : Entity
private data object EditScheduleSendDialog : Entity
diff --git a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelIntegrationTest.kt b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelIntegrationTest.kt
index 24a73aabb3..e7a85d4454 100644
--- a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelIntegrationTest.kt
+++ b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelIntegrationTest.kt
@@ -126,6 +126,7 @@ import ch.protonmail.android.maildetail.presentation.model.MarkAsLegitimateDialo
import ch.protonmail.android.maildetail.presentation.model.MessageIdUiModel
import ch.protonmail.android.maildetail.presentation.model.MoreActionsBottomSheetEntryPoint
import ch.protonmail.android.maildetail.presentation.model.ReportPhishingDialogState
+import ch.protonmail.android.maildetail.presentation.reducer.ConversationBlockSenderDialogReducer
import ch.protonmail.android.maildetail.presentation.reducer.ConversationDeleteDialogReducer
import ch.protonmail.android.maildetail.presentation.reducer.ConversationDetailMessagesReducer
import ch.protonmail.android.maildetail.presentation.reducer.ConversationDetailMetadataReducer
@@ -483,6 +484,7 @@ internal class ConversationDetailViewModelIntegrationTest {
),
deleteDialogReducer = ConversationDeleteDialogReducer(),
reportPhishingDialogReducer = ConversationReportPhishingDialogReducer(),
+ blockSenderDialogReducer = ConversationBlockSenderDialogReducer(),
hiddenMessagesBannerReducer = HiddenMessagesBannerReducer(),
markAsLegitimateDialogReducer = MarkAsLegitimateDialogReducer(),
editScheduledMessageDialogReducer = EditScheduledMessageDialogReducer(),
diff --git a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelTest.kt b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelTest.kt
index 6fdab104da..94ef91c49c 100644
--- a/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelTest.kt
+++ b/mail-detail/presentation/src/test/kotlin/ch/protonmail/android/maildetail/presentation/viewmodel/ConversationDetailViewModelTest.kt
@@ -2043,7 +2043,7 @@ class ConversationDetailViewModelTest {
// When
viewModel.state.test {
initialStateEmitted()
- viewModel.submit(ConversationDetailViewAction.BlockSender(messageIdUiModel, email))
+ viewModel.submit(ConversationDetailViewAction.BlockSenderConfirmed(messageIdUiModel, email))
advanceUntilIdle()
@@ -2053,6 +2053,23 @@ class ConversationDetailViewModelTest {
}
}
+ @Test
+ fun `do not call block sender when dismissed`() = runTest {
+ // Given
+ viewModel.state.test {
+ initialStateEmitted()
+
+ // When
+ viewModel.submit(ConversationDetailViewAction.BlockSenderDismissed)
+
+ advanceUntilIdle()
+
+ // Then
+ coVerify(exactly = 0) { blockSender(userId, any()) }
+ cancelAndIgnoreRemainingEvents()
+ }
+ }
+
@Suppress("LongMethod")
private fun setupCollapsedToExpandMessagesState(
withUnreadMessage: Boolean = false
diff --git a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/model/ContactActionUiModel.kt b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/model/ContactActionUiModel.kt
index cb4e1abcfe..150a224f1a 100644
--- a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/model/ContactActionUiModel.kt
+++ b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/model/ContactActionUiModel.kt
@@ -20,6 +20,7 @@ package ch.protonmail.android.mailmessage.presentation.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
+import ch.protonmail.android.mailcontact.domain.model.ContactId
import ch.protonmail.android.mailmessage.domain.model.Participant
import ch.protonmail.android.mailmessage.presentation.R
@@ -53,7 +54,7 @@ sealed class ContactActionUiModel(
descriptionRes = R.string.contact_actions_add_contact_description
)
- data class BlockContact(val participant: Participant) : ContactActionUiModel(
+ data class BlockContact(val participant: Participant, val contactId: ContactId) : ContactActionUiModel(
iconRes = R.drawable.ic_proton_circle_slash,
textRes = R.string.contact_actions_block_contact,
descriptionRes = R.string.contact_actions_block_contact_description
diff --git a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducer.kt b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducer.kt
index 7c63329730..0c2f7a5e4f 100644
--- a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducer.kt
+++ b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducer.kt
@@ -54,11 +54,18 @@ class ContactActionsBottomSheetReducer @Inject constructor() {
emptyList()
} else {
buildList {
- val action = when {
- contactId == null && isSenderBlocked -> ContactActionUiModel.UnblockAddress(participant)
- contactId == null && !isSenderBlocked -> ContactActionUiModel.BlockAddress(participant)
- contactId != null && isSenderBlocked -> ContactActionUiModel.UnblockContact(participant)
- else -> ContactActionUiModel.BlockContact(participant)
+ val action = if (contactId == null) {
+ if (isSenderBlocked) {
+ ContactActionUiModel.UnblockAddress(participant)
+ } else {
+ ContactActionUiModel.BlockAddress(participant)
+ }
+ } else {
+ if (isSenderBlocked) {
+ ContactActionUiModel.UnblockContact(participant)
+ } else {
+ ContactActionUiModel.BlockContact(participant, contactId)
+ }
}
add(action)
}
diff --git a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/ui/bottomsheet/ContactActionsBottomSheetContent.kt b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/ui/bottomsheet/ContactActionsBottomSheetContent.kt
index 905968e12e..a9fecfae64 100644
--- a/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/ui/bottomsheet/ContactActionsBottomSheetContent.kt
+++ b/mail-message/presentation/src/main/kotlin/ch/protonmail/android/mailmessage/presentation/ui/bottomsheet/ContactActionsBottomSheetContent.kt
@@ -42,6 +42,7 @@ import ch.protonmail.android.design.compose.theme.titleLargeNorm
import ch.protonmail.android.mailcommon.presentation.compose.Avatar
import ch.protonmail.android.mailcommon.presentation.compose.MailDimens
import ch.protonmail.android.mailcommon.presentation.model.AvatarUiModel
+import ch.protonmail.android.mailcontact.domain.model.ContactId
import ch.protonmail.android.mailmessage.domain.model.MessageId
import ch.protonmail.android.mailmessage.domain.model.Participant
import ch.protonmail.android.mailmessage.presentation.model.ContactActionUiModel
@@ -133,9 +134,13 @@ private fun callbackForActions(
is ContactActionUiModel.CopyAddress -> actions.onCopyAddressClicked(action.address)
is ContactActionUiModel.CopyName -> actions.onCopyNameClicked(action.name)
is ContactActionUiModel.NewMessage -> actions.onNewMessageClicked(action.participant)
- is ContactActionUiModel.BlockContact -> actions.onBlockClicked(action.participant, sheetOrigin.getMessageId())
+ is ContactActionUiModel.BlockContact -> actions.onBlockClicked(
+ action.participant,
+ sheetOrigin.getMessageId(), action.contactId
+ )
+
is ContactActionUiModel.UnblockContact -> actions.onUnblockClicked(action.participant, sheetOrigin.getMessageId())
- is ContactActionUiModel.BlockAddress -> actions.onBlockClicked(action.participant, sheetOrigin.getMessageId())
+ is ContactActionUiModel.BlockAddress -> actions.onBlockClicked(action.participant, sheetOrigin.getMessageId(), null)
is ContactActionUiModel.UnblockAddress -> actions.onUnblockClicked(action.participant, sheetOrigin.getMessageId())
}
@@ -194,7 +199,7 @@ object ContactActionsBottomSheetContent {
val onCopyNameClicked: (name: String) -> Unit,
val onNewMessageClicked: (participant: Participant) -> Unit,
val onAddContactClicked: (participant: Participant) -> Unit,
- val onBlockClicked: (participant: Participant, messageId: MessageId?) -> Unit,
+ val onBlockClicked: (participant: Participant, messageId: MessageId?, contactId: ContactId?) -> Unit,
val onUnblockClicked: (participant: Participant, messageId: MessageId?) -> Unit
)
}
@@ -228,7 +233,7 @@ fun ContactActionsBottomSheetContentPreview() {
onCopyNameClicked = {},
onNewMessageClicked = {},
onAddContactClicked = {},
- onBlockClicked = { _, _ -> },
+ onBlockClicked = { _, _, _ -> },
onUnblockClicked = { _, _ -> }
)
)
diff --git a/mail-message/presentation/src/main/res/values/strings.xml b/mail-message/presentation/src/main/res/values/strings.xml
index bce0ef565b..ef0221d242 100644
--- a/mail-message/presentation/src/main/res/values/strings.xml
+++ b/mail-message/presentation/src/main/res/values/strings.xml
@@ -16,7 +16,7 @@
~ along with Proton Mail. If not, see .
-->
-
+
- %d Selected
- %d Selected
@@ -73,6 +73,9 @@
Save this recipient as a contact
Block this contact
Block this contact
+ Emails from %1$s will no longer be delivered and will be permanently deleted. You can manage blocked email addresses in the settings.
+ Block
+ Cancel
Block this contact
Block this contact
Block this address
diff --git a/mail-message/presentation/src/test/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducerTest.kt b/mail-message/presentation/src/test/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducerTest.kt
index 19ee443c24..7cee4f609a 100644
--- a/mail-message/presentation/src/test/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducerTest.kt
+++ b/mail-message/presentation/src/test/kotlin/ch/protonmail/android/mailmessage/presentation/reducer/ContactActionsBottomSheetReducerTest.kt
@@ -20,11 +20,13 @@ package ch.protonmail.android.mailmessage.presentation.reducer
import ch.protonmail.android.mailcommon.presentation.model.BottomSheetState
import ch.protonmail.android.mailcommon.presentation.sample.ParticipantAvatarSample
+import ch.protonmail.android.mailcontact.domain.model.ContactId
import ch.protonmail.android.mailmessage.domain.model.MessageId
import ch.protonmail.android.mailmessage.domain.model.Participant
+import ch.protonmail.android.mailmessage.presentation.model.ContactActionUiModel
import ch.protonmail.android.mailmessage.presentation.model.bottomsheet.ContactActionsBottomSheetState
-import ch.protonmail.android.testdata.contact.ContactActionsGroupsSample
import ch.protonmail.android.testdata.contact.ContactSample
+import kotlinx.collections.immutable.toImmutableList
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -61,6 +63,7 @@ internal class ContactActionsBottomSheetReducerTest(
private val sampleOrigin =
ContactActionsBottomSheetState.Origin.MessageDetails(MessageId("msg-1"))
+
private val transitionsFromLoadingState = listOf(
TestInput(
currentState = BottomSheetState(ContactActionsBottomSheetState.Loading),
@@ -76,7 +79,12 @@ internal class ContactActionsBottomSheetReducerTest(
contentState = ContactActionsBottomSheetState.Data(
participant = sampleParticipant,
avatarUiModel = sampleAvatar,
- actions = ContactActionsGroupsSample.defaultForContact(sampleParticipant, false),
+ actions = expectedGroupsFor(
+ participant = sampleParticipant,
+ contactId = sampleContact.id,
+ isSenderBlocked = false,
+ isPrimaryUserAddress = false
+ ),
origin = sampleOrigin
)
)
@@ -95,7 +103,12 @@ internal class ContactActionsBottomSheetReducerTest(
contentState = ContactActionsBottomSheetState.Data(
participant = sampleParticipant,
avatarUiModel = sampleAvatar,
- actions = ContactActionsGroupsSample.defaultForContact(sampleParticipant, true),
+ actions = expectedGroupsFor(
+ participant = sampleParticipant,
+ contactId = sampleContact.id,
+ isSenderBlocked = true,
+ isPrimaryUserAddress = false
+ ),
origin = sampleOrigin
)
)
@@ -114,7 +127,12 @@ internal class ContactActionsBottomSheetReducerTest(
contentState = ContactActionsBottomSheetState.Data(
participant = sampleParticipant,
avatarUiModel = sampleAvatar,
- actions = ContactActionsGroupsSample.defaultForNoContact(sampleParticipant, true),
+ actions = expectedGroupsFor(
+ participant = sampleParticipant,
+ contactId = null,
+ isSenderBlocked = true,
+ isPrimaryUserAddress = false
+ ),
origin = sampleOrigin
)
)
@@ -133,7 +151,12 @@ internal class ContactActionsBottomSheetReducerTest(
contentState = ContactActionsBottomSheetState.Data(
participant = sampleParticipant,
avatarUiModel = sampleAvatar,
- actions = ContactActionsGroupsSample.defaultForNoContact(sampleParticipant, false),
+ actions = expectedGroupsFor(
+ participant = sampleParticipant,
+ contactId = null,
+ isSenderBlocked = false,
+ isPrimaryUserAddress = false
+ ),
origin = sampleOrigin
)
)
@@ -152,8 +175,11 @@ internal class ContactActionsBottomSheetReducerTest(
contentState = ContactActionsBottomSheetState.Data(
participant = primaryUserParticipant,
avatarUiModel = sampleAvatar,
- actions = ContactActionsGroupsSample.defaultForNoContact(
- primaryUserParticipant, isAddressBlocked = false, isPrimaryUserAddress = true
+ actions = expectedGroupsFor(
+ participant = primaryUserParticipant,
+ contactId = null,
+ isSenderBlocked = false,
+ isPrimaryUserAddress = true
),
origin = sampleOrigin
)
@@ -161,6 +187,44 @@ internal class ContactActionsBottomSheetReducerTest(
)
)
+ private fun expectedGroupsFor(
+ participant: Participant,
+ contactId: ContactId?,
+ isSenderBlocked: Boolean,
+ isPrimaryUserAddress: Boolean
+ ): ContactActionsBottomSheetState.ContactActionsGroups {
+ val first = listOf(
+ ContactActionUiModel.NewMessage(participant)
+ ).toImmutableList()
+
+ val second = listOf(
+ ContactActionUiModel.CopyAddress(participant.address),
+ ContactActionUiModel.CopyName(participant.name)
+ ).toImmutableList()
+
+ val third = if (isPrimaryUserAddress) {
+ emptyList()
+ } else {
+ listOf(
+ when {
+ contactId == null && !isSenderBlocked -> ContactActionUiModel.BlockAddress(participant)
+ contactId == null && isSenderBlocked -> ContactActionUiModel.UnblockAddress(participant)
+ contactId != null && !isSenderBlocked -> ContactActionUiModel.BlockContact(
+ participant, contactId
+ )
+
+ else -> ContactActionUiModel.UnblockContact(participant)
+ }
+ )
+ }.toImmutableList()
+
+ return ContactActionsBottomSheetState.ContactActionsGroups(
+ firstGroup = first,
+ secondGroup = second,
+ thirdGroup = third
+ )
+ }
+
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun data() = transitionsFromLoadingState
diff --git a/test/test-data/src/main/kotlin/ch/protonmail/android/testdata/contact/ContactActionsGroupsSample.kt b/test/test-data/src/main/kotlin/ch/protonmail/android/testdata/contact/ContactActionsGroupsSample.kt
index f45da9dbb6..373caa8d31 100644
--- a/test/test-data/src/main/kotlin/ch/protonmail/android/testdata/contact/ContactActionsGroupsSample.kt
+++ b/test/test-data/src/main/kotlin/ch/protonmail/android/testdata/contact/ContactActionsGroupsSample.kt
@@ -45,7 +45,7 @@ object ContactActionsGroupsSample {
if (isContactBlocked) {
add(ContactActionUiModel.UnblockContact(participant))
} else {
- add(ContactActionUiModel.BlockContact(participant))
+ add(ContactActionUiModel.BlockContact(participant, ContactIdSample.Doe))
}
}.toImmutableList()