Rewrite MessageCountsProvider
to use MessageStore
This commit is contained in:
parent
adabe43efe
commit
ef583ba620
7 changed files with 135 additions and 88 deletions
|
@ -31,7 +31,6 @@ val controllerModule = module {
|
|||
DefaultMessageCountsProvider(
|
||||
preferences = get(),
|
||||
accountSearchConditions = get(),
|
||||
localStoreProvider = get(),
|
||||
messageStoreManager = get()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ package com.fsck.k9.controller
|
|||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.mail.MessagingException
|
||||
import com.fsck.k9.mailstore.LocalStoreProvider
|
||||
import com.fsck.k9.mailstore.MessageStoreManager
|
||||
import com.fsck.k9.search.AccountSearchConditions
|
||||
import com.fsck.k9.search.ConditionsTreeNode
|
||||
import com.fsck.k9.search.LocalSearch
|
||||
import com.fsck.k9.search.SearchAccount
|
||||
import com.fsck.k9.search.getAccounts
|
||||
|
@ -22,22 +21,14 @@ data class MessageCounts(val unread: Int, val starred: Int)
|
|||
internal class DefaultMessageCountsProvider(
|
||||
private val preferences: Preferences,
|
||||
private val accountSearchConditions: AccountSearchConditions,
|
||||
private val localStoreProvider: LocalStoreProvider,
|
||||
private val messageStoreManager: MessageStoreManager
|
||||
) : MessageCountsProvider {
|
||||
override fun getMessageCounts(account: Account): MessageCounts {
|
||||
return try {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
val search = LocalSearch()
|
||||
accountSearchConditions.excludeSpecialFolders(account, search)
|
||||
accountSearchConditions.limitToDisplayableFolders(account, search)
|
||||
|
||||
val search = LocalSearch()
|
||||
accountSearchConditions.excludeSpecialFolders(account, search)
|
||||
accountSearchConditions.limitToDisplayableFolders(account, search)
|
||||
|
||||
localStore.getMessageCounts(search)
|
||||
} catch (e: MessagingException) {
|
||||
Timber.e(e, "Unable to getMessageCounts for account: %s", account)
|
||||
MessageCounts(0, 0)
|
||||
}
|
||||
return getMessageCounts(account, search.conditions)
|
||||
}
|
||||
|
||||
override fun getMessageCounts(searchAccount: SearchAccount): MessageCounts {
|
||||
|
@ -47,7 +38,7 @@ internal class DefaultMessageCountsProvider(
|
|||
var unreadCount = 0
|
||||
var starredCount = 0
|
||||
for (account in accounts) {
|
||||
val accountMessageCount = getMessageCountsWithLocalSearch(account, search)
|
||||
val accountMessageCount = getMessageCounts(account, search.conditions)
|
||||
unreadCount += accountMessageCount.unread
|
||||
starredCount += accountMessageCount.starred
|
||||
}
|
||||
|
@ -69,13 +60,16 @@ internal class DefaultMessageCountsProvider(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getMessageCountsWithLocalSearch(account: Account, search: LocalSearch): MessageCounts {
|
||||
private fun getMessageCounts(account: Account, conditions: ConditionsTreeNode): MessageCounts {
|
||||
return try {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
localStore.getMessageCounts(search)
|
||||
} catch (e: MessagingException) {
|
||||
val messageStore = messageStoreManager.getMessageStore(account)
|
||||
return MessageCounts(
|
||||
unread = messageStore.getUnreadMessageCount(conditions),
|
||||
starred = messageStore.getStarredMessageCount(conditions)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Unable to getMessageCounts for account: %s", account)
|
||||
MessageCounts(0, 0)
|
||||
MessageCounts(unread = 0, starred = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import androidx.core.database.CursorKt;
|
|||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Clock;
|
||||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.controller.MessageCounts;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
|
||||
import com.fsck.k9.controller.PendingCommandSerializer;
|
||||
|
@ -1005,72 +1004,6 @@ public class LocalStore {
|
|||
return folderMap;
|
||||
}
|
||||
|
||||
public int getUnreadMessageCount(LocalSearch search) throws MessagingException {
|
||||
StringBuilder whereBuilder = new StringBuilder();
|
||||
List<String> queryArgs = new ArrayList<>();
|
||||
SqlQueryBuilder.buildWhereClause(search.getConditions(), whereBuilder, queryArgs);
|
||||
|
||||
String where = whereBuilder.toString();
|
||||
final String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]);
|
||||
|
||||
final String sqlQuery = "SELECT SUM(read=0) " +
|
||||
"FROM messages " +
|
||||
"JOIN folders ON (folders.id = messages.folder_id) " +
|
||||
"WHERE (messages.empty = 0 AND messages.deleted = 0)" +
|
||||
(!TextUtils.isEmpty(where) ? " AND (" + where + ")" : "");
|
||||
|
||||
return database.execute(false, new DbCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doDbWork(SQLiteDatabase db) {
|
||||
Cursor cursor = db.rawQuery(sqlQuery, selectionArgs);
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getStarredMessageCount(LocalSearch search) throws MessagingException {
|
||||
StringBuilder whereBuilder = new StringBuilder();
|
||||
List<String> queryArgs = new ArrayList<>();
|
||||
SqlQueryBuilder.buildWhereClause(search.getConditions(), whereBuilder, queryArgs);
|
||||
|
||||
String where = whereBuilder.toString();
|
||||
final String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]);
|
||||
|
||||
final String sqlQuery = "SELECT SUM(flagged=1) " +
|
||||
"FROM messages " +
|
||||
"JOIN folders ON (folders.id = messages.folder_id) " +
|
||||
"WHERE (messages.empty = 0 AND messages.deleted = 0)" +
|
||||
(!TextUtils.isEmpty(where) ? " AND (" + where + ")" : "");
|
||||
|
||||
return database.execute(false, new DbCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doDbWork(SQLiteDatabase db) {
|
||||
Cursor cursor = db.rawQuery(sqlQuery, selectionArgs);
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MessageCounts getMessageCounts(LocalSearch search) throws MessagingException {
|
||||
return new MessageCounts(getUnreadMessageCount(search), getStarredMessageCount(search));
|
||||
}
|
||||
|
||||
public List<NotificationMessage> getNotificationMessages() throws MessagingException {
|
||||
return database.execute(false, db -> {
|
||||
try (Cursor cursor = db.rawQuery(
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.fsck.k9.mail.Flag
|
|||
import com.fsck.k9.mail.FolderClass
|
||||
import com.fsck.k9.mail.FolderType
|
||||
import com.fsck.k9.mail.Header
|
||||
import com.fsck.k9.search.ConditionsTreeNode
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
|
@ -226,6 +227,16 @@ interface MessageStore {
|
|||
*/
|
||||
fun getUnreadMessageCount(folderId: Long): Int
|
||||
|
||||
/**
|
||||
* Retrieve the number of unread messages matching [conditions].
|
||||
*/
|
||||
fun getUnreadMessageCount(conditions: ConditionsTreeNode): Int
|
||||
|
||||
/**
|
||||
* Retrieve the number of starred messages matching [conditions].
|
||||
*/
|
||||
fun getStarredMessageCount(conditions: ConditionsTreeNode): Int
|
||||
|
||||
/**
|
||||
* Update a folder's name and type.
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.fsck.k9.mailstore.MoreMessages
|
|||
import com.fsck.k9.mailstore.SaveMessageData
|
||||
import com.fsck.k9.mailstore.StorageManager
|
||||
import com.fsck.k9.message.extractors.BasicPartInfoExtractor
|
||||
import com.fsck.k9.search.ConditionsTreeNode
|
||||
import java.util.Date
|
||||
|
||||
class K9MessageStore(
|
||||
|
@ -180,6 +181,14 @@ class K9MessageStore(
|
|||
return retrieveFolderOperations.getUnreadMessageCount(folderId)
|
||||
}
|
||||
|
||||
override fun getUnreadMessageCount(conditions: ConditionsTreeNode): Int {
|
||||
return retrieveFolderOperations.getUnreadMessageCount(conditions)
|
||||
}
|
||||
|
||||
override fun getStarredMessageCount(conditions: ConditionsTreeNode): Int {
|
||||
return retrieveFolderOperations.getStarredMessageCount(conditions)
|
||||
}
|
||||
|
||||
override fun getSize(): Long {
|
||||
return databaseOperations.getSize()
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import com.fsck.k9.mailstore.FolderNotFoundException
|
|||
import com.fsck.k9.mailstore.LockableDatabase
|
||||
import com.fsck.k9.mailstore.MoreMessages
|
||||
import com.fsck.k9.mailstore.toFolderType
|
||||
import com.fsck.k9.search.ConditionsTreeNode
|
||||
import com.fsck.k9.search.SqlQueryBuilder
|
||||
|
||||
internal class RetrieveFolderOperations(private val lockableDatabase: LockableDatabase) {
|
||||
fun <T> getFolder(folderId: Long, mapper: FolderMapper<T>): T? {
|
||||
|
@ -170,6 +172,37 @@ $displayModeSelection
|
|||
}
|
||||
}
|
||||
|
||||
fun getUnreadMessageCount(conditions: ConditionsTreeNode): Int {
|
||||
return getMessageCount(condition = "messages.read = 0", conditions)
|
||||
}
|
||||
|
||||
fun getStarredMessageCount(conditions: ConditionsTreeNode): Int {
|
||||
return getMessageCount(condition = "messages.flagged = 1", conditions)
|
||||
}
|
||||
|
||||
private fun getMessageCount(condition: String, extraConditions: ConditionsTreeNode): Int {
|
||||
val whereBuilder = StringBuilder()
|
||||
val queryArgs = mutableListOf<String>()
|
||||
SqlQueryBuilder.buildWhereClause(extraConditions, whereBuilder, queryArgs)
|
||||
|
||||
val where = if (whereBuilder.isNotEmpty()) "AND ($whereBuilder)" else ""
|
||||
val selectionArgs = queryArgs.toTypedArray()
|
||||
|
||||
val query =
|
||||
"""
|
||||
SELECT COUNT(messages.id)
|
||||
FROM messages
|
||||
JOIN folders ON (folders.id = messages.folder_id)
|
||||
WHERE (messages.empty = 0 AND messages.deleted = 0 AND $condition) $where
|
||||
"""
|
||||
|
||||
return lockableDatabase.execute(false) { db ->
|
||||
db.rawQuery(query, selectionArgs).use { cursor ->
|
||||
if (cursor.moveToFirst()) cursor.getInt(0) else 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasMoreMessages(folderId: Long): MoreMessages {
|
||||
return getFolder(folderId) { it.moreMessages } ?: throw FolderNotFoundException(folderId)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.fsck.k9.mail.FolderType
|
|||
import com.fsck.k9.mailstore.FolderNotFoundException
|
||||
import com.fsck.k9.mailstore.MoreMessages
|
||||
import com.fsck.k9.mailstore.toDatabaseFolderType
|
||||
import com.fsck.k9.search.LocalSearch
|
||||
import com.fsck.k9.search.SearchSpecification
|
||||
import com.fsck.k9.storage.RobolectricTest
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Assert.fail
|
||||
|
@ -379,6 +381,68 @@ class RetrieveFolderOperationsTest : RobolectricTest() {
|
|||
assertThat(result).isEqualTo(2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get unread message count with condition from empty folder`() {
|
||||
sqliteDatabase.createFolder(integrate = true)
|
||||
|
||||
val result = retrieveFolderOperations.getUnreadMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get unread message count with condition from non-existent folder`() {
|
||||
val result = retrieveFolderOperations.getUnreadMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get unread message count with condition from non-empty folder`() {
|
||||
val folderId1 = sqliteDatabase.createFolder(integrate = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId1, read = false)
|
||||
sqliteDatabase.createMessage(folderId = folderId1, read = false)
|
||||
sqliteDatabase.createMessage(folderId = folderId1, read = true)
|
||||
val folderId2 = sqliteDatabase.createFolder(integrate = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId2, read = false)
|
||||
sqliteDatabase.createMessage(folderId = folderId2, read = true)
|
||||
|
||||
val result = retrieveFolderOperations.getUnreadMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get starred message count with condition from empty folder`() {
|
||||
sqliteDatabase.createFolder(integrate = true)
|
||||
|
||||
val result = retrieveFolderOperations.getStarredMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get starred message count with condition from non-existent folder`() {
|
||||
val result = retrieveFolderOperations.getStarredMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get starred message count with condition from non-empty folder`() {
|
||||
val folderId1 = sqliteDatabase.createFolder(integrate = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId1, flagged = false)
|
||||
sqliteDatabase.createMessage(folderId = folderId1, flagged = true)
|
||||
val folderId2 = sqliteDatabase.createFolder(integrate = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId2, flagged = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId2, flagged = true)
|
||||
sqliteDatabase.createMessage(folderId = folderId2, flagged = false)
|
||||
|
||||
val result = retrieveFolderOperations.getStarredMessageCount(unifiedInboxConditions)
|
||||
|
||||
assertThat(result).isEqualTo(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get 'more messages' value from non-existent folder`() {
|
||||
try {
|
||||
|
@ -415,4 +479,8 @@ class RetrieveFolderOperationsTest : RobolectricTest() {
|
|||
|
||||
assertThat(result).isEqualTo(MoreMessages.TRUE)
|
||||
}
|
||||
|
||||
private val unifiedInboxConditions = LocalSearch().apply {
|
||||
and(SearchSpecification.SearchField.INTEGRATE, "1", SearchSpecification.Attribute.EQUALS)
|
||||
}.conditions
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue