Do not instantiate observers to resolve message/conversation subject

When displaying the "More" actions bottomsheet, we show the subject at the top of the component. The information is currently retrieved by observing and capturing the first data event emitted by observeMessage/observeConversation, which instantiate a whole watcher and subsequent callbacks.

ET-5458
This commit is contained in:
Niccolò Forlini
2025-11-25 09:35:47 +00:00
parent 79ec99640c
commit 41fbdbd9ab
13 changed files with 123 additions and 174 deletions
@@ -94,7 +94,8 @@ class MessageDetailHeaderUiModelMapper @Inject constructor(
messageIdUiModel = toMessageUiModel(message.messageId),
themeOverride = viewModePreference.toThemeOverride(),
shouldShowQuickReply = message.isReplyAllowed,
hasMoreActions = hasMoreActionsEnabled
hasMoreActions = hasMoreActionsEnabled,
subject = message.subject
)
}
@@ -32,6 +32,7 @@ data class MessageDetailHeaderUiModel(
val avatar: AvatarUiModel,
val avatarImage: AvatarImageUiModel,
val sender: ParticipantUiModel,
val subject: String,
val shouldShowTrackerProtectionIcon: Boolean,
val shouldShowAttachmentIcon: Boolean,
val shouldShowStar: Boolean,
@@ -93,7 +93,8 @@ object MessageDetailHeaderPreviewData {
messageIdUiModel = MessageIdUiModel("string"),
themeOverride = null,
shouldShowQuickReply = true,
hasMoreActions = true
hasMoreActions = true,
subject = "A subject"
)
val WithLabels = WithoutLabels.copy(
@@ -65,6 +65,7 @@ object MessageDetailHeaderUiModelSample {
messageIdUiModel = MessageIdUiModel("id"),
themeOverride = null,
shouldShowQuickReply = true,
hasMoreActions = true
hasMoreActions = true,
subject = "A subject"
)
}
@@ -20,71 +20,65 @@ package ch.protonmail.android.maildetail.presentation.usecase
import ch.protonmail.android.mailcommon.domain.model.Action
import ch.protonmail.android.mailcommon.domain.model.ConversationId
import ch.protonmail.android.mailconversation.domain.entity.ConversationDetailEntryPoint
import ch.protonmail.android.mailconversation.domain.usecase.GetConversationAvailableActions
import ch.protonmail.android.mailconversation.domain.usecase.ObserveConversation
import ch.protonmail.android.maildetail.presentation.model.MoreActionsBottomSheetEntryPoint
import ch.protonmail.android.maillabel.domain.model.LabelId
import ch.protonmail.android.mailmessage.domain.model.MessageId
import ch.protonmail.android.mailmessage.domain.model.MessageThemeOptions
import ch.protonmail.android.mailmessage.domain.usecase.GetMessageAvailableActions
import ch.protonmail.android.mailmessage.domain.usecase.ObserveMessage
import ch.protonmail.android.mailmessage.presentation.model.bottomsheet.DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent
import kotlinx.coroutines.flow.firstOrNull
import me.proton.core.domain.entity.UserId
import javax.inject.Inject
class GetMoreActionsBottomSheetData @Inject constructor(
private val getMessageAvailableActions: GetMessageAvailableActions,
private val getConversationAvailableActions: GetConversationAvailableActions,
private val observeMessage: ObserveMessage,
private val observeConversation: ObserveConversation
private val getConversationAvailableActions: GetConversationAvailableActions
) {
suspend fun forMessage(
userId: UserId,
labelId: LabelId,
messageId: MessageId,
messageThemeOptions: MessageThemeOptions,
entryPoint: MoreActionsBottomSheetEntryPoint
internal suspend fun forMessage(
payload: MoreMessageActionsBottomSheetDataPayload
): DetailMoreActionsBottomSheetEvent.DataLoaded? = getMessageAvailableActions(
userId, labelId, messageId, messageThemeOptions
payload.userId, payload.labelId, payload.messageId, payload.messageThemeOptions
).map { availableActions ->
val message = observeMessage(userId, messageId).firstOrNull()?.getOrNull()
?: return null
val requestIsFromBottomBar = entryPoint is MoreActionsBottomSheetEntryPoint.BottomBar
val requestIsFromBottomBar = payload.entryPoint is MoreActionsBottomSheetEntryPoint.BottomBar
return DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = message.sender.name,
messageSubject = message.subject,
messageIdInConversation = message.messageId.id,
messageSubject = payload.subject,
messageIdInConversation = payload.messageId.id,
availableActions = availableActions,
customizeToolbarAction = if (requestIsFromBottomBar) Action.CustomizeToolbar else null
)
}.getOrNull()
suspend fun forConversation(
userId: UserId,
labelId: LabelId,
conversationId: ConversationId,
entryPoint: ConversationDetailEntryPoint,
showAllMessages: Boolean
): DetailMoreActionsBottomSheetEvent.DataLoaded? =
getConversationAvailableActions(userId, labelId, conversationId).map { availableActions ->
val conversation = observeConversation(userId, conversationId, labelId, entryPoint, showAllMessages)
.firstOrNull()
?.getOrNull()
?: return null
return DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = conversation.senders.first().name,
messageSubject = conversation.subject,
messageIdInConversation = null,
availableActions = availableActions,
customizeToolbarAction = Action.CustomizeToolbar
)
}.getOrNull()
internal suspend fun forConversation(
payload: MoreConversationActionsBottomSheetDataPayload
): DetailMoreActionsBottomSheetEvent.DataLoaded? = getConversationAvailableActions(
payload.userId,
payload.labelId,
payload.conversationId
).map { availableActions ->
return DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSubject = payload.subject,
messageIdInConversation = null,
availableActions = availableActions,
customizeToolbarAction = Action.CustomizeToolbar
)
}.getOrNull()
}
internal data class MoreMessageActionsBottomSheetDataPayload(
val userId: UserId,
val labelId: LabelId,
val messageId: MessageId,
val messageThemeOptions: MessageThemeOptions,
val entryPoint: MoreActionsBottomSheetEntryPoint,
val subject: String
)
internal data class MoreConversationActionsBottomSheetDataPayload(
val userId: UserId,
val labelId: LabelId,
val conversationId: ConversationId,
val subject: String
)
@@ -96,6 +96,8 @@ import ch.protonmail.android.maildetail.presentation.reducer.ConversationDetailR
import ch.protonmail.android.maildetail.presentation.usecase.GetMessagesInSameExclusiveLocation
import ch.protonmail.android.maildetail.presentation.usecase.GetMoreActionsBottomSheetData
import ch.protonmail.android.maildetail.presentation.usecase.LoadImageAvoidDuplicatedExecution
import ch.protonmail.android.maildetail.presentation.usecase.MoreConversationActionsBottomSheetDataPayload
import ch.protonmail.android.maildetail.presentation.usecase.MoreMessageActionsBottomSheetDataPayload
import ch.protonmail.android.maildetail.presentation.usecase.ObservePrimaryUserAddress
import ch.protonmail.android.maildetail.presentation.usecase.print.PrintConfiguration
import ch.protonmail.android.maildetail.presentation.usecase.print.PrintMessage
@@ -535,6 +537,7 @@ class ConversationDetailViewModel @AssistedInject constructor(
emitNewStateFrom(ConversationDetailEvent.ErrorLoadingImageProxyFailed(messageId))
null
}
is AttachmentDataError.Other -> null
}
},
@@ -1041,14 +1044,16 @@ class ConversationDetailViewModel @AssistedInject constructor(
val userId = primaryUserId.first()
val labelId = openedFromLocation
val moreActions = getMoreActionsBottomSheetData.forMessage(
val bottomSheetDataPayload = MoreMessageActionsBottomSheetDataPayload(
userId,
labelId,
initialEvent.messageId,
initialEvent.themeOptions,
initialEvent.entryPoint
initialEvent.entryPoint,
resolveSubject() ?: ""
)
?: return
val moreActions = getMoreActionsBottomSheetData.forMessage(bottomSheetDataPayload) ?: return
emitNewStateFrom(ConversationDetailEvent.ConversationBottomSheetEvent(moreActions))
}
@@ -1076,14 +1081,15 @@ class ConversationDetailViewModel @AssistedInject constructor(
val userId = primaryUserId.first()
val labelId = openedFromLocation
val moreActions = getMoreActionsBottomSheetData.forConversation(
val bottomSheetDataPayload = MoreConversationActionsBottomSheetDataPayload(
userId,
labelId,
conversationId,
conversationEntryPoint,
showAllMessages.value
) ?: return
resolveSubject() ?: ""
)
val moreActions = getMoreActionsBottomSheetData.forConversation(bottomSheetDataPayload) ?: return
emitNewStateFrom(ConversationDetailEvent.ConversationBottomSheetEvent(moreActions))
}
@@ -1729,6 +1735,12 @@ class ConversationDetailViewModel @AssistedInject constructor(
return label == SystemLabelId.AllMail
}
private fun resolveSubject(): String? {
return (state.value.conversationState as? ConversationDetailMetadataState.Data)
?.conversationUiModel
?.subject
}
private suspend fun withUserId(block: suspend (userId: UserId) -> Either<*, *>) {
val userId = primaryUserId.first()
block(userId)
@@ -106,7 +106,8 @@ class MessageDetailHeaderUiModelMapperTest {
messageIdUiModel = MessageIdUiModel(message.messageId.id),
themeOverride = null,
shouldShowQuickReply = true,
hasMoreActions = true
hasMoreActions = true,
subject = "Subject"
)
private val colorMapper: ColorMapper = mockk {
@@ -165,6 +166,9 @@ class MessageDetailHeaderUiModelMapperTest {
@Test
fun `map to ui model returns a correct model`() = runTest {
// Given
val expectedResult = expectedResult.copy(subject = message.subject)
// When
val result = messageDetailHeaderUiModelMapper.toUiModel(
message = message,
@@ -184,7 +188,7 @@ class MessageDetailHeaderUiModelMapperTest {
numAttachments = 1,
attachmentCount = AttachmentCount(1)
)
val expectedResult = expectedResult.copy(shouldShowAttachmentIcon = false)
val expectedResult = expectedResult.copy(shouldShowAttachmentIcon = false, subject = message.subject)
// When
val result = messageDetailHeaderUiModelMapper.toUiModel(
message = message,
@@ -201,7 +205,7 @@ class MessageDetailHeaderUiModelMapperTest {
fun `when the message is not starred, don't show star icon`() = runTest {
// Given
val message = message.copy(isStarred = false)
val expectedResult = expectedResult.copy(shouldShowStar = false)
val expectedResult = expectedResult.copy(shouldShowStar = false, subject = message.subject)
// When
val result = messageDetailHeaderUiModelMapper.toUiModel(
message = message,
@@ -223,6 +227,7 @@ class MessageDetailHeaderUiModelMapperTest {
)
val expectedResult = expectedResult.copy(
shouldShowUndisclosedRecipients = true,
subject = message.subject,
allRecipients = emptyList<ParticipantUiModel>().toImmutableList(),
toRecipients = emptyList<ParticipantUiModel>().toImmutableList(),
ccRecipients = emptyList<ParticipantUiModel>().toImmutableList()
@@ -162,7 +162,6 @@ internal class BottomSheetReducerTest(
TestInput(
currentState = BottomSheetState(null, Effect.empty()),
operation = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = "Sender",
messageSubject = "Subject",
messageIdInConversation = "messageId",
availableActions = AvailableActionsTestData.replyActionsOnly,
@@ -6,23 +6,19 @@ import ch.protonmail.android.mailcommon.domain.model.Action
import ch.protonmail.android.mailcommon.domain.model.DataError
import ch.protonmail.android.mailcommon.domain.sample.ConversationIdSample
import ch.protonmail.android.mailcommon.domain.sample.UserIdSample
import ch.protonmail.android.mailconversation.domain.entity.ConversationDetailEntryPoint
import ch.protonmail.android.mailconversation.domain.sample.ConversationSample
import ch.protonmail.android.mailconversation.domain.usecase.GetConversationAvailableActions
import ch.protonmail.android.mailconversation.domain.usecase.ObserveConversation
import ch.protonmail.android.maildetail.presentation.model.MoreActionsBottomSheetEntryPoint
import ch.protonmail.android.maillabel.domain.model.SystemLabelId
import ch.protonmail.android.mailmessage.domain.sample.MessageIdSample
import ch.protonmail.android.mailmessage.domain.sample.MessageSample
import ch.protonmail.android.mailmessage.domain.usecase.GetMessageAvailableActions
import ch.protonmail.android.mailmessage.domain.usecase.ObserveMessage
import ch.protonmail.android.mailmessage.presentation.model.bottomsheet.DetailMoreActionsBottomSheetState
import ch.protonmail.android.testdata.action.AvailableActionsTestData
import ch.protonmail.android.testdata.conversation.ConversationTestData.conversation
import ch.protonmail.android.testdata.message.MessageThemeOptionsTestData
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -30,16 +26,12 @@ import kotlin.test.assertNull
class GetMoreActionsBottomSheetDataTest {
private val observeMessage = mockk<ObserveMessage>()
private val observeConversation = mockk<ObserveConversation>()
private val getConversationAvailableActions = mockk<GetConversationAvailableActions>()
private val getMessageAvailableActions = mockk<GetMessageAvailableActions>()
private val getMoreBottomSheetData = GetMoreActionsBottomSheetData(
getMessageAvailableActions,
getConversationAvailableActions,
observeMessage,
observeConversation
getConversationAvailableActions
)
@Test
@@ -48,27 +40,27 @@ class GetMoreActionsBottomSheetDataTest {
val themeOptions = MessageThemeOptionsTestData.darkOverrideLight
val userId = UserIdSample.Primary
val labelId = SystemLabelId.Archive.labelId
val messageId = MessageIdSample.PlainTextMessage
val messageId = MessageSample.Invoice.messageId
val message = MessageSample.Invoice
val entryPoint = MoreActionsBottomSheetEntryPoint.MessageHeader
val availableActions = AvailableActionsTestData.replyActionsOnly
val payload = MoreMessageActionsBottomSheetDataPayload(
userId = userId,
labelId = labelId,
messageId = messageId,
messageThemeOptions = themeOptions,
entryPoint = MoreActionsBottomSheetEntryPoint.MessageHeader,
subject = message.subject
)
coEvery {
getMessageAvailableActions(userId, labelId, messageId, themeOptions)
} returns availableActions.right()
coEvery { observeMessage(userId, messageId) } returns flowOf(message.right())
// When
val actual = getMoreBottomSheetData.forMessage(
userId,
labelId,
messageId,
themeOptions,
entryPoint
)
val actual = getMoreBottomSheetData.forMessage(payload)
// Then
val expected = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = message.sender.name,
messageSubject = message.subject,
messageIdInConversation = message.messageId.id,
availableActions = availableActions,
@@ -84,27 +76,27 @@ class GetMoreActionsBottomSheetDataTest {
val themeOptions = MessageThemeOptionsTestData.darkOverrideLight
val userId = UserIdSample.Primary
val labelId = SystemLabelId.Archive.labelId
val messageId = MessageIdSample.PlainTextMessage
val message = MessageSample.Invoice
val entryPoint = MoreActionsBottomSheetEntryPoint.BottomBar
val messageId = message.messageId
val availableActions = AvailableActionsTestData.replyActionsOnly
val payload = MoreMessageActionsBottomSheetDataPayload(
userId = userId,
labelId = labelId,
messageId = messageId,
messageThemeOptions = themeOptions,
entryPoint = MoreActionsBottomSheetEntryPoint.BottomBar,
subject = message.subject
)
coEvery {
getMessageAvailableActions(userId, labelId, messageId, themeOptions)
} returns availableActions.right()
coEvery { observeMessage(userId, messageId) } returns flowOf(message.right())
// When
val actual = getMoreBottomSheetData.forMessage(
userId,
labelId,
messageId,
themeOptions,
entryPoint
)
val actual = getMoreBottomSheetData.forMessage(payload)
// Then
val expected = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = message.sender.name,
messageSubject = message.subject,
messageIdInConversation = message.messageId.id,
availableActions = availableActions,
@@ -122,13 +114,22 @@ class GetMoreActionsBottomSheetDataTest {
val messageId = MessageIdSample.PlainTextMessage
val message = MessageSample.Invoice
val entryPoint = MoreActionsBottomSheetEntryPoint.MessageHeader
val payload = MoreMessageActionsBottomSheetDataPayload(
userId = userId,
labelId = labelId,
messageId = messageId,
messageThemeOptions = themeOptions,
entryPoint = entryPoint,
subject = message.subject
)
coEvery {
getMessageAvailableActions(userId, labelId, messageId, themeOptions)
} returns DataError.Local.NoDataCached.left()
coEvery { observeMessage(userId, messageId) } returns flowOf(message.right())
// When
val actual = getMoreBottomSheetData.forMessage(userId, labelId, messageId, themeOptions, entryPoint)
val actual = getMoreBottomSheetData.forMessage(payload)
// Then
assertNull(actual)
@@ -142,27 +143,22 @@ class GetMoreActionsBottomSheetDataTest {
val conversationId = ConversationIdSample.WeatherForecast
val conversation = ConversationSample.WeatherForecast
val availableActions = AvailableActionsTestData.replyActionsOnly
val entryPoint = ConversationDetailEntryPoint.Mailbox
val showAll = false
coEvery {
getConversationAvailableActions(userId, labelId, conversationId)
} returns availableActions.right()
coEvery {
observeConversation(
userId,
conversationId,
labelId,
entryPoint,
showAll
)
} returns flowOf(conversation.right())
val payload = MoreConversationActionsBottomSheetDataPayload(
userId = userId,
labelId = labelId,
subject = conversation.subject,
conversationId = conversationId
)
// When
val actual = getMoreBottomSheetData.forConversation(userId, labelId, conversationId, entryPoint, showAll)
val actual = getMoreBottomSheetData.forConversation(payload)
// Then
val expected = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = conversation.senders.first().name,
messageSubject = conversation.subject,
messageIdInConversation = null,
availableActions = availableActions,
@@ -177,23 +173,19 @@ class GetMoreActionsBottomSheetDataTest {
val userId = UserIdSample.Primary
val labelId = SystemLabelId.Archive.labelId
val conversationId = ConversationIdSample.WeatherForecast
val entryPoint = ConversationDetailEntryPoint.Mailbox
val showAll = false
coEvery {
getConversationAvailableActions(userId, labelId, conversationId)
} returns DataError.Local.NoDataCached.left()
coEvery {
observeConversation(
userId,
conversationId,
labelId,
entryPoint,
showAll
)
} returns flowOf(conversation.right())
val payload = MoreConversationActionsBottomSheetDataPayload(
userId = userId,
labelId = labelId,
subject = conversation.subject,
conversationId = conversationId
)
// When
val actual = getMoreBottomSheetData.forConversation(userId, labelId, conversationId, entryPoint, showAll)
val actual = getMoreBottomSheetData.forConversation(payload)
// Then
assertNull(actual)
@@ -63,15 +63,12 @@ import ch.protonmail.android.mailcommon.presentation.sample.ParticipantAvatarSam
import ch.protonmail.android.mailcommon.presentation.ui.delete.DeleteDialogState
import ch.protonmail.android.mailcommon.presentation.usecase.FormatExtendedTime
import ch.protonmail.android.mailcommon.presentation.usecase.FormatShortTime
import ch.protonmail.android.mailcontact.domain.model.ContactMetadata
import ch.protonmail.android.mailcontact.domain.usecase.FindContactByEmail
import ch.protonmail.android.mailcontact.domain.usecase.ObserveContacts
import ch.protonmail.android.mailconversation.domain.entity.ConversationDetailEntryPoint
import ch.protonmail.android.mailconversation.domain.entity.ConversationWithMessages
import ch.protonmail.android.mailconversation.domain.sample.ConversationSample
import ch.protonmail.android.mailconversation.domain.usecase.DeleteConversations
import ch.protonmail.android.mailconversation.domain.usecase.GetConversationAvailableActions
import ch.protonmail.android.mailconversation.domain.usecase.ObserveConversation
import ch.protonmail.android.mailconversation.domain.usecase.ObserveConversationMessages
import ch.protonmail.android.mailconversation.domain.usecase.ObserveConversationWithMessages
import ch.protonmail.android.mailconversation.domain.usecase.StarConversations
@@ -247,16 +244,6 @@ internal class ConversationDetailViewModelIntegrationTest {
private val showAllMessages = false
// region mock observe use cases
private val observeContacts: ObserveContacts = mockk {
coEvery {
this@mockk(userId = UserIdSample.Primary)
} returns flowOf(emptyList<ContactMetadata.Contact>().right())
}
private val observeConversation = mockk<ObserveConversation> {
coEvery { this@mockk(UserIdSample.Primary, ConversationIdSample.WeatherForecast, any(), any(), any()) } returns
flowOf(ConversationSample.WeatherForecast.right())
}
private val observeConversationMessages = mockk<ObserveConversationMessages> {
coEvery { this@mockk(UserIdSample.Primary, ConversationIdSample.WeatherForecast, any(), any(), any()) } returns
@@ -391,9 +378,7 @@ internal class ConversationDetailViewModelIntegrationTest {
private val attachmentGroupUiModelMapper = AttachmentGroupUiModelMapper(attachmentMetadataUiModelMapper)
private val getMoreActionsBottomSheetData = GetMoreActionsBottomSheetData(
getMessageAvailableActions,
getConversationAvailableActions,
observeMessage,
observeConversation
getConversationAvailableActions
)
private val getMessagesInSameExclusiveLocation = mockk<GetMessagesInSameExclusiveLocation>()
@@ -1384,41 +1369,6 @@ internal class ConversationDetailViewModelIntegrationTest {
}
}
@Test
fun `verify no bottom sheet data is emitted when more actions bottom sheet is requested and loading fails`() =
runTest {
// Given
val messageId = MessageId("messageId")
val labelId = SystemLabelId.Archive.labelId
val themeOptions = MessageThemeOptionsTestData.darkNoOverride
coEvery {
observeMessage(
userId = userId,
messageId = messageId
)
} returns flowOf(DataError.Local.NoDataCached.left())
coEvery {
getMessageAvailableActions(userId, labelId, messageId, themeOptions)
} returns AvailableActionsTestData.replyActionsOnly.right()
// When
val viewModel = buildConversationDetailViewModel()
viewModel.state.test {
viewModel.submit(
ConversationDetailViewAction.RequestMessageMoreActionsBottomSheet(
messageId,
themeOptions,
MoreActionsBottomSheetEntryPoint.BottomBar
)
)
advanceUntilIdle()
// Then
assertNull(lastEmittedItem().bottomSheetState?.contentState)
}
}
@Test
fun `when user clicks report phishing then confirm dialog is shown`() = runTest {
// Given
@@ -116,7 +116,6 @@ sealed interface DetailMoreActionsBottomSheetState : BottomSheetContentState {
sealed interface DetailMoreActionsBottomSheetOperation : BottomSheetOperation
sealed interface DetailMoreActionsBottomSheetEvent : DetailMoreActionsBottomSheetOperation {
data class DataLoaded(
val messageSender: String,
val messageSubject: String,
val messageIdInConversation: String?,
val availableActions: AvailableActions,
@@ -68,12 +68,8 @@ internal class DetailMoreActionsBottomSheetReducerTest(
companion object {
private const val ExpectedSender = "Sender"
private const val ExpectedSubject = "Subject"
private const val ExpectedMessageId = "messageId"
private const val SingleParticipantCount = 1
private const val MultipleParticipantsCount = 10
private val expectedUiModel = DetailMoreActionsBottomSheetState.DetailDataUiModel(
headerSubjectText = TextUiModel(ExpectedSubject),
messageIdInConversation = ExpectedMessageId
@@ -82,7 +78,6 @@ internal class DetailMoreActionsBottomSheetReducerTest(
TestInput(
currentState = BottomSheetState(DetailMoreActionsBottomSheetState.Loading),
operation = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = ExpectedSender,
messageSubject = ExpectedSubject,
messageIdInConversation = ExpectedMessageId,
availableActions = AvailableActionsTestData.replyReportPhishing,
@@ -102,7 +97,6 @@ internal class DetailMoreActionsBottomSheetReducerTest(
TestInput(
currentState = BottomSheetState(DetailMoreActionsBottomSheetState.Loading),
operation = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = ExpectedSender,
messageSubject = ExpectedSubject,
messageIdInConversation = ExpectedMessageId,
availableActions = AvailableActionsTestData.forwardReportPhishingActions,
@@ -122,7 +116,6 @@ internal class DetailMoreActionsBottomSheetReducerTest(
TestInput(
currentState = BottomSheetState(DetailMoreActionsBottomSheetState.Loading),
operation = DetailMoreActionsBottomSheetState.DetailMoreActionsBottomSheetEvent.DataLoaded(
messageSender = ExpectedSender,
messageSubject = ExpectedSubject,
messageIdInConversation = ExpectedMessageId,
availableActions = AvailableActionsTestData.fullAvailableActions,
@@ -87,7 +87,8 @@ object MessageDetailHeaderUiModelTestData {
messageIdUiModel = MessageIdUiModel("id"),
themeOverride = null,
shouldShowQuickReply = true,
hasMoreActions = true
hasMoreActions = true,
subject = "A subject"
)
fun buildParticipant(