Loading app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt +27 −52 Original line number Diff line number Diff line Loading @@ -2,10 +2,8 @@ package com.fsck.k9.mailstore import android.database.sqlite.SQLiteDatabase import androidx.core.content.contentValuesOf import androidx.core.database.getStringOrNull import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode import com.fsck.k9.helper.map import com.fsck.k9.mail.FolderClass import com.fsck.k9.mail.FolderType as RemoteFolderType Loading @@ -21,13 +19,6 @@ class FolderRepository( .thenByDescending { it.isInTopGroup } .thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name } fun getRemoteFolders(): List<RemoteFolder> { val folders = localStoreProvider.getInstance(account).getPersonalNamespaces(false) return folders .filterNot { it.isLocalOnly } .map { RemoteFolder(it.databaseId, it.serverId, it.name, it.type.toFolderType()) } } fun getDisplayFolders(displayMode: FolderMode?): List<DisplayFolder> { val database = localStoreProvider.getInstance(account).database val displayFolders = database.execute(false) { db -> Loading Loading @@ -70,49 +61,37 @@ class FolderRepository( } } fun getRemoteFolders(): List<RemoteFolder> { val messageStore = messageStoreManager.getMessageStore(account) return messageStore.getFolders(excludeLocalOnly = true) { folder -> RemoteFolder( id = folder.id, serverId = folder.serverId, name = folder.name, type = folder.type.toFolderType() ) } } fun getRemoteFolderDetails(): List<RemoteFolderDetails> { val database = localStoreProvider.getInstance(account).database return database.execute(false) { db -> db.query( "folders", arrayOf( "id", "server_id", "name", "type", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" ), "local_only = 0", null, null, null, null ).use { cursor -> cursor.map { val id = cursor.getLong(0) val messageStore = messageStoreManager.getMessageStore(account) return messageStore.getFolders(excludeLocalOnly = true) { folder -> RemoteFolderDetails( folder = RemoteFolder( id = id, serverId = cursor.getString(1), name = cursor.getString(2), type = cursor.getString(3).toFolderType().toFolderType() id = folder.id, serverId = folder.serverId, name = folder.name, type = folder.type.toFolderType() ), isInTopGroup = cursor.getInt(4) == 1, isIntegrate = cursor.getInt(5) == 1, syncClass = cursor.getStringOrNull(6).toFolderClass(), displayClass = cursor.getStringOrNull(7).toFolderClass(), notifyClass = cursor.getStringOrNull(8).toFolderClass(), pushClass = cursor.getStringOrNull(9).toFolderClass() isInTopGroup = folder.isInTopGroup, isIntegrate = folder.isIntegrate, syncClass = folder.syncClass, displayClass = folder.displayClass, notifyClass = folder.notifyClass, pushClass = folder.pushClass ) } } } } fun getFolderServerId(folderId: Long): String? { val messageStore = messageStoreManager.getMessageStore(account) Loading Loading @@ -239,10 +218,6 @@ class FolderRepository( RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE } private fun String?.toFolderClass(): FolderClass { return this?.let { FolderClass.valueOf(this) } ?: FolderClass.NO_CLASS } fun setIncludeInUnifiedInbox(folderId: Long, includeInUnifiedInbox: Boolean) { val localStore = localStoreProvider.getInstance(account) val folder = localStore.getFolder(folderId) Loading app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt +8 −0 Original line number Diff line number Diff line Loading @@ -60,4 +60,12 @@ interface MessageStore { * @return The value returned by [mapper] or `null` if the folder wasn't found. */ fun <T> getFolder(folderId: Long, mapper: FolderMapper<T>): T? /** * Retrieve folders. * * @param mapper A function to map the values read from the store to a domain-specific object. * @return A list of values returned by [mapper]. */ fun <T> getFolders(excludeLocalOnly: Boolean, mapper: FolderMapper<T>): List<T> } app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt +4 −0 Original line number Diff line number Diff line Loading @@ -42,4 +42,8 @@ class K9MessageStore(private val localStore: LocalStore) : MessageStore { override fun <T> getFolder(folderId: Long, mapper: FolderMapper<T>): T? { return retrieveFolderOperations.getFolder(folderId, mapper) } override fun <T> getFolders(excludeLocalOnly: Boolean, mapper: FolderMapper<T>): List<T> { return retrieveFolderOperations.getFolders(excludeLocalOnly, mapper) } } app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt +28 −13 Original line number Diff line number Diff line package com.fsck.k9.storage.messages import android.database.Cursor import com.fsck.k9.helper.map import com.fsck.k9.mail.FolderClass import com.fsck.k9.mail.FolderType import com.fsck.k9.mailstore.FolderDetailsAccessor Loading @@ -13,19 +14,7 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa return lockableDatabase.execute(false) { db -> db.query( "folders", arrayOf( "id", "name", "type", "server_id", "local_only", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" ), FOLDER_COLUMNS, "id = ?", arrayOf(folderId.toString()), null, Loading @@ -41,6 +30,18 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa } } } fun <T> getFolders(excludeLocalOnly: Boolean = false, mapper: FolderMapper<T>): List<T> { val selection = if (excludeLocalOnly) "local_only = 0" else null return lockableDatabase.execute(false) { db -> db.query("folders", FOLDER_COLUMNS, selection, null, null, null, "id").use { cursor -> val cursorFolderAccessor = CursorFolderAccessor(cursor) cursor.map { mapper.map(cursorFolderAccessor) } } } } } private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor { Loading Loading @@ -77,3 +78,17 @@ private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor { override val pushClass: FolderClass get() = FolderClass.valueOf(cursor.getString(10)) } private val FOLDER_COLUMNS = arrayOf( "id", "name", "type", "server_id", "local_only", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" ) app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt +56 −0 Original line number Diff line number Diff line Loading @@ -50,4 +50,60 @@ class RetrieveFolderOperationsTest : RobolectricTest() { assertThat(result).isNull() } @Test fun `get folders should return all fields`() { val folderId = sqliteDatabase.createFolder( name = "Folder Name", type = "inbox", serverId = "uid", isLocalOnly = false, integrate = true, inTopGroup = true, displayClass = "FIRST_CLASS", syncClass = "FIRST_CLASS", notifyClass = "NO_CLASS", pushClass = "NO_CLASS" ) val result = retrieveFolderOperations.getFolders { folder -> assertThat(folder.id).isEqualTo(folderId) assertThat(folder.name).isEqualTo("Folder Name") assertThat(folder.type).isEqualTo(FolderType.INBOX) assertThat(folder.serverId).isEqualTo("uid") assertThat(folder.isLocalOnly).isEqualTo(false) assertThat(folder.isIntegrate).isEqualTo(true) assertThat(folder.isInTopGroup).isEqualTo(true) assertThat(folder.displayClass).isEqualTo(FolderClass.FIRST_CLASS) assertThat(folder.syncClass).isEqualTo(FolderClass.FIRST_CLASS) assertThat(folder.notifyClass).isEqualTo(FolderClass.NO_CLASS) assertThat(folder.pushClass).isEqualTo(FolderClass.NO_CLASS) true } assertThat(result).isEqualTo(listOf(true)) } @Test fun `get folders with excludeLocalOnly should only return remote folders`() { val (folderId1, _, folderId3) = listOf( sqliteDatabase.createFolder(name = "Folder 1", isLocalOnly = false), sqliteDatabase.createFolder(name = "Folder 2", isLocalOnly = true), sqliteDatabase.createFolder(name = "Folder 3", isLocalOnly = false) ) val result = retrieveFolderOperations.getFolders(excludeLocalOnly = true) { folder -> folder.id to folder.name } assertThat(result.map { it.first }).isEqualTo(listOf(folderId1, folderId3)) assertThat(result.map { it.second }).isEqualTo(listOf("Folder 1", "Folder 3")) } @Test fun `get folders with empty store should return empty list`() { val result = retrieveFolderOperations.getFolders { "failed" } assertThat(result).isEmpty() } } Loading
app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt +27 −52 Original line number Diff line number Diff line Loading @@ -2,10 +2,8 @@ package com.fsck.k9.mailstore import android.database.sqlite.SQLiteDatabase import androidx.core.content.contentValuesOf import androidx.core.database.getStringOrNull import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode import com.fsck.k9.helper.map import com.fsck.k9.mail.FolderClass import com.fsck.k9.mail.FolderType as RemoteFolderType Loading @@ -21,13 +19,6 @@ class FolderRepository( .thenByDescending { it.isInTopGroup } .thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name } fun getRemoteFolders(): List<RemoteFolder> { val folders = localStoreProvider.getInstance(account).getPersonalNamespaces(false) return folders .filterNot { it.isLocalOnly } .map { RemoteFolder(it.databaseId, it.serverId, it.name, it.type.toFolderType()) } } fun getDisplayFolders(displayMode: FolderMode?): List<DisplayFolder> { val database = localStoreProvider.getInstance(account).database val displayFolders = database.execute(false) { db -> Loading Loading @@ -70,49 +61,37 @@ class FolderRepository( } } fun getRemoteFolders(): List<RemoteFolder> { val messageStore = messageStoreManager.getMessageStore(account) return messageStore.getFolders(excludeLocalOnly = true) { folder -> RemoteFolder( id = folder.id, serverId = folder.serverId, name = folder.name, type = folder.type.toFolderType() ) } } fun getRemoteFolderDetails(): List<RemoteFolderDetails> { val database = localStoreProvider.getInstance(account).database return database.execute(false) { db -> db.query( "folders", arrayOf( "id", "server_id", "name", "type", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" ), "local_only = 0", null, null, null, null ).use { cursor -> cursor.map { val id = cursor.getLong(0) val messageStore = messageStoreManager.getMessageStore(account) return messageStore.getFolders(excludeLocalOnly = true) { folder -> RemoteFolderDetails( folder = RemoteFolder( id = id, serverId = cursor.getString(1), name = cursor.getString(2), type = cursor.getString(3).toFolderType().toFolderType() id = folder.id, serverId = folder.serverId, name = folder.name, type = folder.type.toFolderType() ), isInTopGroup = cursor.getInt(4) == 1, isIntegrate = cursor.getInt(5) == 1, syncClass = cursor.getStringOrNull(6).toFolderClass(), displayClass = cursor.getStringOrNull(7).toFolderClass(), notifyClass = cursor.getStringOrNull(8).toFolderClass(), pushClass = cursor.getStringOrNull(9).toFolderClass() isInTopGroup = folder.isInTopGroup, isIntegrate = folder.isIntegrate, syncClass = folder.syncClass, displayClass = folder.displayClass, notifyClass = folder.notifyClass, pushClass = folder.pushClass ) } } } } fun getFolderServerId(folderId: Long): String? { val messageStore = messageStoreManager.getMessageStore(account) Loading Loading @@ -239,10 +218,6 @@ class FolderRepository( RemoteFolderType.ARCHIVE -> FolderType.ARCHIVE } private fun String?.toFolderClass(): FolderClass { return this?.let { FolderClass.valueOf(this) } ?: FolderClass.NO_CLASS } fun setIncludeInUnifiedInbox(folderId: Long, includeInUnifiedInbox: Boolean) { val localStore = localStoreProvider.getInstance(account) val folder = localStore.getFolder(folderId) Loading
app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt +8 −0 Original line number Diff line number Diff line Loading @@ -60,4 +60,12 @@ interface MessageStore { * @return The value returned by [mapper] or `null` if the folder wasn't found. */ fun <T> getFolder(folderId: Long, mapper: FolderMapper<T>): T? /** * Retrieve folders. * * @param mapper A function to map the values read from the store to a domain-specific object. * @return A list of values returned by [mapper]. */ fun <T> getFolders(excludeLocalOnly: Boolean, mapper: FolderMapper<T>): List<T> }
app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt +4 −0 Original line number Diff line number Diff line Loading @@ -42,4 +42,8 @@ class K9MessageStore(private val localStore: LocalStore) : MessageStore { override fun <T> getFolder(folderId: Long, mapper: FolderMapper<T>): T? { return retrieveFolderOperations.getFolder(folderId, mapper) } override fun <T> getFolders(excludeLocalOnly: Boolean, mapper: FolderMapper<T>): List<T> { return retrieveFolderOperations.getFolders(excludeLocalOnly, mapper) } }
app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt +28 −13 Original line number Diff line number Diff line package com.fsck.k9.storage.messages import android.database.Cursor import com.fsck.k9.helper.map import com.fsck.k9.mail.FolderClass import com.fsck.k9.mail.FolderType import com.fsck.k9.mailstore.FolderDetailsAccessor Loading @@ -13,19 +14,7 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa return lockableDatabase.execute(false) { db -> db.query( "folders", arrayOf( "id", "name", "type", "server_id", "local_only", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" ), FOLDER_COLUMNS, "id = ?", arrayOf(folderId.toString()), null, Loading @@ -41,6 +30,18 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa } } } fun <T> getFolders(excludeLocalOnly: Boolean = false, mapper: FolderMapper<T>): List<T> { val selection = if (excludeLocalOnly) "local_only = 0" else null return lockableDatabase.execute(false) { db -> db.query("folders", FOLDER_COLUMNS, selection, null, null, null, "id").use { cursor -> val cursorFolderAccessor = CursorFolderAccessor(cursor) cursor.map { mapper.map(cursorFolderAccessor) } } } } } private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor { Loading Loading @@ -77,3 +78,17 @@ private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor { override val pushClass: FolderClass get() = FolderClass.valueOf(cursor.getString(10)) } private val FOLDER_COLUMNS = arrayOf( "id", "name", "type", "server_id", "local_only", "top_group", "integrate", "poll_class", "display_class", "notify_class", "push_class" )
app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt +56 −0 Original line number Diff line number Diff line Loading @@ -50,4 +50,60 @@ class RetrieveFolderOperationsTest : RobolectricTest() { assertThat(result).isNull() } @Test fun `get folders should return all fields`() { val folderId = sqliteDatabase.createFolder( name = "Folder Name", type = "inbox", serverId = "uid", isLocalOnly = false, integrate = true, inTopGroup = true, displayClass = "FIRST_CLASS", syncClass = "FIRST_CLASS", notifyClass = "NO_CLASS", pushClass = "NO_CLASS" ) val result = retrieveFolderOperations.getFolders { folder -> assertThat(folder.id).isEqualTo(folderId) assertThat(folder.name).isEqualTo("Folder Name") assertThat(folder.type).isEqualTo(FolderType.INBOX) assertThat(folder.serverId).isEqualTo("uid") assertThat(folder.isLocalOnly).isEqualTo(false) assertThat(folder.isIntegrate).isEqualTo(true) assertThat(folder.isInTopGroup).isEqualTo(true) assertThat(folder.displayClass).isEqualTo(FolderClass.FIRST_CLASS) assertThat(folder.syncClass).isEqualTo(FolderClass.FIRST_CLASS) assertThat(folder.notifyClass).isEqualTo(FolderClass.NO_CLASS) assertThat(folder.pushClass).isEqualTo(FolderClass.NO_CLASS) true } assertThat(result).isEqualTo(listOf(true)) } @Test fun `get folders with excludeLocalOnly should only return remote folders`() { val (folderId1, _, folderId3) = listOf( sqliteDatabase.createFolder(name = "Folder 1", isLocalOnly = false), sqliteDatabase.createFolder(name = "Folder 2", isLocalOnly = true), sqliteDatabase.createFolder(name = "Folder 3", isLocalOnly = false) ) val result = retrieveFolderOperations.getFolders(excludeLocalOnly = true) { folder -> folder.id to folder.name } assertThat(result.map { it.first }).isEqualTo(listOf(folderId1, folderId3)) assertThat(result.map { it.second }).isEqualTo(listOf("Folder 1", "Folder 3")) } @Test fun `get folders with empty store should return empty list`() { val result = retrieveFolderOperations.getFolders { "failed" } assertThat(result).isEmpty() } }