Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ val navigationDropDownDrawerModule: Module = module {
notificationStream = get(),
featureFlagProvider = get(),
avatarMapper = get(),
unifiedFolderRepository = get(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ import net.thunderbird.core.android.account.LegacyAccountDtoManager
import net.thunderbird.core.featureflag.FeatureFlagKey
import net.thunderbird.core.featureflag.FeatureFlagProvider
import net.thunderbird.feature.account.storage.mapper.AvatarDataMapper
import net.thunderbird.feature.navigation.drawer.dropdown.domain.DomainContract.UnifiedFolderRepository
import net.thunderbird.feature.navigation.drawer.dropdown.domain.DomainContract.UseCase
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.DisplayAccount
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.MailDisplayAccount
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayAccount
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayFolder
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayFolderType
import net.thunderbird.feature.notification.api.content.AuthenticationErrorNotification
import net.thunderbird.feature.notification.api.receiver.InAppNotificationStream

Expand All @@ -35,6 +38,7 @@ internal class GetDisplayAccounts(
private val notificationStream: InAppNotificationStream,
private val featureFlagProvider: FeatureFlagProvider,
private val avatarMapper: AvatarDataMapper,
private val unifiedFolderRepository: UnifiedFolderRepository,
private val coroutineContext: CoroutineContext = Dispatchers.IO,
) : UseCase.GetDisplayAccounts {

Expand All @@ -49,7 +53,7 @@ internal class GetDisplayAccounts(
getMessageCountsFlow(account)
}

combine(messageCountsFlows) { messageCountsList ->
val displayAccountsFlow = combine(messageCountsFlows) { messageCountsList ->
val displayAccounts = messageCountsList.mapIndexed { index, messageCounts ->
val account = accounts[index]
MailDisplayAccount(
Expand All @@ -65,11 +69,18 @@ internal class GetDisplayAccounts(
)
}

if (showUnifiedAccount) {
withUnifiedAccount(displayAccounts)
} else {
displayAccounts
displayAccounts
}

if (showUnifiedAccount) {
combine(
displayAccountsFlow,
unifiedFolderRepository.getUnifiedDisplayFolderFlow(UnifiedDisplayFolderType.INBOX),
) { displayAccounts, unifiedInbox ->
withUnifiedAccount(displayAccounts, unifiedInbox)
}
} else {
displayAccountsFlow
}
}
}
Expand All @@ -92,10 +103,13 @@ internal class GetDisplayAccounts(
}
}

private fun withUnifiedAccount(accounts: List<DisplayAccount>): List<DisplayAccount> {
private fun withUnifiedAccount(
accounts: List<DisplayAccount>,
unifiedInbox: UnifiedDisplayFolder,
): List<DisplayAccount> {
val unified = UnifiedDisplayAccount(
unreadMessageCount = accounts.sumOf { it.unreadMessageCount },
starredMessageCount = accounts.sumOf { it.starredMessageCount },
unreadMessageCount = unifiedInbox.unreadMessageCount,
starredMessageCount = unifiedInbox.starredMessageCount,
hasError = accounts.any { it.hasError },
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import net.thunderbird.feature.search.legacy.SearchAccount

internal class FakeMessageCountsProvider(
private val messageCounts: MessageCounts,
private val accountMessageCounts: Map<String, MessageCounts> = emptyMap(),
) : MessageCountsProvider {
var recordedSearch: LocalMessageSearch =
LocalMessageSearch()

override fun getMessageCounts(account: LegacyAccountDto): MessageCounts {
TODO("Not yet implemented")
return checkNotNull(accountMessageCounts[account.uuid])
}

override fun getMessageCounts(searchAccount: SearchAccount): MessageCounts {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import net.thunderbird.core.android.account.AccountRemovedListener
import net.thunderbird.core.android.account.AccountsChangeListener
import net.thunderbird.core.android.account.LegacyAccountDto
Expand All @@ -15,7 +16,7 @@ internal class FakeLegacyAccountDtoManager(
}

override fun getAccountsFlow(): Flow<List<LegacyAccountDto>> {
TODO("Not yet implemented")
return flowOf(accounts)
}

override fun getAccount(accountUuid: String): LegacyAccountDto? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase

import app.k9mail.legacy.mailstore.MessageListChangedListener
import app.k9mail.legacy.mailstore.MessageListRepository
import app.k9mail.legacy.mailstore.MessageMapper
import app.k9mail.legacy.message.controller.MessageCounts
import assertk.assertThat
import assertk.assertions.isEqualTo
import kotlin.test.Test
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import net.thunderbird.core.android.account.Identity
import net.thunderbird.core.android.account.LegacyAccountDto
import net.thunderbird.feature.account.avatar.Avatar
import net.thunderbird.feature.account.storage.mapper.AvatarDataMapper
import net.thunderbird.feature.account.storage.profile.AvatarDto
import net.thunderbird.feature.account.storage.profile.AvatarTypeDto
import net.thunderbird.feature.navigation.drawer.dropdown.data.FakeMessageCountsProvider
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayAccount
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayFolder
import net.thunderbird.feature.navigation.drawer.dropdown.domain.entity.UnifiedDisplayFolderType
import net.thunderbird.feature.navigation.drawer.dropdown.ui.FakeFeatureFlagProvider
import net.thunderbird.feature.notification.api.content.InAppNotification
import net.thunderbird.feature.notification.api.receiver.InAppNotificationStream

internal class GetDisplayAccountsTest {

@Test
fun `should use filtered unified inbox counts for unified account`() = runTest {
// Arrange
val includedAccount = createAccount("00000000-0000-0000-0000-000000000001")
val excludedAccount = createAccount("00000000-0000-0000-0000-000000000002")
val testSubject = GetDisplayAccounts(
accountManager = FakeLegacyAccountDtoManager(accounts = listOf(includedAccount, excludedAccount)),
messageCountsProvider = FakeMessageCountsProvider(
messageCounts = MessageCounts(unread = 1, starred = 2),
accountMessageCounts = mapOf(
includedAccount.uuid to MessageCounts(unread = 1, starred = 2),
excludedAccount.uuid to MessageCounts(unread = 5, starred = 7),
),
),
messageListRepository = FakeMessageListRepository(),
notificationStream = FakeInAppNotificationStream(),
featureFlagProvider = FakeFeatureFlagProvider(),
avatarMapper = FakeAvatarDataMapper,
unifiedFolderRepository = FakeUnifiedFolderRepository(
flowOf(
UnifiedDisplayFolder(
id = "unified_inbox",
unifiedType = UnifiedDisplayFolderType.INBOX,
unreadMessageCount = 1,
starredMessageCount = 2,
),
),
),
)

// Act
val result = testSubject(showUnifiedAccount = true).first()

// Assert
assertThat(result.first()).isEqualTo(
UnifiedDisplayAccount(
unreadMessageCount = 1,
starredMessageCount = 2,
hasError = false,
),
)
}

private fun createAccount(uuid: String): LegacyAccountDto {
return LegacyAccountDto(uuid).apply {
identities = mutableListOf(Identity(email = "$uuid@example.com"))
}
}

private class FakeMessageListRepository : MessageListRepository {
override fun addListener(listener: MessageListChangedListener) = Unit

override fun addListener(accountUuid: String, listener: MessageListChangedListener) = Unit

override fun removeListener(listener: MessageListChangedListener) = Unit

override fun notifyMessageListChanged(accountUuid: String) = Unit

override fun <T> getMessages(
accountUuid: String,
selection: String,
selectionArgs: Array<String>,
sortOrder: String,
messageMapper: MessageMapper<T>,
): List<T> = emptyList()

override fun <T> getThreadedMessages(
accountUuid: String,
selection: String,
selectionArgs: Array<String>,
sortOrder: String,
messageMapper: MessageMapper<T>,
): List<T> = emptyList()

override fun <T> getThread(
accountUuid: String,
threadId: Long,
sortOrder: String,
messageMapper: MessageMapper<T>,
): List<T> = emptyList()
}

private class FakeInAppNotificationStream : InAppNotificationStream {
override val notifications: StateFlow<Set<InAppNotification>> = MutableStateFlow(emptySet())
}

private object FakeAvatarDataMapper : AvatarDataMapper {
override fun toDomain(dto: AvatarDto): Avatar = Avatar.Monogram("?")

override fun toDto(domain: Avatar): AvatarDto {
return AvatarDto(
avatarType = AvatarTypeDto.MONOGRAM,
avatarMonogram = "?",
avatarImageUri = null,
avatarIconName = null,
)
}
}
}
Loading