Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 923b0308 authored by cketti's avatar cketti
Browse files

Change K9BackendFolder.setMessageFlag() to use MessageStore

parent c20de077
Loading
Loading
Loading
Loading
+3 −82
Original line number Diff line number Diff line
@@ -12,9 +12,9 @@ import java.util.Date
import com.fsck.k9.mailstore.MoreMessages as StoreMoreMessages

class K9BackendFolder(
    private val localStore: LocalStore,
    localStore: LocalStore,
    private val messageStore: MessageStore,
    private val folderServerId: String
    folderServerId: String
) : BackendFolder {
    private val database = localStore.database
    private val databaseId: String
@@ -88,40 +88,7 @@ class K9BackendFolder(
    }

    override fun setMessageFlag(messageServerId: String, flag: Flag, value: Boolean) {
        when (flag) {
            Flag.DELETED -> database.setMessagesBoolean(messageServerId, "deleted", value)
            Flag.SEEN -> database.setMessagesBoolean(messageServerId, "read", value)
            Flag.FLAGGED -> database.setMessagesBoolean(messageServerId, "flagged", value)
            Flag.ANSWERED -> database.setMessagesBoolean(messageServerId, "answered", value)
            Flag.FORWARDED -> database.setMessagesBoolean(messageServerId, "forwarded", value)
            else -> {
                val flagsColumnValue = database.getString(
                    table = "messages",
                    column = "flags",
                    selection = "folder_id = ? AND uid = ?",
                    selectionArgs = *arrayOf(databaseId, messageServerId)
                ) ?: ""

                val flags = flagsColumnValue.split(',').toMutableSet()
                if (value) {
                    flags.add(flag.toString())
                } else {
                    flags.remove(flag.toString())
                }

                val serializedFlags = flags.joinToString(separator = ",")

                database.setString(
                    table = "messages",
                    column = "flags",
                    selection = "folder_id = ? AND uid = ?",
                    selectionArgs = *arrayOf(databaseId, messageServerId),
                    value = serializedFlags
                )
            }
        }

        localStore.notifyChange()
        messageStore.setMessageFlag(folderId, messageServerId, flag, value)
    }

    // TODO: Move implementation from LocalFolder to this class
@@ -220,52 +187,6 @@ class K9BackendFolder(
        }
    }

    private fun LockableDatabase.getString(
        table: String = "folders",
        column: String,
        selection: String = "id = ?",
        vararg selectionArgs: String = arrayOf(databaseId)
    ): String? {
        return execute(false) { db ->
            val cursor = db.query(table, arrayOf(column), selection, selectionArgs, null, null, null)
            cursor.use {
                if (it.moveToFirst()) {
                    it.getStringOrNull(0)
                } else {
                    throw IllegalStateException("Couldn't find value for column $table.$column")
                }
            }
        }
    }

    private fun LockableDatabase.setString(
        table: String = "folders",
        column: String,
        value: String?,
        selection: String = "id = ?",
        vararg selectionArgs: String = arrayOf(databaseId)
    ) {
        execute(false) { db ->
            val contentValues = ContentValues().apply {
                put(column, value)
            }
            db.update(table, contentValues, selection, selectionArgs)
        }
    }

    private fun LockableDatabase.setMessagesBoolean(
        messageServerId: String,
        column: String,
        value: Boolean
    ) {
        execute(false) { db ->
            val contentValues = ContentValues().apply {
                put(column, if (value) 1 else 0)
            }
            db.update("messages", contentValues, "folder_id = ? AND uid = ?", arrayOf(databaseId, messageServerId))
        }
    }

    private fun StoreMoreMessages.toMoreMessages(): MoreMessages = when (this) {
        StoreMoreMessages.UNKNOWN -> MoreMessages.UNKNOWN
        StoreMoreMessages.FALSE -> MoreMessages.FALSE
+5 −0
Original line number Diff line number Diff line
@@ -39,6 +39,11 @@ interface MessageStore {
     */
    fun setFlag(messageIds: Collection<Long>, flag: Flag, set: Boolean)

    /**
     * Set or remove a flag on a message.
     */
    fun setMessageFlag(folderId: Long, messageServerId: String, flag: Flag, set: Boolean)

    /**
     * Retrieve the server ID for a given message.
     */
+67 −0
Original line number Diff line number Diff line
package com.fsck.k9.storage.messages

import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import com.fsck.k9.mail.Flag
import com.fsck.k9.mailstore.LockableDatabase

@@ -18,6 +19,17 @@ internal class FlagMessageOperations(private val lockableDatabase: LockableDatab
        }
    }

    fun setMessageFlag(folderId: Long, messageServerId: String, flag: Flag, set: Boolean) {
        when (flag) {
            Flag.DELETED -> setBoolean(folderId, messageServerId, "deleted", set)
            Flag.SEEN -> setBoolean(folderId, messageServerId, "read", set)
            Flag.FLAGGED -> setBoolean(folderId, messageServerId, "flagged", set)
            Flag.ANSWERED -> setBoolean(folderId, messageServerId, "answered", set)
            Flag.FORWARDED -> setBoolean(folderId, messageServerId, "forwarded", set)
            else -> rebuildFlagsColumnValue(folderId, messageServerId, flag, set)
        }
    }

    private fun setSpecialFlags(messageIds: Collection<Long>, flag: Flag, set: Boolean) {
        val columnName = when (flag) {
            Flag.SEEN -> "read"
@@ -45,4 +57,59 @@ internal class FlagMessageOperations(private val lockableDatabase: LockableDatab
    private fun rebuildFlagsColumnValue(messageIds: Collection<Long>, flag: Flag, set: Boolean) {
        throw UnsupportedOperationException("not implemented")
    }

    private fun rebuildFlagsColumnValue(folderId: Long, messageServerId: String, flag: Flag, set: Boolean) {
        lockableDatabase.execute(true) { database ->
            val oldFlags = database.readFlagsColumn(folderId, messageServerId)

            val newFlags = if (set) oldFlags + flag else oldFlags - flag
            val newFlagsString = newFlags.joinToString(separator = ",")

            val values = ContentValues().apply {
                put("flags", newFlagsString)
            }

            database.update(
                "messages",
                values,
                "folder_id = ? AND uid = ?",
                arrayOf(folderId.toString(), messageServerId)
            )
        }
    }

    private fun SQLiteDatabase.readFlagsColumn(folderId: Long, messageServerId: String): Set<Flag> {
        return query(
            "messages",
            arrayOf("flags"),
            "folder_id = ? AND uid = ?",
            arrayOf(folderId.toString(), messageServerId),
            null,
            null,
            null
        ).use { cursor ->
            if (!cursor.moveToFirst()) error("Message not found $folderId:$messageServerId")

            if (!cursor.isNull(0)) {
                cursor.getString(0).split(',').map { flagString -> Flag.valueOf(flagString) }.toSet()
            } else {
                emptySet()
            }
        }
    }

    private fun setBoolean(folderId: Long, messageServerId: String, columnName: String, value: Boolean) {
        lockableDatabase.execute(false) { database ->
            val values = ContentValues().apply {
                put(columnName, if (value) 1 else 0)
            }

            database.update(
                "messages",
                values,
                "folder_id = ? AND uid = ?",
                arrayOf(folderId.toString(), messageServerId)
            )
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -44,6 +44,11 @@ class K9MessageStore(
        localStore.notifyChange()
    }

    override fun setMessageFlag(folderId: Long, messageServerId: String, flag: Flag, set: Boolean) {
        flagMessageOperations.setMessageFlag(folderId, messageServerId, flag, set)
        localStore.notifyChange()
    }

    override fun getMessageServerId(messageId: Long): String {
        return retrieveMessageOperations.getMessageServerId(messageId)
    }
+41 −0
Original line number Diff line number Diff line
@@ -53,4 +53,45 @@ class FlagMessageOperationsTest : RobolectricTest() {
        assertThat(otherMessages).hasSize(1)
        assertThat(otherMessages.all { it.read == 0 }).isTrue()
    }

    @Test
    fun `mark message as read`() {
        sqliteDatabase.createMessage(folderId = 1, uid = "uid1", read = false)

        flagMessageOperations.setMessageFlag(folderId = 1, messageServerId = "uid1", Flag.SEEN, true)

        val message = sqliteDatabase.readMessages().first()
        assertThat(message.read).isEqualTo(1)
    }

    @Test
    fun `mark message as unread`() {
        sqliteDatabase.createMessage(folderId = 1, uid = "uid1", read = true)

        flagMessageOperations.setMessageFlag(folderId = 1, messageServerId = "uid1", Flag.SEEN, false)

        val message = sqliteDatabase.readMessages().first()
        assertThat(message.read).isEqualTo(0)
    }

    @Test
    fun `mark message as X_DOWNLOADED_FULL`() {
        sqliteDatabase.createMessage(folderId = 1, uid = "uid1", flags = "X_SUBJECT_DECRYPTED")

        flagMessageOperations.setMessageFlag(folderId = 1, messageServerId = "uid1", Flag.X_DOWNLOADED_FULL, true)

        val message = sqliteDatabase.readMessages().first()
        val readFlags = message.flags!!.split(',').toSet()
        assertThat(readFlags).isEqualTo(setOf("X_SUBJECT_DECRYPTED", "X_DOWNLOADED_FULL"))
    }

    @Test
    fun `remove X_DOWNLOADED_FULL flag`() {
        sqliteDatabase.createMessage(folderId = 1, uid = "uid1", flags = "X_DOWNLOADED_FULL")

        flagMessageOperations.setMessageFlag(folderId = 1, messageServerId = "uid1", Flag.X_DOWNLOADED_FULL, false)

        val message = sqliteDatabase.readMessages().first()
        assertThat(message.flags).isEqualTo("")
    }
}