diff --git a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/legacy/FoldersViewModel.kt b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/legacy/FoldersViewModel.kt index 2b6a8a74b3..e106b7bc1f 100644 --- a/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/legacy/FoldersViewModel.kt +++ b/feature/navigation/drawer/src/main/kotlin/app/k9mail/feature/navigation/drawer/legacy/FoldersViewModel.kt @@ -5,9 +5,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import app.k9mail.legacy.account.Account -import app.k9mail.legacy.mailstore.FolderRepository +import app.k9mail.legacy.mailstore.DisplayFolderRepository import app.k9mail.legacy.message.controller.MessageCountsProvider import app.k9mail.legacy.search.SearchAccount +import app.k9mail.legacy.ui.folder.DisplayUnifiedInbox +import app.k9mail.legacy.ui.folder.FolderList import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -20,7 +22,7 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalCoroutinesApi::class) class FoldersViewModel( - private val folderRepository: FolderRepository, + private val folderRepository: DisplayFolderRepository, private val messageCountsProvider: MessageCountsProvider, private val isShowUnifiedInbox: () -> Boolean, private val getUnifiedInboxTitle: () -> String, diff --git a/legacy/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt b/legacy/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt index 3fb188c0e7..d1917b4bbc 100644 --- a/legacy/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt +++ b/legacy/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt @@ -1,5 +1,6 @@ package com.fsck.k9.mailstore +import app.k9mail.legacy.mailstore.DisplayFolderRepository import app.k9mail.legacy.mailstore.FolderRepository import app.k9mail.legacy.mailstore.MessageListRepository import app.k9mail.legacy.mailstore.MessageStoreManager @@ -9,7 +10,18 @@ import com.fsck.k9.message.extractors.MessagePreviewCreator import org.koin.dsl.module val mailStoreModule = module { - single { FolderRepository(messageStoreManager = get(), accountManager = get()) } + single { + FolderRepository( + messageStoreManager = get(), + accountManager = get(), + ) + } + single { + DisplayFolderRepository( + messageStoreManager = get(), + accountManager = get(), + ) + } single { MessageViewInfoExtractorFactory(get(), get(), get()) } single { StorageManager.getInstance(get()) } single { SpecialFolderSelectionStrategy() } diff --git a/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/DisplayFolderRepository.kt b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/DisplayFolderRepository.kt new file mode 100644 index 0000000000..ed5bf840b3 --- /dev/null +++ b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/DisplayFolderRepository.kt @@ -0,0 +1,103 @@ +package app.k9mail.legacy.mailstore + +import app.k9mail.core.mail.folder.api.Folder +import app.k9mail.core.mail.folder.api.FolderType +import app.k9mail.legacy.account.Account +import app.k9mail.legacy.account.Account.FolderMode +import app.k9mail.legacy.account.AccountManager +import app.k9mail.legacy.di.DI +import app.k9mail.legacy.folder.DisplayFolder +import app.k9mail.legacy.mailstore.FolderTypeMapper.folderTypeOf +import app.k9mail.legacy.message.controller.MessagingControllerRegistry +import app.k9mail.legacy.message.controller.SimpleMessagingListener +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +class DisplayFolderRepository( + private val messageStoreManager: MessageStoreManager, + private val accountManager: AccountManager, + private val coroutineContext: CoroutineContext = Dispatchers.IO, +) { + private val sortForDisplay = + compareByDescending { it.folder.type == FolderType.INBOX } + .thenByDescending { it.folder.type == FolderType.OUTBOX } + .thenByDescending { it.folder.type != FolderType.REGULAR } + .thenByDescending { it.isInTopGroup } + .thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name } + + private fun getDisplayFolders(account: Account, displayMode: FolderMode?): List { + val messageStore = messageStoreManager.getMessageStore(account.uuid) + return messageStore.getDisplayFolders( + displayMode = displayMode ?: account.folderDisplayMode, + outboxFolderId = account.outboxFolderId, + ) { folder -> + DisplayFolder( + folder = Folder( + id = folder.id, + name = folder.name, + type = folderTypeOf(account, folder.id), + isLocalOnly = folder.isLocalOnly, + ), + isInTopGroup = folder.isInTopGroup, + unreadMessageCount = folder.unreadMessageCount, + starredMessageCount = folder.starredMessageCount, + ) + }.sortedWith(sortForDisplay) + } + + fun getDisplayFoldersFlow(account: Account, displayMode: FolderMode): Flow> { + val messagingController = DI.get() + val messageStore = messageStoreManager.getMessageStore(account.uuid) + + return callbackFlow { + send(getDisplayFolders(account, displayMode)) + + val folderStatusChangedListener = object : SimpleMessagingListener() { + override fun folderStatusChanged(statusChangedAccount: Account, folderId: Long) { + if (statusChangedAccount.uuid == account.uuid) { + trySendBlocking(getDisplayFolders(account, displayMode)) + } + } + } + messagingController.addListener(folderStatusChangedListener) + + val folderSettingsChangedListener = FolderSettingsChangedListener { + trySendBlocking(getDisplayFolders(account, displayMode)) + } + messageStore.addFolderSettingsChangedListener(folderSettingsChangedListener) + + awaitClose { + messagingController.removeListener(folderStatusChangedListener) + messageStore.removeFolderSettingsChangedListener(folderSettingsChangedListener) + } + }.buffer(capacity = Channel.CONFLATED) + .distinctUntilChanged() + .flowOn(coroutineContext) + } + + fun getDisplayFoldersFlow(accountUuid: String): Flow> { + return accountManager.getAccountFlow(accountUuid) + .map { latestAccount -> + AccountContainer(latestAccount, latestAccount.folderDisplayMode) + } + .distinctUntilChanged() + .flatMapLatest { (account, folderDisplayMode) -> + getDisplayFoldersFlow(account, folderDisplayMode) + } + } +} + +private data class AccountContainer( + val account: Account, + val folderDisplayMode: FolderMode, +) diff --git a/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderRepository.kt b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderRepository.kt index c1147f5ca3..d78bce7d27 100644 --- a/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderRepository.kt +++ b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderRepository.kt @@ -2,15 +2,12 @@ package app.k9mail.legacy.mailstore import app.k9mail.core.mail.folder.api.Folder import app.k9mail.core.mail.folder.api.FolderDetails -import app.k9mail.core.mail.folder.api.FolderType import app.k9mail.legacy.account.Account import app.k9mail.legacy.account.Account.FolderMode import app.k9mail.legacy.account.AccountManager -import app.k9mail.legacy.di.DI -import app.k9mail.legacy.folder.DisplayFolder import app.k9mail.legacy.folder.RemoteFolder -import app.k9mail.legacy.message.controller.MessagingControllerRegistry -import app.k9mail.legacy.message.controller.SimpleMessagingListener +import app.k9mail.legacy.mailstore.FolderTypeMapper.folderTypeOf +import app.k9mail.legacy.mailstore.RemoteFolderTypeMapper.toFolderType import com.fsck.k9.mail.FolderClass import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers @@ -25,7 +22,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import com.fsck.k9.mail.FolderType as RemoteFolderType @Suppress("TooManyFunctions") @OptIn(ExperimentalCoroutinesApi::class) @@ -34,74 +30,6 @@ class FolderRepository( private val accountManager: AccountManager, private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, ) { - private val sortForDisplay = - compareByDescending { it.folder.type == FolderType.INBOX } - .thenByDescending { it.folder.type == FolderType.OUTBOX } - .thenByDescending { it.folder.type != FolderType.REGULAR } - .thenByDescending { it.isInTopGroup } - .thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name } - - fun getDisplayFolders(account: Account, displayMode: FolderMode?): List { - val messageStore = messageStoreManager.getMessageStore(account) - return messageStore.getDisplayFolders( - displayMode = displayMode ?: account.folderDisplayMode, - outboxFolderId = account.outboxFolderId, - ) { folder -> - DisplayFolder( - folder = Folder( - id = folder.id, - name = folder.name, - type = folderTypeOf(account, folder.id), - isLocalOnly = folder.isLocalOnly, - ), - isInTopGroup = folder.isInTopGroup, - unreadMessageCount = folder.unreadMessageCount, - starredMessageCount = folder.starredMessageCount, - ) - }.sortedWith(sortForDisplay) - } - - fun getDisplayFoldersFlow(account: Account, displayMode: FolderMode): Flow> { - val messagingController = DI.get() - val messageStore = messageStoreManager.getMessageStore(account) - - return callbackFlow { - send(getDisplayFolders(account, displayMode)) - - val folderStatusChangedListener = object : SimpleMessagingListener() { - override fun folderStatusChanged(statusChangedAccount: Account, folderId: Long) { - if (statusChangedAccount.uuid == account.uuid) { - trySendBlocking(getDisplayFolders(account, displayMode)) - } - } - } - messagingController.addListener(folderStatusChangedListener) - - val folderSettingsChangedListener = FolderSettingsChangedListener { - trySendBlocking(getDisplayFolders(account, displayMode)) - } - messageStore.addFolderSettingsChangedListener(folderSettingsChangedListener) - - awaitClose { - messagingController.removeListener(folderStatusChangedListener) - messageStore.removeFolderSettingsChangedListener(folderSettingsChangedListener) - } - }.buffer(capacity = Channel.CONFLATED) - .distinctUntilChanged() - .flowOn(ioDispatcher) - } - - fun getDisplayFoldersFlow(accountUuid: String): Flow> { - return accountManager.getAccountFlow(accountUuid) - .map { latestAccount -> - AccountContainer(latestAccount, latestAccount.folderDisplayMode) - } - .distinctUntilChanged() - .flatMapLatest { (account, folderDisplayMode) -> - getDisplayFoldersFlow(account, folderDisplayMode) - } - } - fun getFolder(account: Account, folderId: Long): Folder? { val messageStore = messageStoreManager.getMessageStore(account) return messageStore.getFolder(folderId) { folder -> @@ -259,28 +187,6 @@ class FolderRepository( messageStore.setNotificationsEnabled(folderId, enable) } - private fun folderTypeOf(account: Account, folderId: Long) = when (folderId) { - account.inboxFolderId -> FolderType.INBOX - account.outboxFolderId -> FolderType.OUTBOX - account.sentFolderId -> FolderType.SENT - account.trashFolderId -> FolderType.TRASH - account.draftsFolderId -> FolderType.DRAFTS - account.archiveFolderId -> FolderType.ARCHIVE - account.spamFolderId -> FolderType.SPAM - else -> FolderType.REGULAR - } - - private fun RemoteFolderType.toFolderType(): FolderType = when (this) { - RemoteFolderType.REGULAR -> FolderType.REGULAR - RemoteFolderType.INBOX -> FolderType.INBOX - RemoteFolderType.OUTBOX -> FolderType.REGULAR // We currently don't support remote Outbox folders - RemoteFolderType.DRAFTS -> FolderType.DRAFTS - RemoteFolderType.SENT -> FolderType.SENT - RemoteFolderType.TRASH -> FolderType.TRASH - RemoteFolderType.SPAM -> FolderType.SPAM - RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE - } - private fun Account.getFolderPushModeFlow(): Flow { return accountManager.getAccountFlow(uuid).map { it.folderPushMode } } @@ -292,11 +198,6 @@ class FolderRepository( get() = if (syncClass == FolderClass.INHERITED) displayClass else syncClass } -private data class AccountContainer( - val account: Account, - val folderDisplayMode: FolderMode, -) - data class RemoteFolderDetails( val folder: RemoteFolder, val isInTopGroup: Boolean, diff --git a/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderTypeMapper.kt b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderTypeMapper.kt new file mode 100644 index 0000000000..4b18f79f12 --- /dev/null +++ b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/FolderTypeMapper.kt @@ -0,0 +1,18 @@ +package app.k9mail.legacy.mailstore + +import app.k9mail.core.mail.folder.api.FolderType +import app.k9mail.legacy.account.Account + +object FolderTypeMapper { + + fun folderTypeOf(account: Account, folderId: Long) = when (folderId) { + account.inboxFolderId -> FolderType.INBOX + account.outboxFolderId -> FolderType.OUTBOX + account.sentFolderId -> FolderType.SENT + account.trashFolderId -> FolderType.TRASH + account.draftsFolderId -> FolderType.DRAFTS + account.archiveFolderId -> FolderType.ARCHIVE + account.spamFolderId -> FolderType.SPAM + else -> FolderType.REGULAR + } +} diff --git a/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/RemoteFolderTypeMapper.kt b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/RemoteFolderTypeMapper.kt new file mode 100644 index 0000000000..cfc3424c70 --- /dev/null +++ b/legacy/mailstore/src/main/java/app/k9mail/legacy/mailstore/RemoteFolderTypeMapper.kt @@ -0,0 +1,18 @@ +package app.k9mail.legacy.mailstore + +import app.k9mail.core.mail.folder.api.FolderType +import com.fsck.k9.mail.FolderType as RemoteFolderType + +object RemoteFolderTypeMapper { + + fun RemoteFolderType.toFolderType(): FolderType = when (this) { + RemoteFolderType.REGULAR -> FolderType.REGULAR + RemoteFolderType.INBOX -> FolderType.INBOX + RemoteFolderType.OUTBOX -> FolderType.REGULAR // We currently don't support remote Outbox folders + RemoteFolderType.DRAFTS -> FolderType.DRAFTS + RemoteFolderType.SENT -> FolderType.SENT + RemoteFolderType.TRASH -> FolderType.TRASH + RemoteFolderType.SPAM -> FolderType.SPAM + RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE + } +} diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt index bb438f713d..f023b0be25 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt @@ -7,14 +7,16 @@ import androidx.lifecycle.viewModelScope import app.k9mail.legacy.account.Account import app.k9mail.legacy.account.Account.FolderMode import app.k9mail.legacy.folder.DisplayFolder -import app.k9mail.legacy.mailstore.FolderRepository +import app.k9mail.legacy.mailstore.DisplayFolderRepository import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.launch @OptIn(ExperimentalCoroutinesApi::class) -class ChooseFolderViewModel(private val folderRepository: FolderRepository) : ViewModel() { +class ChooseFolderViewModel( + private val folderRepository: DisplayFolderRepository, +) : ViewModel() { private val inputFlow = MutableSharedFlow(replay = 1) private val foldersFlow = inputFlow .flatMapLatest { (account, displayMode) -> diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt index 475e00f976..87e2b67b2c 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt @@ -5,9 +5,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import app.k9mail.legacy.account.Account import app.k9mail.legacy.folder.DisplayFolder -import app.k9mail.legacy.mailstore.FolderRepository +import app.k9mail.legacy.mailstore.DisplayFolderRepository -class ManageFoldersViewModel(private val folderRepository: FolderRepository) : ViewModel() { +class ManageFoldersViewModel( + private val folderRepository: DisplayFolderRepository, +) : ViewModel() { fun getFolders(account: Account): LiveData> { return folderRepository.getDisplayFoldersFlow(account.uuid).asLiveData() }