Add FolderRepository.getPushFoldersFlow()
This method returns a flow that emits the list of folders to sync via Push. It will automatically update when the account's 'Push folders' setting or a folder's Push class is changed.
This commit is contained in:
parent
3b2a8adb1c
commit
6862b737ed
11 changed files with 184 additions and 15 deletions
|
@ -233,11 +233,11 @@ class Preferences internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun addOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener) {
|
||||
override fun addOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener) {
|
||||
accountsChangeListeners.add(accountsChangeListener)
|
||||
}
|
||||
|
||||
fun removeOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener) {
|
||||
override fun removeOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener) {
|
||||
accountsChangeListeners.remove(accountsChangeListener)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,29 @@ package com.fsck.k9.mailstore
|
|||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Account.FolderMode
|
||||
import com.fsck.k9.AccountsChangeListener
|
||||
import com.fsck.k9.mail.FolderClass
|
||||
import com.fsck.k9.preferences.AccountManager
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
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.launch
|
||||
import com.fsck.k9.mail.FolderType as RemoteFolderType
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class FolderRepository(
|
||||
private val messageStoreManager: MessageStoreManager,
|
||||
private val account: Account
|
||||
private val accountManager: AccountManager,
|
||||
private val account: Account,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) {
|
||||
private val sortForDisplay =
|
||||
compareByDescending<DisplayFolder> { it.folder.type == FolderType.INBOX }
|
||||
|
@ -99,6 +116,54 @@ class FolderRepository(
|
|||
}
|
||||
}
|
||||
|
||||
fun getPushFoldersFlow(): Flow<List<RemoteFolder>> {
|
||||
return account.getFolderPushModeFlow()
|
||||
.flatMapLatest { pushMode ->
|
||||
getPushFoldersFlow(pushMode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPushFoldersFlow(folderMode: FolderMode): Flow<List<RemoteFolder>> {
|
||||
val messageStore = messageStoreManager.getMessageStore(account)
|
||||
return callbackFlow {
|
||||
send(getPushFolders(folderMode))
|
||||
|
||||
val listener = FolderSettingsChangedListener {
|
||||
launch {
|
||||
send(getPushFolders(folderMode))
|
||||
}
|
||||
}
|
||||
messageStore.addFolderSettingsChangedListener(listener)
|
||||
|
||||
awaitClose {
|
||||
messageStore.removeFolderSettingsChangedListener(listener)
|
||||
}
|
||||
}.buffer(capacity = Channel.CONFLATED)
|
||||
.distinctUntilChanged()
|
||||
.flowOn(ioDispatcher)
|
||||
}
|
||||
|
||||
private fun getPushFolders(folderMode: FolderMode): List<RemoteFolder> {
|
||||
if (folderMode == FolderMode.NONE) return emptyList()
|
||||
|
||||
return getRemoteFolderDetails()
|
||||
.asSequence()
|
||||
.filter { folderDetails ->
|
||||
val pushClass = folderDetails.effectivePushClass
|
||||
when (folderMode) {
|
||||
FolderMode.NONE -> false
|
||||
FolderMode.ALL -> true
|
||||
FolderMode.FIRST_CLASS -> pushClass == FolderClass.FIRST_CLASS
|
||||
FolderMode.FIRST_AND_SECOND_CLASS -> {
|
||||
pushClass == FolderClass.FIRST_CLASS || pushClass == FolderClass.SECOND_CLASS
|
||||
}
|
||||
FolderMode.NOT_SECOND_CLASS -> pushClass != FolderClass.SECOND_CLASS
|
||||
}
|
||||
}
|
||||
.map { folderDetails -> folderDetails.folder }
|
||||
.toList()
|
||||
}
|
||||
|
||||
fun getFolderServerId(folderId: Long): String? {
|
||||
val messageStore = messageStoreManager.getMessageStore(account)
|
||||
return messageStore.getFolder(folderId) { folder ->
|
||||
|
@ -162,6 +227,31 @@ class FolderRepository(
|
|||
RemoteFolderType.SPAM -> FolderType.SPAM
|
||||
RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE
|
||||
}
|
||||
|
||||
private fun Account.getFolderPushModeFlow(): Flow<FolderMode> {
|
||||
val account = this@getFolderPushModeFlow
|
||||
return callbackFlow {
|
||||
send(account.folderPushMode)
|
||||
|
||||
val listener = AccountsChangeListener {
|
||||
launch {
|
||||
send(account.folderPushMode)
|
||||
}
|
||||
}
|
||||
accountManager.addOnAccountsChangeListener(listener)
|
||||
|
||||
awaitClose {
|
||||
accountManager.removeOnAccountsChangeListener(listener)
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
.flowOn(ioDispatcher)
|
||||
}
|
||||
|
||||
private val RemoteFolderDetails.effectivePushClass: FolderClass
|
||||
get() = if (pushClass == FolderClass.INHERITED) effectiveSyncClass else pushClass
|
||||
|
||||
private val RemoteFolderDetails.effectiveSyncClass: FolderClass
|
||||
get() = if (syncClass == FolderClass.INHERITED) displayClass else syncClass
|
||||
}
|
||||
|
||||
data class Folder(val id: Long, val name: String, val type: FolderType, val isLocalOnly: Boolean)
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package com.fsck.k9.mailstore
|
||||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.preferences.AccountManager
|
||||
|
||||
class FolderRepositoryManager(private val messageStoreManager: MessageStoreManager) {
|
||||
fun getFolderRepository(account: Account) = FolderRepository(messageStoreManager, account)
|
||||
class FolderRepositoryManager(
|
||||
private val messageStoreManager: MessageStoreManager,
|
||||
private val accountManager: AccountManager
|
||||
) {
|
||||
fun getFolderRepository(account: Account): FolderRepository {
|
||||
return FolderRepository(messageStoreManager, accountManager, account)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.fsck.k9.message.extractors.MessagePreviewCreator
|
|||
import org.koin.dsl.module
|
||||
|
||||
val mailStoreModule = module {
|
||||
single { FolderRepositoryManager(messageStoreManager = get()) }
|
||||
single { FolderRepositoryManager(messageStoreManager = get(), accountManager = get()) }
|
||||
single { MessageViewInfoExtractorFactory(get(), get(), get()) }
|
||||
single { StorageManager.getInstance(get()) }
|
||||
single { SearchStatusManager() }
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package com.fsck.k9.mailstore
|
||||
|
||||
import com.fsck.k9.mail.FolderClass
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
|
||||
class ListenableMessageStore(private val messageStore: MessageStore) : MessageStore by messageStore {
|
||||
private val folderSettingsListener = CopyOnWriteArraySet<FolderSettingsChangedListener>()
|
||||
|
||||
override fun createFolders(folders: List<CreateFolderInfo>) {
|
||||
messageStore.createFolders(folders)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun deleteFolders(folderServerIds: List<String>) {
|
||||
messageStore.deleteFolders(folderServerIds)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun updateFolderSettings(folderDetails: FolderDetails) {
|
||||
messageStore.updateFolderSettings(folderDetails)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun setIncludeInUnifiedInbox(folderId: Long, includeInUnifiedInbox: Boolean) {
|
||||
messageStore.setIncludeInUnifiedInbox(folderId, includeInUnifiedInbox)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun setDisplayClass(folderId: Long, folderClass: FolderClass) {
|
||||
messageStore.setDisplayClass(folderId, folderClass)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun setSyncClass(folderId: Long, folderClass: FolderClass) {
|
||||
messageStore.setSyncClass(folderId, folderClass)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
override fun setNotificationClass(folderId: Long, folderClass: FolderClass) {
|
||||
messageStore.setNotificationClass(folderId, folderClass)
|
||||
notifyFolderSettingsChanged()
|
||||
}
|
||||
|
||||
fun addFolderSettingsChangedListener(listener: FolderSettingsChangedListener) {
|
||||
folderSettingsListener.add(listener)
|
||||
}
|
||||
|
||||
fun removeFolderSettingsChangedListener(listener: FolderSettingsChangedListener) {
|
||||
folderSettingsListener.remove(listener)
|
||||
}
|
||||
|
||||
private fun notifyFolderSettingsChanged() {
|
||||
for (listener in folderSettingsListener) {
|
||||
listener.onFolderSettingsChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun interface FolderSettingsChangedListener {
|
||||
fun onFolderSettingsChanged()
|
||||
}
|
|
@ -3,5 +3,5 @@ package com.fsck.k9.mailstore
|
|||
import com.fsck.k9.Account
|
||||
|
||||
interface MessageStoreFactory {
|
||||
fun create(account: Account): MessageStore
|
||||
fun create(account: Account): ListenableMessageStore
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import com.fsck.k9.preferences.AccountManager
|
|||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class MessageStoreManager(private val accountManager: AccountManager, private val messageStoreFactory: MessageStoreFactory) {
|
||||
private val messageStores = ConcurrentHashMap<String, MessageStore>()
|
||||
private val messageStores = ConcurrentHashMap<String, ListenableMessageStore>()
|
||||
|
||||
init {
|
||||
accountManager.addAccountRemovedListener { account ->
|
||||
|
@ -13,12 +13,12 @@ class MessageStoreManager(private val accountManager: AccountManager, private va
|
|||
}
|
||||
}
|
||||
|
||||
fun getMessageStore(accountUuid: String): MessageStore {
|
||||
fun getMessageStore(accountUuid: String): ListenableMessageStore {
|
||||
val account = accountManager.getAccount(accountUuid) ?: error("Account not found: $accountUuid")
|
||||
return getMessageStore(account)
|
||||
}
|
||||
|
||||
fun getMessageStore(account: Account): MessageStore {
|
||||
fun getMessageStore(account: Account): ListenableMessageStore {
|
||||
return messageStores.getOrPut(account.uuid) { messageStoreFactory.create(account) }
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,12 @@ package com.fsck.k9.preferences
|
|||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.AccountRemovedListener
|
||||
import com.fsck.k9.AccountsChangeListener
|
||||
|
||||
interface AccountManager {
|
||||
fun getAccount(accountUuid: String): Account?
|
||||
fun addAccountRemovedListener(listener: AccountRemovedListener)
|
||||
fun moveAccount(account: Account, newPosition: Int)
|
||||
fun addOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener)
|
||||
fun removeOnAccountsChangeListener(accountsChangeListener: AccountsChangeListener)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ import org.mockito.kotlin.whenever
|
|||
|
||||
class MessageStoreManagerTest {
|
||||
private val account = Account("00000000-0000-4000-0000-000000000000")
|
||||
private val messageStore1 = mock<MessageStore>(name = "messageStore1")
|
||||
private val messageStore2 = mock<MessageStore>(name = "messageStore2")
|
||||
private val messageStore1 = mock<ListenableMessageStore>(name = "messageStore1")
|
||||
private val messageStore2 = mock<ListenableMessageStore>(name = "messageStore2")
|
||||
private val messageStoreFactory = mock<MessageStoreFactory> {
|
||||
on { create(account) } doReturn messageStore1 doReturn messageStore2
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.fsck.k9.storage.messages
|
||||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.mailstore.ListenableMessageStore
|
||||
import com.fsck.k9.mailstore.LocalStoreProvider
|
||||
import com.fsck.k9.mailstore.MessageStore
|
||||
import com.fsck.k9.mailstore.MessageStoreFactory
|
||||
import com.fsck.k9.mailstore.NotifierMessageStore
|
||||
import com.fsck.k9.mailstore.StorageManager
|
||||
|
@ -13,9 +13,10 @@ class K9MessageStoreFactory(
|
|||
private val storageManager: StorageManager,
|
||||
private val basicPartInfoExtractor: BasicPartInfoExtractor
|
||||
) : MessageStoreFactory {
|
||||
override fun create(account: Account): MessageStore {
|
||||
override fun create(account: Account): ListenableMessageStore {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val messageStore = K9MessageStore(localStore.database, storageManager, basicPartInfoExtractor, account.uuid)
|
||||
return NotifierMessageStore(messageStore, localStore)
|
||||
val notifierMessageStore = NotifierMessageStore(messageStore, localStore)
|
||||
return ListenableMessageStore(notifierMessageStore)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildConfig = [
|
||||
|
@ -86,6 +88,12 @@ subprojects {
|
|||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile) {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'org.jlleitschuh.gradle.ktlint'
|
||||
ktlint {
|
||||
version = versions.ktlint
|
||||
|
|
Loading…
Reference in a new issue