Merge pull request #4421 from k9mail/special_folders
Properly configure special folders during (initial) folder sync
This commit is contained in:
commit
aaaf75dc6f
9 changed files with 91 additions and 63 deletions
|
@ -8,7 +8,6 @@ import com.fsck.k9.mail.Folder.FolderType as RemoteFolderType
|
|||
|
||||
class FolderRepository(
|
||||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy,
|
||||
private val account: Account
|
||||
) {
|
||||
private val sortForDisplay =
|
||||
|
@ -18,20 +17,7 @@ class FolderRepository(
|
|||
.thenByDescending { it.isInTopGroup }
|
||||
.thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name }
|
||||
|
||||
fun getRemoteFolderInfo(): RemoteFolderInfo {
|
||||
val folders = getRemoteFolders()
|
||||
val automaticSpecialFolders = mapOf(
|
||||
FolderType.ARCHIVE to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.ARCHIVE),
|
||||
FolderType.DRAFTS to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.DRAFTS),
|
||||
FolderType.SENT to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.SENT),
|
||||
FolderType.SPAM to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.SPAM),
|
||||
FolderType.TRASH to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.TRASH)
|
||||
)
|
||||
|
||||
return RemoteFolderInfo(folders, automaticSpecialFolders)
|
||||
}
|
||||
|
||||
private fun getRemoteFolders(): List<Folder> {
|
||||
fun getRemoteFolders(): List<Folder> {
|
||||
val folders = localStoreProvider.getInstance(account).getPersonalNamespaces(false)
|
||||
|
||||
return folders
|
||||
|
@ -127,6 +113,30 @@ class FolderRepository(
|
|||
RemoteFolderType.SPAM -> FolderType.SPAM
|
||||
RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE
|
||||
}
|
||||
|
||||
fun setIncludeInUnifiedInbox(serverId: String, includeInUnifiedInbox: Boolean) {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val folder = localStore.getFolder(serverId)
|
||||
folder.isIntegrate = includeInUnifiedInbox
|
||||
}
|
||||
|
||||
fun setDisplayClass(serverId: String, folderClass: FolderClass) {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val folder = localStore.getFolder(serverId)
|
||||
folder.displayClass = folderClass
|
||||
}
|
||||
|
||||
fun setSyncClass(serverId: String, folderClass: FolderClass) {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val folder = localStore.getFolder(serverId)
|
||||
folder.syncClass = folderClass
|
||||
}
|
||||
|
||||
fun setNotificationClass(serverId: String, folderClass: FolderClass) {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val folder = localStore.getFolder(serverId)
|
||||
folder.notifyClass = folderClass
|
||||
}
|
||||
}
|
||||
|
||||
data class Folder(val id: Long, val serverId: String, val name: String, val type: FolderType)
|
||||
|
@ -137,8 +147,6 @@ data class DisplayFolder(
|
|||
val unreadCount: Int
|
||||
)
|
||||
|
||||
data class RemoteFolderInfo(val folders: List<Folder>, val automaticSpecialFolders: Map<FolderType, Folder?>)
|
||||
|
||||
enum class FolderType {
|
||||
REGULAR,
|
||||
INBOX,
|
||||
|
|
|
@ -6,5 +6,5 @@ class FolderRepositoryManager(
|
|||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy
|
||||
) {
|
||||
fun getFolderRepository(account: Account) = FolderRepository(localStoreProvider, specialFolderSelectionStrategy, account)
|
||||
fun getFolderRepository(account: Account) = FolderRepository(localStoreProvider, account)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,18 @@ import com.fsck.k9.Preferences
|
|||
class K9BackendStorageFactory(
|
||||
private val preferences: Preferences,
|
||||
private val folderRepositoryManager: FolderRepositoryManager,
|
||||
private val localStoreProvider: LocalStoreProvider
|
||||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy
|
||||
) {
|
||||
fun createBackendStorage(account: Account): K9BackendStorage {
|
||||
val folderRepository = folderRepositoryManager.getFolderRepository(account)
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val specialFolderUpdater = SpecialFolderUpdater(preferences, folderRepository, account)
|
||||
val specialFolderUpdater = SpecialFolderUpdater(
|
||||
preferences,
|
||||
folderRepository,
|
||||
specialFolderSelectionStrategy,
|
||||
account
|
||||
)
|
||||
val specialFolderListener = SpecialFolderBackendStorageListener(specialFolderUpdater)
|
||||
val autoExpandFolderListener = AutoExpandFolderBackendStorageListener(preferences, account)
|
||||
val listeners = listOf(specialFolderListener, autoExpandFolderListener)
|
||||
|
|
|
@ -8,5 +8,5 @@ val mailStoreModule = module {
|
|||
single { StorageManager.getInstance(get()) }
|
||||
single { SearchStatusManager() }
|
||||
single { SpecialFolderSelectionStrategy() }
|
||||
single { K9BackendStorageFactory(get(), get(), get()) }
|
||||
single { K9BackendStorageFactory(get(), get(), get(), get()) }
|
||||
}
|
||||
|
|
|
@ -914,29 +914,6 @@ public class LocalStore {
|
|||
}
|
||||
|
||||
final LocalFolder.PreferencesHolder prefHolder = folder.new PreferencesHolder();
|
||||
|
||||
// When created, special folders should always be displayed
|
||||
// inbox should be integrated
|
||||
// and the inbox and drafts folders should be syncced by default
|
||||
if (account.isSpecialFolder(serverId)) {
|
||||
prefHolder.inTopGroup = true;
|
||||
prefHolder.displayClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
if (serverId.equals(account.getInboxFolder())) {
|
||||
prefHolder.integrate = true;
|
||||
prefHolder.notifyClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
prefHolder.pushClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
} else {
|
||||
prefHolder.pushClass = LocalFolder.FolderClass.INHERITED;
|
||||
|
||||
}
|
||||
if (serverId.equals(account.getInboxFolder()) || serverId.equals(account.getDraftsFolder())) {
|
||||
prefHolder.syncClass = LocalFolder.FolderClass.FIRST_CLASS;
|
||||
} else {
|
||||
prefHolder.syncClass = LocalFolder.FolderClass.NO_CLASS;
|
||||
}
|
||||
}
|
||||
folder.refresh(serverId, prefHolder); // Recover settings from Preferences
|
||||
|
||||
db.execSQL("INSERT INTO folders (name, visible_limit, top_group, display_class, poll_class, notify_class, push_class, integrate, server_id, local_only, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", new Object[] {
|
||||
name,
|
||||
visibleLimit,
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.fsck.k9.mailstore
|
|||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Account.SpecialFolderSelection
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.mail.Folder.FolderClass
|
||||
|
||||
/**
|
||||
* Updates special folders in [Account] if they are marked as [SpecialFolderSelection.AUTOMATIC] or if they are marked
|
||||
|
@ -11,33 +12,46 @@ import com.fsck.k9.Preferences
|
|||
class SpecialFolderUpdater(
|
||||
private val preferences: Preferences,
|
||||
private val folderRepository: FolderRepository,
|
||||
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy,
|
||||
private val account: Account
|
||||
) {
|
||||
fun updateSpecialFolders() {
|
||||
val (folders, automaticSpecialFolders) = folderRepository.getRemoteFolderInfo()
|
||||
val folders = folderRepository.getRemoteFolders()
|
||||
|
||||
updateInbox(folders)
|
||||
updateSpecialFolder(FolderType.ARCHIVE, folders, automaticSpecialFolders)
|
||||
updateSpecialFolder(FolderType.DRAFTS, folders, automaticSpecialFolders)
|
||||
updateSpecialFolder(FolderType.SENT, folders, automaticSpecialFolders)
|
||||
updateSpecialFolder(FolderType.SPAM, folders, automaticSpecialFolders)
|
||||
updateSpecialFolder(FolderType.TRASH, folders, automaticSpecialFolders)
|
||||
updateSpecialFolder(FolderType.ARCHIVE, folders)
|
||||
updateSpecialFolder(FolderType.DRAFTS, folders)
|
||||
updateSpecialFolder(FolderType.SENT, folders)
|
||||
updateSpecialFolder(FolderType.SPAM, folders)
|
||||
updateSpecialFolder(FolderType.TRASH, folders)
|
||||
|
||||
saveAccount()
|
||||
}
|
||||
|
||||
private fun updateInbox(folders: List<Folder>) {
|
||||
account.inboxFolder = folders.firstOrNull { it.type == FolderType.INBOX }?.serverId
|
||||
val oldInboxServerId = account.inboxFolder
|
||||
val newInboxServerId = folders.firstOrNull { it.type == FolderType.INBOX }?.serverId
|
||||
if (newInboxServerId == oldInboxServerId) return
|
||||
|
||||
account.inboxFolder = newInboxServerId
|
||||
|
||||
if (oldInboxServerId != null && folders.any { it.serverId == oldInboxServerId }) {
|
||||
folderRepository.setIncludeInUnifiedInbox(oldInboxServerId, false)
|
||||
}
|
||||
|
||||
if (newInboxServerId != null) {
|
||||
folderRepository.setIncludeInUnifiedInbox(newInboxServerId, true)
|
||||
folderRepository.setDisplayClass(newInboxServerId, FolderClass.FIRST_CLASS)
|
||||
folderRepository.setSyncClass(newInboxServerId, FolderClass.FIRST_CLASS)
|
||||
folderRepository.setNotificationClass(newInboxServerId, FolderClass.FIRST_CLASS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSpecialFolder(
|
||||
type: FolderType,
|
||||
folders: List<Folder>,
|
||||
automaticSpecialFolders: Map<FolderType, Folder?>
|
||||
) {
|
||||
private fun updateSpecialFolder(type: FolderType, folders: List<Folder>) {
|
||||
when (getSpecialFolderSelection(type)) {
|
||||
SpecialFolderSelection.AUTOMATIC -> {
|
||||
setSpecialFolder(type, automaticSpecialFolders[type]?.serverId, SpecialFolderSelection.AUTOMATIC)
|
||||
val specialFolder = specialFolderSelectionStrategy.selectSpecialFolder(folders, type)
|
||||
setSpecialFolder(type, specialFolder?.serverId, SpecialFolderSelection.AUTOMATIC)
|
||||
}
|
||||
SpecialFolderSelection.MANUAL -> {
|
||||
if (folders.none { it.serverId == getSpecialFolder(type) }) {
|
||||
|
@ -66,6 +80,8 @@ class SpecialFolderUpdater(
|
|||
}
|
||||
|
||||
private fun setSpecialFolder(type: FolderType, folder: String?, selection: SpecialFolderSelection) {
|
||||
if (getSpecialFolder(type) == folder) return
|
||||
|
||||
when (type) {
|
||||
FolderType.ARCHIVE -> account.setArchiveFolder(folder, selection)
|
||||
FolderType.DRAFTS -> account.setDraftsFolder(folder, selection)
|
||||
|
@ -74,6 +90,11 @@ class SpecialFolderUpdater(
|
|||
FolderType.TRASH -> account.setTrashFolder(folder, selection)
|
||||
else -> throw AssertionError("Unsupported: $type")
|
||||
}
|
||||
|
||||
if (folder != null) {
|
||||
folderRepository.setDisplayClass(folder, FolderClass.FIRST_CLASS)
|
||||
folderRepository.setSyncClass(folder, FolderClass.NO_CLASS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveAccount() {
|
||||
|
|
|
@ -23,7 +23,7 @@ val settingsUiModule = module {
|
|||
Executors.newSingleThreadExecutor(NamedThreadFactory("SaveSettings"))
|
||||
}
|
||||
|
||||
viewModel { AccountSettingsViewModel(get(), get()) }
|
||||
viewModel { AccountSettingsViewModel(get(), get(), get()) }
|
||||
single { AccountSettingsDataStoreFactory(get(), get(), get(named("SaveSettingsExecutorService"))) }
|
||||
|
||||
viewModel { SettingsExportViewModel(get(), get()) }
|
||||
|
|
|
@ -22,7 +22,6 @@ import com.fsck.k9.fragment.ConfirmationDialogFragment
|
|||
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
import com.fsck.k9.mailstore.RemoteFolderInfo
|
||||
import com.fsck.k9.ui.R
|
||||
import com.fsck.k9.ui.endtoend.AutocryptKeyTransferActivity
|
||||
import com.fsck.k9.ui.observe
|
||||
|
|
|
@ -5,8 +5,10 @@ import androidx.lifecycle.MutableLiveData
|
|||
import androidx.lifecycle.ViewModel
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderRepositoryManager
|
||||
import com.fsck.k9.mailstore.RemoteFolderInfo
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
import com.fsck.k9.mailstore.SpecialFolderSelectionStrategy
|
||||
import com.fsck.k9.ui.account.AccountsLiveData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
@ -15,9 +17,10 @@ import kotlinx.coroutines.withContext
|
|||
|
||||
class AccountSettingsViewModel(
|
||||
private val preferences: Preferences,
|
||||
private val folderRepositoryManager: FolderRepositoryManager
|
||||
private val folderRepositoryManager: FolderRepositoryManager,
|
||||
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy
|
||||
) : ViewModel() {
|
||||
public val accounts = AccountsLiveData(preferences)
|
||||
val accounts = AccountsLiveData(preferences)
|
||||
private val accountLiveData = MutableLiveData<Account>()
|
||||
private val foldersLiveData = MutableLiveData<RemoteFolderInfo>()
|
||||
|
||||
|
@ -58,8 +61,22 @@ class AccountSettingsViewModel(
|
|||
val folderRepository = folderRepositoryManager.getFolderRepository(account)
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
foldersLiveData.value = withContext(Dispatchers.IO) {
|
||||
folderRepository.getRemoteFolderInfo()
|
||||
val folders = folderRepository.getRemoteFolders()
|
||||
val automaticSpecialFolders = getAutomaticSpecialFolders(folders)
|
||||
RemoteFolderInfo(folders, automaticSpecialFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAutomaticSpecialFolders(folders: List<Folder>): Map<FolderType, Folder?> {
|
||||
return mapOf(
|
||||
FolderType.ARCHIVE to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.ARCHIVE),
|
||||
FolderType.DRAFTS to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.DRAFTS),
|
||||
FolderType.SENT to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.SENT),
|
||||
FolderType.SPAM to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.SPAM),
|
||||
FolderType.TRASH to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.TRASH)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class RemoteFolderInfo(val folders: List<Folder>, val automaticSpecialFolders: Map<FolderType, Folder?>)
|
||||
|
|
Loading…
Reference in a new issue