diff --git a/mail-common/dagger/src/main/kotlin/ch/protonmail/android/mailcommon/dagger/MailCommonDataModule.kt b/mail-common/dagger/src/main/kotlin/ch/protonmail/android/mailcommon/dagger/MailCommonDataModule.kt index f178e2c754..2f944610bc 100644 --- a/mail-common/dagger/src/main/kotlin/ch/protonmail/android/mailcommon/dagger/MailCommonDataModule.kt +++ b/mail-common/dagger/src/main/kotlin/ch/protonmail/android/mailcommon/dagger/MailCommonDataModule.kt @@ -23,11 +23,13 @@ import ch.protonmail.android.mailcommon.data.repository.UndoRepositoryImpl import ch.protonmail.android.mailcommon.data.system.BuildVersionProviderImpl import ch.protonmail.android.mailcommon.data.system.ContentValuesProviderImpl import ch.protonmail.android.mailcommon.data.system.DeviceCapabilitiesImpl +import ch.protonmail.android.mailcommon.data.system.SenderImageModeProviderImpl import ch.protonmail.android.mailcommon.domain.network.NetworkManager import ch.protonmail.android.mailcommon.domain.repository.UndoRepository import ch.protonmail.android.mailcommon.domain.system.BuildVersionProvider import ch.protonmail.android.mailcommon.domain.system.ContentValuesProvider import ch.protonmail.android.mailcommon.domain.system.DeviceCapabilities +import ch.protonmail.android.mailcommon.domain.usecase.SenderImageModeProvider import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -56,5 +58,8 @@ object MailCommonDataModule { @Binds fun bindUndoRepository(impl: UndoRepositoryImpl): UndoRepository + @Binds + fun bindSenderImageModeProvider(impl: SenderImageModeProviderImpl): SenderImageModeProvider + } } diff --git a/mail-common/data/src/main/kotlin/ch/protonmail/android/mailcommon/data/system/SenderImageModeProviderImpl.kt b/mail-common/data/src/main/kotlin/ch/protonmail/android/mailcommon/data/system/SenderImageModeProviderImpl.kt new file mode 100644 index 0000000000..7cf7e33ee4 --- /dev/null +++ b/mail-common/data/src/main/kotlin/ch/protonmail/android/mailcommon/data/system/SenderImageModeProviderImpl.kt @@ -0,0 +1,43 @@ +/* + * 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.mailcommon.data.system + +import android.content.Context +import android.content.res.Configuration +import androidx.appcompat.app.AppCompatDelegate +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme +import ch.protonmail.android.mailcommon.domain.usecase.SenderImageModeProvider +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +class SenderImageModeProviderImpl @Inject constructor( + @ApplicationContext private val applicationContext: Context +) : SenderImageModeProvider { + + override operator fun invoke(): SenderImageTheme { + val isDark = when (AppCompatDelegate.getDefaultNightMode()) { + AppCompatDelegate.MODE_NIGHT_YES -> true + AppCompatDelegate.MODE_NIGHT_NO -> false + else -> applicationContext.resources.configuration.let { + it.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES + } + } + return if (isDark) SenderImageTheme.Dark else SenderImageTheme.Light + } +} diff --git a/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/model/SenderImageTheme.kt b/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/model/SenderImageTheme.kt new file mode 100644 index 0000000000..ea38b2dcfa --- /dev/null +++ b/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/model/SenderImageTheme.kt @@ -0,0 +1,24 @@ +/* + * 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.mailcommon.domain.model + +enum class SenderImageTheme(val value: String) { + Dark("dark"), + Light("light") +} diff --git a/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/usecase/SenderImageModeProvider.kt b/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/usecase/SenderImageModeProvider.kt new file mode 100644 index 0000000000..45bee3716f --- /dev/null +++ b/mail-common/domain/src/main/kotlin/ch/protonmail/android/mailcommon/domain/usecase/SenderImageModeProvider.kt @@ -0,0 +1,26 @@ +/* + * 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.mailcommon.domain.usecase + +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme + +interface SenderImageModeProvider { + + operator fun invoke(): SenderImageTheme +} diff --git a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSource.kt b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSource.kt index 42a438378c..46b6328c6c 100644 --- a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSource.kt +++ b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSource.kt @@ -25,6 +25,7 @@ import ch.protonmail.android.mailcommon.data.mapper.LocalMessageId import ch.protonmail.android.mailcommon.data.mapper.LocalMessageMetadata import ch.protonmail.android.mailcommon.data.mapper.RemoteMessageId import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoSendError import ch.protonmail.android.mailcommon.domain.model.UndoableOperation import ch.protonmail.android.mailmessage.domain.model.MessageId @@ -62,7 +63,8 @@ interface RustMessageDataSource { suspend fun getSenderImage( userId: UserId, address: String, - bimi: String? + bimi: String?, + mode: SenderImageTheme ): String? suspend fun markRead(userId: UserId, messages: List): Either diff --git a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImpl.kt b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImpl.kt index 4a678f2d08..a0a9eed13f 100644 --- a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImpl.kt +++ b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImpl.kt @@ -28,6 +28,7 @@ import ch.protonmail.android.mailcommon.data.mapper.RemoteMessageId import ch.protonmail.android.mailcommon.domain.annotation.MissingRustApi import ch.protonmail.android.mailcommon.domain.coroutines.IODispatcher import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoSendError import ch.protonmail.android.mailcommon.domain.model.UndoableOperation import ch.protonmail.android.maillabel.data.local.RustMailboxFactory @@ -166,7 +167,8 @@ class RustMessageDataSourceImpl @Inject constructor( override suspend fun getSenderImage( userId: UserId, address: String, - bimi: String? + bimi: String?, + mode: SenderImageTheme ): String? = withContext(ioDispatcher) { val session = userSessionRepository.getUserSession(userId) if (session == null) { @@ -174,7 +176,7 @@ class RustMessageDataSourceImpl @Inject constructor( return@withContext null } - return@withContext getRustSenderImage(session, address, bimi) + return@withContext getRustSenderImage(session, address, bimi, mode) .onLeft { Timber.d("rust-message: Failed to get sender image $it") } .getOrNull() } diff --git a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImpl.kt b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImpl.kt index 91eab24aff..260cea07af 100644 --- a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImpl.kt +++ b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImpl.kt @@ -23,6 +23,7 @@ import arrow.core.Either import ch.protonmail.android.mailcommon.domain.model.ConversationCursorError import ch.protonmail.android.mailcommon.domain.model.CursorId import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoSendError import ch.protonmail.android.mailcommon.domain.repository.ConversationCursor import ch.protonmail.android.mailcommon.domain.repository.UndoRepository @@ -72,9 +73,10 @@ class RustMessageRepositoryImpl @Inject constructor( override suspend fun getSenderImage( userId: UserId, address: String, - bimi: String? + bimi: String?, + mode: SenderImageTheme ): SenderImage? { - return rustMessageDataSource.getSenderImage(userId, address, bimi)?.let { imageString -> + return rustMessageDataSource.getSenderImage(userId, address, bimi, mode)?.let { imageString -> SenderImage(File(imageString)) } } diff --git a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/usecase/GetRustSenderImage.kt b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/usecase/GetRustSenderImage.kt index 22ee5b20cd..633dbe59b4 100644 --- a/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/usecase/GetRustSenderImage.kt +++ b/mail-message/data/src/main/kotlin/ch/protonmail/android/mailmessage/data/usecase/GetRustSenderImage.kt @@ -23,6 +23,7 @@ import arrow.core.left import arrow.core.right import ch.protonmail.android.mailcommon.data.mapper.toDataError import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailsession.domain.wrapper.MailUserSessionWrapper import uniffi.mail_uniffi.MailUserSessionImageForSenderResult import javax.inject.Inject @@ -32,8 +33,9 @@ class GetRustSenderImage @Inject constructor() { suspend operator fun invoke( mailUserSession: MailUserSessionWrapper, address: String, - bimi: String? - ): Either = when (val result = mailUserSession.imageForSender(address, bimi)) { + bimi: String?, + mode: SenderImageTheme + ): Either = when (val result = mailUserSession.imageForSender(address, bimi, mode)) { is MailUserSessionImageForSenderResult.Error -> result.v1.toDataError().left() is MailUserSessionImageForSenderResult.Ok -> { when (val image = result.v1) { diff --git a/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImplTest.kt b/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImplTest.kt index eb88bed986..142a77424f 100644 --- a/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImplTest.kt +++ b/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/local/RustMessageDataSourceImplTest.kt @@ -24,6 +24,7 @@ import arrow.core.right import ch.protonmail.android.mailcommon.data.mapper.LocalLabelId import ch.protonmail.android.mailcommon.data.mapper.LocalMessageId import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoSendError import ch.protonmail.android.maillabel.data.local.RustMailboxFactory import ch.protonmail.android.maillabel.data.mapper.toLocalLabelId @@ -213,16 +214,17 @@ internal class RustMessageDataSourceImplTest { val mailSession = mockk() val address = "test@example.com" val bimi = "bimiSelector" + val mode = SenderImageTheme.Light val expectedImage = "image.png" coEvery { userSessionRepository.getUserSession(userId) } returns mailSession - coEvery { getRustSenderImage(mailSession, address, bimi) } returns expectedImage.right() + coEvery { getRustSenderImage(mailSession, address, bimi, mode) } returns expectedImage.right() // When - val result = dataSource.getSenderImage(userId, address, bimi) + val result = dataSource.getSenderImage(userId, address, bimi, mode) // Then - coVerify { getRustSenderImage(mailSession, address, bimi) } + coVerify { getRustSenderImage(mailSession, address, bimi, mode) } assertEquals(expectedImage, result) } @@ -232,14 +234,15 @@ internal class RustMessageDataSourceImplTest { val userId = UserIdTestData.userId val address = "test@example.com" val bimi = "bimiSelector" + val mode = SenderImageTheme.Light coEvery { userSessionRepository.getUserSession(userId) } returns null // When - val result = dataSource.getSenderImage(userId, address, bimi) + val result = dataSource.getSenderImage(userId, address, bimi, mode) // Then - coVerify(exactly = 0) { getRustSenderImage(any(), any(), any()) } + coVerify(exactly = 0) { getRustSenderImage(any(), any(), any(), any()) } assertNull(result) } @@ -250,18 +253,20 @@ internal class RustMessageDataSourceImplTest { val mailSession = mockk() val address = "test@example.com" val bimi = "bimiSelector" + val mode = SenderImageTheme.Light coEvery { userSessionRepository.getUserSession(userId) } returns mailSession coEvery { getRustSenderImage( mailSession, address, - bimi + bimi, + mode ) } returns DataError.Local.CryptoError.left() // When - val result = dataSource.getSenderImage(userId, address, bimi) + val result = dataSource.getSenderImage(userId, address, bimi, mode) // Then assertNull(result) diff --git a/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImplTest.kt b/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImplTest.kt index b30be4ca47..8b792da409 100644 --- a/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImplTest.kt +++ b/mail-message/data/src/test/kotlin/ch/protonmail/android/mailmessage/data/repository/RustMessageRepositoryImplTest.kt @@ -27,6 +27,7 @@ import ch.protonmail.android.mailcommon.domain.model.ConversationId import ch.protonmail.android.mailcommon.domain.model.CursorId import ch.protonmail.android.mailcommon.domain.model.CursorResult import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoableOperation import ch.protonmail.android.mailcommon.domain.repository.ConversationCursor import ch.protonmail.android.mailcommon.domain.repository.UndoRepository @@ -240,16 +241,17 @@ internal class RustMessageRepositoryImplTest { val userId = UserIdTestData.userId val address = "test@example.com" val bimi = "bimiSelector" + val mode = SenderImageTheme.Light val imagePath = "image.png" val expectedSenderImage = SenderImage(File(imagePath)) - coEvery { rustMessageDataSource.getSenderImage(userId, address, bimi) } returns imagePath + coEvery { rustMessageDataSource.getSenderImage(userId, address, bimi, mode) } returns imagePath // When - val result = repository.getSenderImage(userId, address, bimi) + val result = repository.getSenderImage(userId, address, bimi, mode) // Then - coVerify { rustMessageDataSource.getSenderImage(userId, address, bimi) } + coVerify { rustMessageDataSource.getSenderImage(userId, address, bimi, mode) } assertEquals(expectedSenderImage, result) } @@ -259,14 +261,15 @@ internal class RustMessageRepositoryImplTest { val userId = UserIdTestData.userId val address = "test@example.com" val bimi = "bimiSelector" + val mode = SenderImageTheme.Light - coEvery { rustMessageDataSource.getSenderImage(userId, address, bimi) } returns null + coEvery { rustMessageDataSource.getSenderImage(userId, address, bimi, mode) } returns null // When - val result = repository.getSenderImage(userId, address, bimi) + val result = repository.getSenderImage(userId, address, bimi, mode) // Then - coVerify { rustMessageDataSource.getSenderImage(userId, address, bimi) } + coVerify { rustMessageDataSource.getSenderImage(userId, address, bimi, mode) } assertNull(result) } diff --git a/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/repository/MessageRepository.kt b/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/repository/MessageRepository.kt index bc20ff8d83..95a61c1237 100644 --- a/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/repository/MessageRepository.kt +++ b/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/repository/MessageRepository.kt @@ -22,6 +22,7 @@ import arrow.core.Either import ch.protonmail.android.mailcommon.domain.model.ConversationCursorError import ch.protonmail.android.mailcommon.domain.model.CursorId import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailcommon.domain.model.UndoSendError import ch.protonmail.android.mailcommon.domain.repository.ConversationCursor import ch.protonmail.android.maillabel.domain.model.LabelId @@ -49,7 +50,8 @@ interface MessageRepository { suspend fun getSenderImage( userId: UserId, address: String, - bimi: String? + bimi: String?, + mode: SenderImageTheme ): SenderImage? /** diff --git a/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/usecase/GetSenderImage.kt b/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/usecase/GetSenderImage.kt index 19e0bd46a8..3855df2afb 100644 --- a/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/usecase/GetSenderImage.kt +++ b/mail-message/domain/src/main/kotlin/ch/protonmail/android/mailmessage/domain/usecase/GetSenderImage.kt @@ -18,19 +18,22 @@ package ch.protonmail.android.mailmessage.domain.usecase -import ch.protonmail.android.mailsession.domain.usecase.ObservePrimaryUserId +import ch.protonmail.android.mailcommon.domain.usecase.SenderImageModeProvider import ch.protonmail.android.mailmessage.domain.model.SenderImage import ch.protonmail.android.mailmessage.domain.repository.MessageRepository +import ch.protonmail.android.mailsession.domain.usecase.ObservePrimaryUserId import kotlinx.coroutines.flow.firstOrNull import javax.inject.Inject class GetSenderImage @Inject constructor( private val observePrimaryUserId: ObservePrimaryUserId, - private val messageRepository: MessageRepository + private val messageRepository: MessageRepository, + private val senderImageModeProvider: SenderImageModeProvider ) { suspend operator fun invoke(address: String, bimiSelector: String?): SenderImage? { + val mode = senderImageModeProvider() return observePrimaryUserId().firstOrNull()?.let { userId -> - messageRepository.getSenderImage(userId, address, bimiSelector) + messageRepository.getSenderImage(userId, address, bimiSelector, mode) } } } diff --git a/mail-session/domain/src/main/kotlin/ch/protonmail/android/mailsession/domain/wrapper/MailUserSessionWrapper.kt b/mail-session/domain/src/main/kotlin/ch/protonmail/android/mailsession/domain/wrapper/MailUserSessionWrapper.kt index eb78bf0ea6..3afca6d657 100644 --- a/mail-session/domain/src/main/kotlin/ch/protonmail/android/mailsession/domain/wrapper/MailUserSessionWrapper.kt +++ b/mail-session/domain/src/main/kotlin/ch/protonmail/android/mailsession/domain/wrapper/MailUserSessionWrapper.kt @@ -24,6 +24,7 @@ import arrow.core.right import ch.protonmail.android.mailcommon.data.mapper.LocalAttachmentId import ch.protonmail.android.mailcommon.data.mapper.toDataError import ch.protonmail.android.mailcommon.domain.model.DataError +import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme import ch.protonmail.android.mailsession.domain.mapper.toEventLoopError import ch.protonmail.android.mailsession.domain.model.EventLoopError import timber.log.Timber @@ -33,6 +34,7 @@ import uniffi.mail_uniffi.ExecuteWhenOnlineCallbackAsync import uniffi.mail_uniffi.Fork import uniffi.mail_uniffi.MailUserSession import uniffi.mail_uniffi.MailUserSessionForkResult +import uniffi.mail_uniffi.MailUserSessionImageForSenderResult import uniffi.mail_uniffi.MailUserSessionOverrideUserFeatureFlagResult import uniffi.mail_uniffi.MailUserSessionUserResult import uniffi.mail_uniffi.MeasurementEventType @@ -61,14 +63,20 @@ class MailUserSessionWrapper(private val userSession: MailUserSession) { VoidEventResult.Ok -> Unit.right() } - suspend fun imageForSender(address: String, bimi: String?) = userSession.imageForSender( - address, - bimi, - true, - SenderImageSize.S128, - null, - "png" - ) + suspend fun imageForSender( + address: String, + bimi: String?, + mode: SenderImageTheme + ): MailUserSessionImageForSenderResult { + return userSession.imageForSender( + address, + bimi, + true, + SenderImageSize.S128, + mode.value, + "png" + ) + } suspend fun getAttachment(attachmentId: LocalAttachmentId) = userSession.getAttachment(attachmentId)