mirror of
https://github.com/ProtonMail/android-mail.git
synced 2026-05-15 09:50:40 +00:00
Respect the active theme when loading sender image
ET-4901
This commit is contained in:
+5
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+43
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
+24
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ch.protonmail.android.mailcommon.domain.model
|
||||
|
||||
enum class SenderImageTheme(val value: String) {
|
||||
Dark("dark"),
|
||||
Light("light")
|
||||
}
|
||||
+26
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ch.protonmail.android.mailcommon.domain.usecase
|
||||
|
||||
import ch.protonmail.android.mailcommon.domain.model.SenderImageTheme
|
||||
|
||||
interface SenderImageModeProvider {
|
||||
|
||||
operator fun invoke(): SenderImageTheme
|
||||
}
|
||||
+3
-1
@@ -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<LocalMessageId>): Either<DataError, Unit>
|
||||
|
||||
+4
-2
@@ -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()
|
||||
}
|
||||
|
||||
+4
-2
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -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<DataError, String> = when (val result = mailUserSession.imageForSender(address, bimi)) {
|
||||
bimi: String?,
|
||||
mode: SenderImageTheme
|
||||
): Either<DataError, String> = when (val result = mailUserSession.imageForSender(address, bimi, mode)) {
|
||||
is MailUserSessionImageForSenderResult.Error -> result.v1.toDataError().left()
|
||||
is MailUserSessionImageForSenderResult.Ok -> {
|
||||
when (val image = result.v1) {
|
||||
|
||||
+12
-7
@@ -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<MailUserSessionWrapper>()
|
||||
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<MailUserSessionWrapper>()
|
||||
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)
|
||||
|
||||
+9
-6
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -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?
|
||||
|
||||
/**
|
||||
|
||||
+6
-3
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-8
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user