Merge pull request #4421 from k9mail/special_folders

Properly configure special folders during (initial) folder sync
This commit is contained in:
cketti 2020-01-08 00:39:46 +01:00 committed by GitHub
commit aaaf75dc6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 63 deletions

View file

@ -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,

View file

@ -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)
}

View file

@ -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)

View file

@ -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()) }
}

View file

@ -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,

View file

@ -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() {

View file

@ -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()) }

View file

@ -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

View file

@ -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?>)