Add draft mime type to domain and ui models and on state when draft ready

ET-4304
This commit is contained in:
Marino Meneghel
2025-08-14 15:01:43 +02:00
committed by Niccolò Forlini
parent 25d330e354
commit 5da0c09d63
11 changed files with 51 additions and 4 deletions
@@ -16,6 +16,8 @@
* along with Proton Mail. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("TooManyFunctions")
package ch.protonmail.android.composer.data.mapper
import ch.protonmail.android.composer.data.local.LocalDraft
@@ -26,6 +28,7 @@ import ch.protonmail.android.composer.data.wrapper.DraftWrapperWithSyncStatus
import ch.protonmail.android.mailcommon.data.mapper.LocalAttachmentData
import ch.protonmail.android.mailcommon.data.mapper.LocalComposerRecipient
import ch.protonmail.android.mailcommon.data.mapper.LocalDraftSendResult
import ch.protonmail.android.mailcommon.data.mapper.LocalMimeType
import ch.protonmail.android.mailcommon.data.mapper.toDataError
import ch.protonmail.android.mailcommon.domain.annotation.MissingRustApi
import ch.protonmail.android.mailcommon.domain.model.DataError
@@ -33,10 +36,11 @@ import ch.protonmail.android.mailcomposer.domain.model.ChangeSenderError
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftFieldsWithSyncStatus
import ch.protonmail.android.mailcomposer.domain.model.MessagePassword
import ch.protonmail.android.mailcomposer.domain.model.MessagePasswordError
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.MessageExpirationError
import ch.protonmail.android.mailcomposer.domain.model.MessageExpirationTime
import ch.protonmail.android.mailcomposer.domain.model.MessagePassword
import ch.protonmail.android.mailcomposer.domain.model.MessagePasswordError
import ch.protonmail.android.mailcomposer.domain.model.MessageSendingStatus
import ch.protonmail.android.mailcomposer.domain.model.OpenDraftError
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
@@ -79,6 +83,7 @@ import uniffi.proton_mail_uniffi.DraftSenderAddressChangeError
import uniffi.proton_mail_uniffi.DraftSenderAddressChangeErrorReason
import uniffi.proton_mail_uniffi.DraftSenderAddressList
import uniffi.proton_mail_uniffi.DraftSyncStatus
import uniffi.proton_mail_uniffi.MimeType
import uniffi.proton_mail_uniffi.SingleRecipientEntry
import kotlin.time.DurationUnit
import kotlin.time.Instant
@@ -106,6 +111,7 @@ fun LocalDraft.toDraftFields() = DraftFields(
sender = SenderEmail(this.sender),
subject = Subject(this.subject),
body = DraftBody(this.body),
mimeType = this.mimeType.toDraftMimeType(),
recipientsTo = RecipientsTo(this.recipientsTo.toRecipients()),
recipientsCc = RecipientsCc(this.recipientsCc.toRecipients()),
recipientsBcc = RecipientsBcc(this.recipientsBcc.toRecipients())
@@ -394,6 +400,16 @@ private fun DraftAttachmentUploadError.toDataError() = when (this) {
}
}
private fun LocalMimeType.toDraftMimeType() = when (this) {
MimeType.APPLICATION_JSON,
MimeType.APPLICATION_PDF,
MimeType.MESSAGE_RFC822,
MimeType.MULTIPART_MIXED,
MimeType.MULTIPART_RELATED,
MimeType.TEXT_HTML -> DraftMimeType.Html
MimeType.TEXT_PLAIN -> DraftMimeType.PlainText
}
@MissingRustApi
// Hardcoded values in the mapping
@@ -22,6 +22,7 @@ data class DraftFields(
val sender: SenderEmail,
val subject: Subject,
val body: DraftBody,
val mimeType: DraftMimeType,
val recipientsTo: RecipientsTo,
val recipientsCc: RecipientsCc,
val recipientsBcc: RecipientsBcc
@@ -29,6 +29,7 @@ class DraftFieldsTest {
sender = SenderEmail("A sender email"),
subject = Subject("A test subject"),
body = DraftBody("A draft body"),
mimeType = DraftMimeType.Html,
recipientsTo = RecipientsTo(emptyList()),
recipientsCc = RecipientsCc(emptyList()),
recipientsBcc = RecipientsBcc(emptyList())
@@ -21,6 +21,7 @@ package ch.protonmail.android.mailcomposer.presentation.model
import ch.protonmail.android.mailattachments.domain.model.AttachmentId
import ch.protonmail.android.mailcommon.presentation.Effect
import ch.protonmail.android.mailcommon.presentation.model.TextUiModel
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailmessage.domain.model.MessageId
import ch.protonmail.android.mailmessage.domain.model.Participant
import ch.protonmail.android.mailmessage.presentation.model.attachment.AttachmentGroupUiModel
@@ -45,6 +46,7 @@ sealed interface ComposerState {
data class Main(
val sender: SenderUiModel,
val draftType: DraftMimeType,
val senderAddresses: ImmutableList<SenderUiModel>,
val isSubmittable: Boolean,
val loadingType: LoadingType
@@ -54,6 +56,7 @@ sealed interface ComposerState {
fun initial() = Main(
sender = SenderUiModel(""),
draftType = DraftMimeType.Html,
senderAddresses = emptyList<SenderUiModel>().toImmutableList(),
isSubmittable = false,
loadingType = LoadingType.None
@@ -29,7 +29,8 @@ internal sealed interface MainStateModification : ComposerStateModification<Comp
data class OnDraftReady(val draftUiModel: DraftUiModel) : MainStateModification {
override fun apply(state: ComposerState.Main): ComposerState.Main = state.copy(
sender = SenderUiModel(draftUiModel.draftFields.sender.value)
sender = SenderUiModel(draftUiModel.draftFields.sender.value),
draftType = draftUiModel.draftFields.mimeType
)
}
@@ -42,6 +42,7 @@ import ch.protonmail.android.mailcomposer.domain.model.ChangeSenderError
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftFieldsWithSyncStatus
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.OpenDraftError
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
@@ -284,6 +285,7 @@ class ComposerViewModel @AssistedInject constructor(
it.sender,
it.subject,
it.body,
currentMimeType(),
RecipientsTo(toParticipants),
RecipientsCc(ccParticipants),
RecipientsBcc(bccParticipants)
@@ -424,6 +426,7 @@ class ComposerViewModel @AssistedInject constructor(
currentSenderEmail(),
subject,
draftBody,
currentMimeType(),
recipientsTo,
recipientsCc,
recipientsBcc
@@ -775,6 +778,7 @@ class ComposerViewModel @AssistedInject constructor(
currentSenderEmail(),
Subject(subjectTextField.text.toString().stripNewLines()),
DraftBody(bodyTextField.text.toString()),
currentMimeType(),
RecipientsTo(toParticipants),
RecipientsCc(ccParticipants),
RecipientsBcc(bccParticipants)
@@ -813,6 +817,8 @@ class ComposerViewModel @AssistedInject constructor(
private fun currentSenderEmail() = SenderEmail(composerStates.value.main.sender.email)
private fun currentMimeType(): DraftMimeType = composerStates.value.main.draftType
private suspend fun ensureContactsLoaded() {
if (contactsCache.value == null) {
val contactsList = getContacts(primaryUserId()).getOrElse { emptyList() }
@@ -25,6 +25,7 @@ import ch.protonmail.android.mailcomposer.domain.model.AttachmentAddError
import ch.protonmail.android.mailcomposer.domain.model.AttachmentAddErrorWithList
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsTo
@@ -74,6 +75,7 @@ internal class CompositeEventTest(
SenderEmail("author@proton.me"),
Subject("Here is the matter"),
DraftBody("Decrypted body of this draft"),
DraftMimeType.Html,
RecipientsTo(listOf(Recipient("you@proton.ch", "Name"))),
RecipientsCc(emptyList()),
RecipientsBcc(emptyList())
@@ -28,6 +28,7 @@ import ch.protonmail.android.mailcomposer.domain.model.AttachmentAddError
import ch.protonmail.android.mailcomposer.domain.model.AttachmentAddErrorWithList
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsTo
@@ -76,6 +77,7 @@ internal class EffectsStateModificationTest(
SenderEmail("author@proton.me"),
Subject("Here is the matter"),
DraftBody("Decrypted body of this draft"),
DraftMimeType.Html,
RecipientsTo(listOf(Recipient("you@proton.ch", "Name"))),
RecipientsCc(emptyList()),
RecipientsBcc(emptyList())
@@ -20,6 +20,7 @@ package ch.protonmail.android.mailcomposer.presentation.mapper.modifications
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsTo
@@ -56,12 +57,12 @@ internal class MainStateModificationTest(
private val initialState = ComposerState.Main.initial()
private val senderEmail = SenderEmail("sender-email@proton.me")
private val displayBodyUpdated = DraftDisplayBodyUiModel("<html>with sender-email@ signature</html>")
private val draftDisplayBody = DraftDisplayBodyUiModel("<html>draft display body</html>")
private val draftFields = DraftFields(
SenderEmail("author@proton.me"),
Subject("Here is the matter"),
DraftBody("Decrypted body of this draft"),
DraftMimeType.Html,
RecipientsTo(listOf(Recipient("you@proton.ch", "Name"))),
RecipientsCc(emptyList()),
RecipientsBcc(emptyList())
@@ -37,6 +37,7 @@ import ch.protonmail.android.mailcommon.presentation.model.TextUiModel
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftFieldsWithSyncStatus
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.OpenDraftError
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
@@ -246,6 +247,7 @@ internal class ComposerViewModelTest {
expectedSenderEmail,
expectedSubject,
expectedDraftBody,
DraftMimeType.Html,
recipientsTo,
recipientsCc,
recipientsBcc
@@ -372,6 +374,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
mimeType = DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -412,6 +415,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
mimeType = DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -456,6 +460,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
mimeType = DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -863,6 +868,7 @@ internal class ComposerViewModelTest {
expectedSenderEmail,
expectedSubject,
expectedDraftBody,
DraftMimeType.Html,
recipientsTo,
recipientsCc,
recipientsBcc
@@ -908,6 +914,7 @@ internal class ComposerViewModelTest {
expectedSenderEmail,
expectedSubject,
expectedDraftBody,
DraftMimeType.Html,
recipientsTo,
recipientsCc,
recipientsBcc
@@ -990,6 +997,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -1101,6 +1109,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
mimeType = DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -1141,6 +1150,7 @@ internal class ComposerViewModelTest {
sender = expectedSenderEmail,
subject = expectedSubject,
body = expectedDraftBody,
mimeType = DraftMimeType.Html,
recipientsTo = recipientsTo,
recipientsCc = recipientsCc,
recipientsBcc = recipientsBcc
@@ -1445,6 +1455,7 @@ internal class ComposerViewModelTest {
SenderEmail("author@proton.me"),
Subject("Here is the matter"),
DraftBody("Decrypted body of this draft"),
DraftMimeType.Html,
RecipientsTo(listOf(Recipient("valid@email.com", "Valid Email"))),
RecipientsCc(emptyList()),
RecipientsBcc(emptyList())
@@ -21,6 +21,7 @@ package ch.protonmail.android.testdata.composer
import ch.protonmail.android.mailcommon.domain.sample.UserAddressSample
import ch.protonmail.android.mailcomposer.domain.model.DraftBody
import ch.protonmail.android.mailcomposer.domain.model.DraftFields
import ch.protonmail.android.mailcomposer.domain.model.DraftMimeType
import ch.protonmail.android.mailcomposer.domain.model.RecipientsBcc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsCc
import ch.protonmail.android.mailcomposer.domain.model.RecipientsTo
@@ -45,6 +46,7 @@ object DraftFieldsTestData {
expectedSubject: String = "Subject for the message",
expectedSenderEmail: String = UserAddressSample.PrimaryAddress.email,
expectedDraftBody: String = "I am plaintext",
expectedMimeType: DraftMimeType = DraftMimeType.Html,
recipientsToAddresses: List<String> = listOf(RecipientSample.NamelessRecipient.address),
recipientsCcAddresses: List<String> = listOf(RecipientSample.NamelessRecipient.address),
recipientsBccAddresses: List<String> = listOf(RecipientSample.NamelessRecipient.address)
@@ -52,6 +54,7 @@ object DraftFieldsTestData {
SenderEmail(expectedSenderEmail),
Subject(expectedSubject),
DraftBody(expectedDraftBody),
expectedMimeType,
RecipientsTo(recipientsToAddresses.toRecipient()),
RecipientsCc(recipientsCcAddresses.toRecipient()),
RecipientsBcc(recipientsBccAddresses.toRecipient())