diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt index 592c561be6a..5e4a5861902 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt @@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.Outbox import androidx.compose.material.icons.filled.Star import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.outlined.AccountCircle +import androidx.compose.material.icons.outlined.AllInbox import androidx.compose.material.icons.outlined.Archive import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.ChevronLeft @@ -50,6 +51,9 @@ object Icons { val AccountCircle: ImageVector get() = MaterialIcons.Outlined.AccountCircle + val AllInbox: ImageVector + get() = MaterialIcons.Outlined.AllInbox + val Archive: ImageVector get() = MaterialIcons.Outlined.Archive diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContentPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContentPreview.kt index 4b7398034d5..c853fb01ec5 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContentPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContentPreview.kt @@ -4,6 +4,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_ACCOUNT +import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_FOLDER +import app.k9mail.feature.navigation.drawer.ui.FakeData.UNIFIED_FOLDER import kotlinx.collections.immutable.persistentListOf @Composable @@ -23,7 +25,7 @@ internal fun DrawerContentPreview() { @Composable @Preview(showBackground = true) -fun DrawerContentWithAccountPreview() { +internal fun DrawerContentWithAccountPreview() { PreviewWithTheme { DrawerContent( state = DrawerContract.State( @@ -35,3 +37,44 @@ fun DrawerContentWithAccountPreview() { ) } } + +@Composable +@Preview(showBackground = true) +internal fun DrawerContentWithFoldersPreview() { + PreviewWithTheme { + DrawerContent( + state = DrawerContract.State( + accounts = persistentListOf( + DISPLAY_ACCOUNT, + ), + selectedAccount = null, + folders = persistentListOf( + UNIFIED_FOLDER, + DISPLAY_FOLDER, + ), + ), + onEvent = {}, + ) + } +} + +@Composable +@Preview(showBackground = true) +internal fun DrawerContentWithSelectedFolderPreview() { + PreviewWithTheme { + DrawerContent( + state = DrawerContract.State( + accounts = persistentListOf( + DISPLAY_ACCOUNT, + ), + selectedAccount = DISPLAY_ACCOUNT, + folders = persistentListOf( + UNIFIED_FOLDER, + DISPLAY_FOLDER, + ), + selectedFolder = DISPLAY_FOLDER, + ), + onEvent = {}, + ) + } +} diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/FakeData.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/FakeData.kt index cb847e0c1ea..7ab5cde18f6 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/FakeData.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/FakeData.kt @@ -4,6 +4,8 @@ import app.k9mail.core.mail.folder.api.Folder import app.k9mail.core.mail.folder.api.FolderType import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolderType import app.k9mail.legacy.account.Account import app.k9mail.legacy.account.Identity @@ -52,4 +54,11 @@ internal object FakeData { unreadMessageCount = 14, starredMessageCount = 5, ) + + val UNIFIED_FOLDER = DisplayUnifiedFolder( + id = "unified_inbox", + unifiedType = DisplayUnifiedFolderType.INBOX, + unreadMessageCount = 123, + starredMessageCount = 567, + ) } diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountAvatarPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountAvatarPreview.kt index 106a27621e7..3f4d0533fbb 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountAvatarPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountAvatarPreview.kt @@ -7,7 +7,7 @@ import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_ACCOUNT @Composable @Preview(showBackground = true) -fun AccountAvatarPreview() { +internal fun AccountAvatarPreview() { PreviewWithThemes { AccountAvatar( account = DISPLAY_ACCOUNT, diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListItemPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListItemPreview.kt index 8c3588764eb..f4666c0d487 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListItemPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListItemPreview.kt @@ -7,7 +7,7 @@ import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_ACCOUNT @Composable @Preview(showBackground = true) -fun AccountListItemPreview() { +internal fun AccountListItemPreview() { PreviewWithThemes { AccountListItem( account = DISPLAY_ACCOUNT, diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListPreview.kt index 1a1aa916b9c..81c688f2dbf 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/account/AccountListPreview.kt @@ -8,7 +8,7 @@ import kotlinx.collections.immutable.persistentListOf @Composable @Preview(showBackground = true) -fun AccountListPreview() { +internal fun AccountListPreview() { PreviewWithTheme { AccountList( accounts = persistentListOf( @@ -23,7 +23,7 @@ fun AccountListPreview() { @Composable @Preview(showBackground = true) -fun AccountListWithSelectedPreview() { +internal fun AccountListWithSelectedPreview() { PreviewWithTheme { AccountList( accounts = persistentListOf( diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItemPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItemPreview.kt index 18835b183b2..e502e974df9 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItemPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItemPreview.kt @@ -1,66 +1,73 @@ package app.k9mail.feature.navigation.drawer.ui.folder import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import app.k9mail.core.mail.folder.api.FolderType import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_FOLDER +import app.k9mail.feature.navigation.drawer.ui.FakeData.UNIFIED_FOLDER +import app.k9mail.legacy.ui.folder.FolderNameFormatter @Composable @Preview(showBackground = true) -fun FolderListItemPreview() { +internal fun FolderListItemPreview() { PreviewWithThemes { FolderListItem( displayFolder = DISPLAY_FOLDER, selected = false, showStarredCount = false, onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), ) } } @Composable @Preview(showBackground = true) -fun FolderListItemSelectedPreview() { +internal fun FolderListItemSelectedPreview() { PreviewWithThemes { FolderListItem( displayFolder = DISPLAY_FOLDER, selected = true, showStarredCount = false, onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), ) } } @Composable @Preview(showBackground = true) -fun FolderListItemWithStarredPreview() { +internal fun FolderListItemWithStarredPreview() { PreviewWithThemes { FolderListItem( displayFolder = DISPLAY_FOLDER, selected = false, showStarredCount = true, onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), ) } } @Composable @Preview(showBackground = true) -fun FolderListItemWithStarredSelectedPreview() { +internal fun FolderListItemWithStarredSelectedPreview() { PreviewWithThemes { FolderListItem( displayFolder = DISPLAY_FOLDER, selected = true, showStarredCount = true, onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), ) } } @Composable @Preview(showBackground = true) -fun FolderListItemWithInboxFolderPreview() { +internal fun FolderListItemWithInboxFolderPreview() { PreviewWithThemes { FolderListItem( displayFolder = DISPLAY_FOLDER.copy( @@ -71,6 +78,21 @@ fun FolderListItemWithInboxFolderPreview() { selected = false, showStarredCount = true, onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), + ) + } +} + +@Composable +@Preview(showBackground = true) +internal fun FolderListItemWithUnifiedFolderPreview() { + PreviewWithThemes { + FolderListItem( + displayFolder = UNIFIED_FOLDER, + selected = false, + showStarredCount = false, + onClick = {}, + folderNameFormatter = FolderNameFormatter(LocalContext.current.resources), ) } } diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListPreview.kt new file mode 100644 index 00000000000..7ecfcef883f --- /dev/null +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListPreview.kt @@ -0,0 +1,54 @@ +package app.k9mail.feature.navigation.drawer.ui.folder + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme +import app.k9mail.feature.navigation.drawer.ui.FakeData.DISPLAY_FOLDER +import app.k9mail.feature.navigation.drawer.ui.FakeData.UNIFIED_FOLDER +import kotlinx.collections.immutable.persistentListOf + +@Composable +@Preview(showBackground = true) +internal fun FolderListPreview() { + PreviewWithTheme { + FolderList( + folders = persistentListOf( + DISPLAY_FOLDER, + ), + selectedFolder = null, + onFolderClick = {}, + showStarredCount = false, + ) + } +} + +@Composable +@Preview(showBackground = true) +internal fun FolderListPreviewSelected() { + PreviewWithTheme { + FolderList( + folders = persistentListOf( + DISPLAY_FOLDER, + ), + selectedFolder = DISPLAY_FOLDER, + onFolderClick = {}, + showStarredCount = false, + ) + } +} + +@Composable +@Preview(showBackground = true) +internal fun FolderListWithUnifiedFolderPreview() { + PreviewWithTheme { + FolderList( + folders = persistentListOf( + UNIFIED_FOLDER, + DISPLAY_FOLDER, + ), + selectedFolder = DISPLAY_FOLDER, + onFolderClick = {}, + showStarredCount = false, + ) + } +} diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingItemPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingItemPreview.kt index f3b3adc32e4..cfd63708628 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingItemPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingItemPreview.kt @@ -6,7 +6,7 @@ import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes @Composable @Preview(showBackground = true) -fun SettingItemPreview() { +internal fun SettingItemPreview() { PreviewWithThemes { SettingItem( label = "Setting", diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListItemPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListItemPreview.kt index 0ea943319f8..a5e16ecbaf5 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListItemPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListItemPreview.kt @@ -7,7 +7,7 @@ import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons @Composable @Preview(showBackground = true) -fun SettingListItemPreview() { +internal fun SettingListItemPreview() { PreviewWithThemes { SettingListItem( label = "Settings", diff --git a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListPreview.kt b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListPreview.kt index 34a2659c59e..a9587eaff76 100644 --- a/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListPreview.kt +++ b/feature/navigation/drawer/src/debug/kotlin/app/k9mail/feature/navigation/drawer/ui/setting/SettingListPreview.kt @@ -6,7 +6,7 @@ import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme @Composable @Preview(showBackground = true) -fun SettingListPreview() { +internal fun SettingListPreview() { PreviewWithTheme { SettingList( onAccountSelectorClick = {}, @@ -18,7 +18,7 @@ fun SettingListPreview() { @Composable @Preview(showBackground = true) -fun SettingListShowAccountSelectorPreview() { +internal fun SettingListShowAccountSelectorPreview() { PreviewWithTheme { SettingList( onAccountSelectorClick = {}, diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/FolderDrawer.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/FolderDrawer.kt index abde0ffd0dd..c1fabae908f 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/FolderDrawer.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/FolderDrawer.kt @@ -17,6 +17,7 @@ class FolderDrawer( override val parent: AppCompatActivity, private val openAccount: (account: Account) -> Unit, private val openFolder: (folderId: Long) -> Unit, + private val openUnifiedFolder: () -> Unit, private val openManageFolders: () -> Unit, private val openSettings: () -> Unit, createDrawerListener: () -> DrawerLayout.DrawerListener, @@ -40,6 +41,7 @@ class FolderDrawer( DrawerView( openAccount = openAccount, openFolder = openFolder, + openUnifiedFolder = openUnifiedFolder, openManageFolders = openManageFolders, openSettings = openSettings, closeDrawer = { close() }, diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/NavigationDrawerModule.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/NavigationDrawerModule.kt index 5d751563bbe..a69724638f3 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/NavigationDrawerModule.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/NavigationDrawerModule.kt @@ -33,6 +33,7 @@ val navigationDrawerModule: Module = module { single { GetDisplayFoldersForAccount( repository = get(), + messageCountsProvider = get(), ) } diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/DomainContract.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/DomainContract.kt index ed9eec44337..be741190c3e 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/DomainContract.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/DomainContract.kt @@ -1,7 +1,7 @@ package app.k9mail.feature.navigation.drawer.domain import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount -import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder import app.k9mail.feature.navigation.drawer.domain.entity.DrawerConfig import app.k9mail.legacy.account.Account import kotlinx.coroutines.flow.Flow @@ -18,7 +18,7 @@ interface DomainContract { } fun interface GetDisplayFoldersForAccount { - operator fun invoke(accountUuid: String): Flow> + operator fun invoke(accountUuid: String, includeUnifiedFolders: Boolean): Flow> } /** diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayAccountFolder.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayAccountFolder.kt index f5f561d1df2..7c94d3112d6 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayAccountFolder.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayAccountFolder.kt @@ -6,6 +6,8 @@ data class DisplayAccountFolder( val accountUuid: String, val folder: Folder, val isInTopGroup: Boolean, - val unreadMessageCount: Int, - val starredMessageCount: Int, -) + override val unreadMessageCount: Int, + override val starredMessageCount: Int, +) : DisplayFolder { + override val id: String = accountUuid + folder.id +} diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayFolder.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayFolder.kt new file mode 100644 index 00000000000..7caaf35da2d --- /dev/null +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayFolder.kt @@ -0,0 +1,7 @@ +package app.k9mail.feature.navigation.drawer.domain.entity + +interface DisplayFolder { + val id: String + val unreadMessageCount: Int + val starredMessageCount: Int +} diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolder.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolder.kt new file mode 100644 index 00000000000..5c48169df86 --- /dev/null +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolder.kt @@ -0,0 +1,8 @@ +package app.k9mail.feature.navigation.drawer.domain.entity + +data class DisplayUnifiedFolder( + override val id: String, + val unifiedType: DisplayUnifiedFolderType, + override val unreadMessageCount: Int, + override val starredMessageCount: Int, +) : DisplayFolder diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolderType.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolderType.kt new file mode 100644 index 00000000000..2c510766a65 --- /dev/null +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DisplayUnifiedFolderType.kt @@ -0,0 +1,5 @@ +package app.k9mail.feature.navigation.drawer.domain.entity + +enum class DisplayUnifiedFolderType { + INBOX, +} diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DrawerConfig.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DrawerConfig.kt index 07c6168016b..1fe2a96bd9d 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DrawerConfig.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/entity/DrawerConfig.kt @@ -1,6 +1,6 @@ package app.k9mail.feature.navigation.drawer.domain.entity data class DrawerConfig( - val showUnifiedInbox: Boolean, + val showUnifiedFolders: Boolean, val showStarredCount: Boolean, ) diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDisplayFoldersForAccount.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDisplayFoldersForAccount.kt index df5449c4b09..a853a8d4603 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDisplayFoldersForAccount.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDisplayFoldersForAccount.kt @@ -2,14 +2,22 @@ package app.k9mail.feature.navigation.drawer.domain.usecase import app.k9mail.feature.navigation.drawer.domain.DomainContract.UseCase import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolderType +import app.k9mail.legacy.message.controller.MessageCountsProvider +import app.k9mail.legacy.search.LocalSearch +import app.k9mail.legacy.search.api.SearchAttribute +import app.k9mail.legacy.search.api.SearchField import app.k9mail.legacy.ui.folder.DisplayFolderRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map class GetDisplayFoldersForAccount( private val repository: DisplayFolderRepository, + private val messageCountsProvider: MessageCountsProvider, ) : UseCase.GetDisplayFoldersForAccount { - override fun invoke(accountUuid: String): Flow> { + override fun invoke(accountUuid: String, includeUnifiedFolders: Boolean): Flow> { return repository.getDisplayFoldersFlow(accountUuid).map { displayFolders -> displayFolders.map { displayFolder -> DisplayAccountFolder( @@ -20,6 +28,41 @@ class GetDisplayFoldersForAccount( starredMessageCount = displayFolder.starredMessageCount, ) } + }.map { displayFolders -> + if (includeUnifiedFolders) { + createDisplayUnifiedFolders() + displayFolders + } else { + displayFolders + } } } + + private fun createDisplayUnifiedFolders(): List { + return listOf( + createUnifiedInboxFolder(), + ) + } + + private fun createUnifiedInboxFolder(): DisplayUnifiedFolder { + val search = getUnifiedInboxSearch() + val messageCounts = messageCountsProvider.getMessageCounts(search) + + return DisplayUnifiedFolder( + id = UNIFIED_INBOX_ID, + unifiedType = DisplayUnifiedFolderType.INBOX, + unreadMessageCount = messageCounts.unread, + starredMessageCount = messageCounts.starred, + ) + } + + private fun getUnifiedInboxSearch(): LocalSearch { + return LocalSearch().apply { + id = UNIFIED_INBOX_ID + and(SearchField.INTEGRATE, "1", SearchAttribute.EQUALS) + } + } + + companion object { + private const val UNIFIED_INBOX_ID = "unified_inbox" + } } diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContract.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContract.kt index 2ed1086827c..a7066ef50f7 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContract.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerContract.kt @@ -3,7 +3,7 @@ package app.k9mail.feature.navigation.drawer.ui import androidx.compose.runtime.Stable import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount -import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder import app.k9mail.feature.navigation.drawer.domain.entity.DrawerConfig import app.k9mail.legacy.account.Account import kotlinx.collections.immutable.ImmutableList @@ -16,13 +16,13 @@ interface DrawerContract { @Stable data class State( val config: DrawerConfig = DrawerConfig( - showUnifiedInbox = false, + showUnifiedFolders = false, showStarredCount = false, ), val accounts: ImmutableList = persistentListOf(), val selectedAccount: DisplayAccount? = null, - val folders: ImmutableList = persistentListOf(), - val selectedFolder: DisplayAccountFolder? = null, + val folders: ImmutableList = persistentListOf(), + val selectedFolder: DisplayFolder? = null, val showAccountSelector: Boolean = false, val isLoading: Boolean = false, ) @@ -30,7 +30,7 @@ interface DrawerContract { sealed interface Event { data class OnAccountClick(val account: DisplayAccount) : Event data class OnAccountViewClick(val account: DisplayAccount) : Event - data class OnFolderClick(val folder: DisplayAccountFolder) : Event + data class OnFolderClick(val folder: DisplayFolder) : Event data object OnAccountSelectorClick : Event data object OnManageFoldersClick : Event data object OnSettingsClick : Event @@ -40,6 +40,7 @@ interface DrawerContract { sealed interface Effect { data class OpenAccount(val account: Account) : Effect data class OpenFolder(val folderId: Long) : Effect + data object OpenUnifiedFolder : Effect data object OpenManageFolders : Effect data object OpenSettings : Effect data object CloseDrawer : Effect diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerView.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerView.kt index 9865a500cd6..04e4d607fbb 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerView.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerView.kt @@ -13,6 +13,7 @@ import org.koin.androidx.compose.koinViewModel fun DrawerView( openAccount: (account: Account) -> Unit, openFolder: (folderId: Long) -> Unit, + openUnifiedFolder: () -> Unit, openManageFolders: () -> Unit, openSettings: () -> Unit, closeDrawer: () -> Unit, @@ -22,6 +23,7 @@ fun DrawerView( when (effect) { is Effect.OpenAccount -> openAccount(effect.account) is Effect.OpenFolder -> openFolder(effect.folderId) + Effect.OpenUnifiedFolder -> openUnifiedFolder() is Effect.OpenManageFolders -> openManageFolders() is Effect.OpenSettings -> openSettings() Effect.CloseDrawer -> closeDrawer() diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModel.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModel.kt index 86294e8e049..7af317d529b 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModel.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModel.kt @@ -5,6 +5,8 @@ import app.k9mail.core.ui.compose.common.mvi.BaseViewModel import app.k9mail.feature.navigation.drawer.domain.DomainContract.UseCase import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Effect import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Event import app.k9mail.feature.navigation.drawer.ui.DrawerContract.State @@ -16,8 +18,9 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @Suppress("MagicNumber") @@ -70,19 +73,22 @@ class DrawerViewModel( @OptIn(ExperimentalCoroutinesApi::class) private suspend fun loadFolders() { - state.mapNotNull { it.selectedAccount?.account?.uuid } + state.map { + it.selectedAccount?.let { selectAccount -> + Pair(selectAccount.account.uuid, it.config.showUnifiedFolders) + } + }.filterNotNull() .distinctUntilChanged() - .flatMapLatest { accountUuid -> - getDisplayFoldersForAccount(accountUuid) + .flatMapLatest { (accountUuid, showUnifiedInbox) -> + getDisplayFoldersForAccount(accountUuid, showUnifiedInbox) }.collectLatest { folders -> updateFolders(folders) } } - private fun updateFolders(displayFolders: List) { + private fun updateFolders(displayFolders: List) { val selectedFolder = displayFolders.find { - it.accountUuid == state.value.selectedAccount?.account?.uuid && - it.folder.id == state.value.selectedFolder?.folder?.id + it.id == state.value.selectedFolder?.id } ?: displayFolders.firstOrNull() updateState { @@ -133,11 +139,16 @@ class DrawerViewModel( } } - private fun selectFolder(folder: DisplayAccountFolder) { + private fun selectFolder(folder: DisplayFolder) { updateState { it.copy(selectedFolder = folder) } - emitEffect(Effect.OpenFolder(folder.folder.id)) + + if (folder is DisplayAccountFolder) { + emitEffect(Effect.OpenFolder(folder.folder.id)) + } else if (folder is DisplayUnifiedFolder) { + emitEffect(Effect.OpenUnifiedFolder) + } viewModelScope.launch { delay(DRAWER_CLOSE_DELAY) diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderList.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderList.kt index 332d03a3619..e8fbb445901 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderList.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderList.kt @@ -2,34 +2,57 @@ package app.k9mail.feature.navigation.drawer.ui.folder import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import app.k9mail.core.ui.compose.designsystem.atom.DividerHorizontal import app.k9mail.core.ui.compose.theme2.MainTheme -import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder +import app.k9mail.legacy.ui.folder.FolderNameFormatter import kotlinx.collections.immutable.ImmutableList @Composable fun FolderList( - folders: ImmutableList, - selectedFolder: DisplayAccountFolder?, - onFolderClick: (DisplayAccountFolder) -> Unit, + folders: ImmutableList, + selectedFolder: DisplayFolder?, + onFolderClick: (DisplayFolder) -> Unit, showStarredCount: Boolean, modifier: Modifier = Modifier, ) { + val resources = LocalContext.current.resources + val folderNameFormatter = remember { FolderNameFormatter(resources) } + LazyColumn( modifier = modifier .fillMaxWidth(), contentPadding = PaddingValues(vertical = MainTheme.spacings.default), ) { - items(folders) { folder -> + items( + items = folders, + key = { it.id }, + ) { folder -> FolderListItem( displayFolder = folder, selected = folder == selectedFolder, showStarredCount = showStarredCount, onClick = onFolderClick, + folderNameFormatter = folderNameFormatter, ) + if (folder is DisplayUnifiedFolder) { + DividerHorizontal( + modifier = Modifier + .fillMaxWidth() + .padding( + vertical = MainTheme.spacings.default, + horizontal = MainTheme.spacings.triple, + ), + ) + } } } } diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItem.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItem.kt index 978db3ba5d3..60c84e74272 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItem.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/ui/folder/FolderListItem.kt @@ -3,28 +3,35 @@ package app.k9mail.feature.navigation.drawer.ui.folder import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource import app.k9mail.core.mail.folder.api.FolderType import app.k9mail.core.ui.compose.designsystem.atom.icon.Icon import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons import app.k9mail.core.ui.compose.designsystem.organism.drawer.NavigationDrawerItem +import app.k9mail.feature.navigation.drawer.R import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolderType +import app.k9mail.legacy.ui.folder.FolderNameFormatter @Composable fun FolderListItem( - displayFolder: DisplayAccountFolder, + displayFolder: DisplayFolder, selected: Boolean, - onClick: (DisplayAccountFolder) -> Unit, + onClick: (DisplayFolder) -> Unit, showStarredCount: Boolean, + folderNameFormatter: FolderNameFormatter, modifier: Modifier = Modifier, ) { NavigationDrawerItem( - label = displayFolder.folder.name, + label = mapFolderName(displayFolder, folderNameFormatter), selected = selected, onClick = { onClick(displayFolder) }, modifier = modifier, icon = { Icon( - imageVector = mapFolderIcon(displayFolder.folder.type), + imageVector = mapFolderIcon(displayFolder), ) }, badge = { @@ -37,8 +44,35 @@ fun FolderListItem( ) } -private fun mapFolderIcon(type: FolderType): ImageVector { - return when (type) { +@Composable +private fun mapFolderName( + displayFolder: DisplayFolder, + folderNameFormatter: FolderNameFormatter, +): String { + return when (displayFolder) { + is DisplayAccountFolder -> folderNameFormatter.displayName(displayFolder.folder) + is DisplayUnifiedFolder -> mapUnifiedFolderName(displayFolder) + else -> throw IllegalArgumentException("Unknown display folder: $displayFolder") + } +} + +@Composable +private fun mapUnifiedFolderName(folder: DisplayUnifiedFolder): String { + return when (folder.unifiedType) { + DisplayUnifiedFolderType.INBOX -> stringResource(R.string.navigation_drawer_unified_inbox_title) + } +} + +private fun mapFolderIcon(folder: DisplayFolder): ImageVector { + return when (folder) { + is DisplayAccountFolder -> mapDisplayAccountFolderIcon(folder) + is DisplayUnifiedFolder -> mapDisplayUnifiedFolderIcon(folder) + else -> throw IllegalArgumentException("Unknown display folder type: $folder") + } +} + +private fun mapDisplayAccountFolderIcon(folder: DisplayAccountFolder): ImageVector { + return when (folder.folder.type) { FolderType.INBOX -> Icons.Outlined.Inbox FolderType.OUTBOX -> Icons.Outlined.Outbox FolderType.SENT -> Icons.Outlined.Send @@ -49,3 +83,9 @@ private fun mapFolderIcon(type: FolderType): ImageVector { FolderType.REGULAR -> Icons.Outlined.Folder } } + +private fun mapDisplayUnifiedFolderIcon(folder: DisplayUnifiedFolder): ImageVector { + when (folder.unifiedType) { + DisplayUnifiedFolderType.INBOX -> return Icons.Outlined.AllInbox + } +} diff --git a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDrawerConfigTest.kt b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDrawerConfigTest.kt index 60cb138c812..6f3c9dc680a 100644 --- a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDrawerConfigTest.kt +++ b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/domain/usecase/GetDrawerConfigTest.kt @@ -12,7 +12,7 @@ class GetDrawerConfigTest { @Test fun `should get drawer config`() = runTest { val drawerConfig = DrawerConfig( - showUnifiedInbox = true, + showUnifiedFolders = true, showStarredCount = true, ) @@ -24,7 +24,7 @@ class GetDrawerConfigTest { assertThat(result).isEqualTo( DrawerConfig( - showUnifiedInbox = true, + showUnifiedFolders = true, showStarredCount = true, ), ) diff --git a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerStateTest.kt b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerStateTest.kt index 60dfcfa2ee7..05e74a855b6 100644 --- a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerStateTest.kt +++ b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerStateTest.kt @@ -16,7 +16,7 @@ class DrawerStateTest { assertThat(state).isEqualTo( State( config = DrawerConfig( - showUnifiedInbox = false, + showUnifiedFolders = false, showStarredCount = false, ), accounts = persistentListOf(), diff --git a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewKtTest.kt b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewKtTest.kt index 70169ffa27d..1f249cb837a 100644 --- a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewKtTest.kt +++ b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewKtTest.kt @@ -18,68 +18,42 @@ class DrawerViewKtTest : ComposeTest() { fun `should delegate effects`() = runTest { val initialState = State() val viewModel = FakeDrawerViewModel(initialState) - var openAccountCounter = 0 - var openFolderCounter = 0 - var openManageFoldersCounter = 0 - var openSettingsCounter = 0 - var closeDrawerCounter = 0 + val counter = Counter() + val verifyCounter = Counter() setContentWithTheme { DrawerView( - openAccount = { openAccountCounter++ }, - openFolder = { openFolderCounter++ }, - openManageFolders = { openManageFoldersCounter++ }, - openSettings = { openSettingsCounter++ }, - closeDrawer = { closeDrawerCounter++ }, + openAccount = { counter.openAccountCount++ }, + openFolder = { counter.openFolderCount++ }, + openUnifiedFolder = { counter.openUnifiedFolderCount++ }, + openManageFolders = { counter.openManageFoldersCount++ }, + openSettings = { counter.openSettingsCount++ }, + closeDrawer = { counter.closeDrawerCount++ }, viewModel = viewModel, ) } - assertThat(openAccountCounter).isEqualTo(0) - assertThat(openFolderCounter).isEqualTo(0) - assertThat(openManageFoldersCounter).isEqualTo(0) - assertThat(openSettingsCounter).isEqualTo(0) - assertThat(closeDrawerCounter).isEqualTo(0) + assertThat(counter).isEqualTo(verifyCounter) viewModel.effect(Effect.OpenAccount(FakeData.ACCOUNT)) - assertThat(openAccountCounter).isEqualTo(1) - assertThat(openFolderCounter).isEqualTo(0) - assertThat(openManageFoldersCounter).isEqualTo(0) - assertThat(openSettingsCounter).isEqualTo(0) - assertThat(closeDrawerCounter).isEqualTo(0) + verifyCounter.openAccountCount++ + assertThat(counter).isEqualTo(verifyCounter) + verifyCounter.openFolderCount++ viewModel.effect(Effect.OpenFolder(1)) - assertThat(openAccountCounter).isEqualTo(1) - assertThat(openFolderCounter).isEqualTo(1) - assertThat(openManageFoldersCounter).isEqualTo(0) - assertThat(openSettingsCounter).isEqualTo(0) - assertThat(closeDrawerCounter).isEqualTo(0) + verifyCounter.openUnifiedFolderCount++ + viewModel.effect(Effect.OpenUnifiedFolder) + verifyCounter.openManageFoldersCount++ viewModel.effect(Effect.OpenManageFolders) - assertThat(openAccountCounter).isEqualTo(1) - assertThat(openFolderCounter).isEqualTo(1) - assertThat(openManageFoldersCounter).isEqualTo(1) - assertThat(openSettingsCounter).isEqualTo(0) - assertThat(closeDrawerCounter).isEqualTo(0) - + verifyCounter.openSettingsCount++ viewModel.effect(Effect.OpenSettings) - assertThat(openAccountCounter).isEqualTo(1) - assertThat(openFolderCounter).isEqualTo(1) - assertThat(openManageFoldersCounter).isEqualTo(1) - assertThat(openSettingsCounter).isEqualTo(1) - assertThat(closeDrawerCounter).isEqualTo(0) - + verifyCounter.closeDrawerCount++ viewModel.effect(Effect.CloseDrawer) - - assertThat(openAccountCounter).isEqualTo(1) - assertThat(openFolderCounter).isEqualTo(1) - assertThat(openManageFoldersCounter).isEqualTo(1) - assertThat(openSettingsCounter).isEqualTo(1) - assertThat(closeDrawerCounter).isEqualTo(1) } @Test @@ -93,6 +67,7 @@ class DrawerViewKtTest : ComposeTest() { DrawerView( openAccount = {}, openFolder = {}, + openUnifiedFolder = {}, openManageFolders = {}, openSettings = {}, closeDrawer = {}, @@ -120,4 +95,14 @@ class DrawerViewKtTest : ComposeTest() { .printToString() .contains("ProgressBarRangeInfo(current=0.0, range=0.0..1.0, steps=0)") } + + @Suppress("DataClassShouldBeImmutable") + private data class Counter( + var openAccountCount: Int = 0, + var openFolderCount: Int = 0, + var openUnifiedFolderCount: Int = 0, + var openManageFoldersCount: Int = 0, + var openSettingsCount: Int = 0, + var closeDrawerCount: Int = 0, + ) } diff --git a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModelTest.kt b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModelTest.kt index 461a28e0364..7fc83ca2a08 100644 --- a/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModelTest.kt +++ b/feature/navigation/drawer/src/test/kotlin/app/k9mail/feature/navigation/drawer/ui/DrawerViewModelTest.kt @@ -9,6 +9,9 @@ import app.k9mail.core.ui.compose.testing.mvi.eventStateTest import app.k9mail.core.ui.compose.testing.mvi.turbinesWithInitialStateCheck import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccountFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolder +import app.k9mail.feature.navigation.drawer.domain.entity.DisplayUnifiedFolderType import app.k9mail.feature.navigation.drawer.domain.entity.DrawerConfig import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Effect import app.k9mail.feature.navigation.drawer.ui.DrawerContract.Event @@ -201,7 +204,7 @@ class DrawerViewModelTest { } @Test - fun `should set selected folder when OnFolderClick event is received`() = runTest { + fun `should set selected folder and emit OpenFolder when OnFolderClick event is received`() = runTest { val displayAccounts = createDisplayAccountList(3) val getDisplayAccountsFlow = MutableStateFlow(displayAccounts) val displayFoldersMap = mapOf( @@ -234,6 +237,42 @@ class DrawerViewModelTest { } } + @Test + fun `should set selected folder emit OpenUnifiedFolder when OnFolderClick event for unified folder is received`() = + runTest { + val displayAccounts = createDisplayAccountList(1) + val getDisplayAccountsFlow = MutableStateFlow(displayAccounts) + val displayFoldersMap = mapOf( + displayAccounts[0].account.uuid to + createDisplayFolderList(1) + listOf(createDisplayUnifiedFolder()), + ) + val displayFoldersFlow = MutableStateFlow(displayFoldersMap) + val initialState = State( + accounts = displayAccounts.toImmutableList(), + selectedAccount = displayAccounts[0], + folders = displayFoldersMap[displayAccounts[0].account.uuid]!!.toImmutableList(), + selectedFolder = displayFoldersMap[displayAccounts[0].account.uuid]!![0], + ) + val testSubject = createTestSubject( + displayAccountsFlow = getDisplayAccountsFlow, + displayFoldersFlow = displayFoldersFlow, + ) + val turbines = turbinesWithInitialStateCheck(testSubject, initialState) + + advanceUntilIdle() + + val displayFolders = displayFoldersMap[displayAccounts[0].account.uuid] ?: emptyList() + testSubject.event(Event.OnFolderClick(displayFolders[1])) + + assertThat(turbines.awaitStateItem().selectedFolder).isEqualTo(displayFolders[1]) + + assertThat(turbines.awaitEffectItem()).isEqualTo(Effect.OpenUnifiedFolder) + + turbines.assertThatAndEffectTurbineConsumed { + isEqualTo(Effect.CloseDrawer) + } + } + @Test fun `should change state when OnAccountSelectorClick event is received`() = runTest { val testSubject = createTestSubject() @@ -277,13 +316,13 @@ class DrawerViewModelTest { private fun createTestSubject( drawerConfigFlow: Flow = flow { emit(createDrawerConfig()) }, displayAccountsFlow: Flow> = flow { emit(emptyList()) }, - displayFoldersFlow: Flow>> = flow { emit(emptyMap()) }, + displayFoldersFlow: Flow>> = flow { emit(emptyMap()) }, syncMailFlow: Flow> = flow { emit(Result.success(Unit)) }, ): DrawerViewModel { return DrawerViewModel( getDrawerConfig = { drawerConfigFlow }, getDisplayAccounts = { displayAccountsFlow }, - getDisplayFoldersForAccount = { accountUuid -> + getDisplayFoldersForAccount = { accountUuid, _ -> displayFoldersFlow.map { it[accountUuid] ?: emptyList() } }, syncMail = { syncMailFlow }, @@ -295,7 +334,7 @@ class DrawerViewModelTest { showStarredCount: Boolean = false, ): DrawerConfig { return DrawerConfig( - showUnifiedInbox = showUnifiedInbox, + showUnifiedFolders = showUnifiedInbox, showStarredCount = showStarredCount, ) } @@ -369,4 +408,18 @@ class DrawerViewModelTest { ) } } + + private fun createDisplayUnifiedFolder( + id: String = "unified_inbox", + unifiedType: DisplayUnifiedFolderType = DisplayUnifiedFolderType.INBOX, + unreadCount: Int = 0, + starredCount: Int = 0, + ): DisplayUnifiedFolder { + return DisplayUnifiedFolder( + id = id, + unifiedType = unifiedType, + unreadMessageCount = unreadCount, + starredMessageCount = starredCount, + ) + } } diff --git a/feature/widget/unread/src/test/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetDataProviderTest.kt b/feature/widget/unread/src/test/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetDataProviderTest.kt index c8b0e93cc28..d770889aaab 100644 --- a/feature/widget/unread/src/test/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetDataProviderTest.kt +++ b/feature/widget/unread/src/test/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetDataProviderTest.kt @@ -7,6 +7,7 @@ import app.k9mail.legacy.account.Account import app.k9mail.legacy.mailstore.FolderRepository import app.k9mail.legacy.message.controller.MessageCounts import app.k9mail.legacy.message.controller.MessageCountsProvider +import app.k9mail.legacy.search.LocalSearch import app.k9mail.legacy.search.SearchAccount import app.k9mail.legacy.ui.folder.FolderNameFormatter import assertk.assertThat @@ -136,6 +137,10 @@ class UnreadWidgetDataProviderTest : AutoCloseKoinTest() { return MessageCounts(unread = SEARCH_ACCOUNT_UNREAD_COUNT, starred = 0) } + override fun getMessageCounts(search: LocalSearch): MessageCounts { + throw UnsupportedOperationException() + } + override fun getUnreadMessageCount(account: Account, folderId: Long): Int { return FOLDER_UNREAD_COUNT } diff --git a/legacy/common/src/main/java/com/fsck/k9/feature/NavigationDrawerConfigLoader.kt b/legacy/common/src/main/java/com/fsck/k9/feature/NavigationDrawerConfigLoader.kt index fb8fb70ff64..14dd1dcb19b 100644 --- a/legacy/common/src/main/java/com/fsck/k9/feature/NavigationDrawerConfigLoader.kt +++ b/legacy/common/src/main/java/com/fsck/k9/feature/NavigationDrawerConfigLoader.kt @@ -7,7 +7,7 @@ import com.fsck.k9.K9 class NavigationDrawerConfigLoader : DrawerConfigLoader { override fun loadDrawerConfig(): DrawerConfig { return DrawerConfig( - showUnifiedInbox = K9.isShowUnifiedInbox, + showUnifiedFolders = K9.isShowUnifiedInbox, showStarredCount = K9.isShowStarredCount, ) } diff --git a/legacy/core/src/main/java/com/fsck/k9/controller/DefaultMessageCountsProvider.kt b/legacy/core/src/main/java/com/fsck/k9/controller/DefaultMessageCountsProvider.kt index c5c7d073961..8553cdadaae 100644 --- a/legacy/core/src/main/java/com/fsck/k9/controller/DefaultMessageCountsProvider.kt +++ b/legacy/core/src/main/java/com/fsck/k9/controller/DefaultMessageCountsProvider.kt @@ -27,7 +27,10 @@ internal class DefaultMessageCountsProvider( } override fun getMessageCounts(searchAccount: SearchAccount): MessageCounts { - val search = searchAccount.relatedSearch + return getMessageCounts(searchAccount.relatedSearch) + } + + override fun getMessageCounts(search: LocalSearch): MessageCounts { val accounts = search.getAccounts(accountManager) var unreadCount = 0 diff --git a/legacy/message/src/main/java/app/k9mail/legacy/message/controller/MessageCountsProvider.kt b/legacy/message/src/main/java/app/k9mail/legacy/message/controller/MessageCountsProvider.kt index ccc7d8b50a0..0c27cc4b3e5 100644 --- a/legacy/message/src/main/java/app/k9mail/legacy/message/controller/MessageCountsProvider.kt +++ b/legacy/message/src/main/java/app/k9mail/legacy/message/controller/MessageCountsProvider.kt @@ -1,11 +1,13 @@ package app.k9mail.legacy.message.controller import app.k9mail.legacy.account.Account +import app.k9mail.legacy.search.LocalSearch import app.k9mail.legacy.search.SearchAccount interface MessageCountsProvider { fun getMessageCounts(account: Account): MessageCounts fun getMessageCounts(searchAccount: SearchAccount): MessageCounts + fun getMessageCounts(search: LocalSearch): MessageCounts fun getUnreadMessageCount(account: Account, folderId: Long): Int } diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt index a92682556ad..b611011469e 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt @@ -610,6 +610,7 @@ open class MessageList : parent = this, openAccount = { account -> openRealAccount(account) }, openFolder = { folderId -> openFolder(folderId) }, + openUnifiedFolder = { openUnifiedInbox() }, openManageFolders = { launchManageFoldersScreen() }, openSettings = { SettingsActivity.launch(this) }, createDrawerListener = { createDrawerListener() },