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

Unverified Commit c93f5ea7 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #6612 from thundernest/message_counts

Refactoring: Message counts
parents 550b2844 dd89dee4
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -15,14 +15,12 @@ import com.fsck.k9.network.connectivityModule
import com.fsck.k9.notification.coreNotificationModule
import com.fsck.k9.power.powerModule
import com.fsck.k9.preferences.preferencesModule
import com.fsck.k9.search.searchModule

val coreModules = listOf(
    mainModule,
    openPgpModule,
    autocryptModule,
    mailStoreModule,
    searchModule,
    extractorModule,
    htmlModule,
    quoteModule,
+1 −3
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ val controllerModule = module {
            get<NotificationController>(),
            get<NotificationStrategy>(),
            get<LocalStoreProvider>(),
            get<MessageCountsProvider>(),
            get<BackendManager>(),
            get<Preferences>(),
            get<MessageStoreManager>(),
@@ -31,8 +30,7 @@ val controllerModule = module {
    single<MessageCountsProvider> {
        DefaultMessageCountsProvider(
            preferences = get(),
            accountSearchConditions = get(),
            localStoreProvider = get()
            messageStoreManager = get()
        )
    }
}
+34 −22
Original line number Diff line number Diff line
@@ -2,39 +2,34 @@ 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.search.AccountSearchConditions
import com.fsck.k9.mailstore.MessageStoreManager
import com.fsck.k9.search.ConditionsTreeNode
import com.fsck.k9.search.LocalSearch
import com.fsck.k9.search.SearchAccount
import com.fsck.k9.search.excludeSpecialFolders
import com.fsck.k9.search.getAccounts
import com.fsck.k9.search.limitToDisplayableFolders
import timber.log.Timber

interface MessageCountsProvider {
    fun getMessageCounts(account: Account): MessageCounts
    fun getMessageCounts(searchAccount: SearchAccount): MessageCounts
    fun getUnreadMessageCount(account: Account, folderId: Long): Int
}

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)

            localStore.getMessageCounts(search)
        } catch (e: MessagingException) {
            Timber.e(e, "Unable to getMessageCounts for account: %s", account)
            MessageCounts(0, 0)
        val search = LocalSearch().apply {
            excludeSpecialFolders(account)
            limitToDisplayableFolders(account)
        }

        return getMessageCounts(account, search.conditions)
    }

    override fun getMessageCounts(searchAccount: SearchAccount): MessageCounts {
@@ -44,7 +39,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
        }
@@ -52,13 +47,30 @@ internal class DefaultMessageCountsProvider(
        return MessageCounts(unreadCount, starredCount)
    }

    private fun getMessageCountsWithLocalSearch(account: Account, search: LocalSearch): MessageCounts {
    override fun getUnreadMessageCount(account: Account, folderId: Long): Int {
        return try {
            val messageStore = messageStoreManager.getMessageStore(account)
            return if (folderId == account.outboxFolderId) {
                messageStore.getMessageCount(folderId)
            } else {
                messageStore.getUnreadMessageCount(folderId)
            }
        } catch (e: Exception) {
            Timber.e(e, "Unable to getUnreadMessageCount for account: %s, folder: %d", account, folderId)
            0
        }
    }

    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)
        }
    }
}
+1 −25
Original line number Diff line number Diff line
@@ -81,7 +81,6 @@ import com.fsck.k9.mailstore.SpecialLocalFoldersCreator;
import com.fsck.k9.notification.NotificationController;
import com.fsck.k9.notification.NotificationStrategy;
import com.fsck.k9.search.LocalSearch;
import com.fsck.k9.search.SearchAccount;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import timber.log.Timber;
@@ -125,7 +124,6 @@ public class MessagingController {
    private final Set<MessagingListener> listeners = new CopyOnWriteArraySet<>();
    private final ExecutorService threadPool = Executors.newCachedThreadPool();
    private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
    private final MessageCountsProvider messageCountsProvider;
    private final DraftOperations draftOperations;
    private final NotificationOperations notificationOperations;

@@ -140,15 +138,13 @@ public class MessagingController {

    MessagingController(Context context, NotificationController notificationController,
            NotificationStrategy notificationStrategy, LocalStoreProvider localStoreProvider,
            MessageCountsProvider messageCountsProvider, BackendManager backendManager,
            Preferences preferences, MessageStoreManager messageStoreManager,
            BackendManager backendManager, Preferences preferences, MessageStoreManager messageStoreManager,
            SaveMessageDataCreator saveMessageDataCreator, SpecialLocalFoldersCreator specialLocalFoldersCreator,
            List<ControllerExtension> controllerExtensions) {
        this.context = context;
        this.notificationController = notificationController;
        this.notificationStrategy = notificationStrategy;
        this.localStoreProvider = localStoreProvider;
        this.messageCountsProvider = messageCountsProvider;
        this.backendManager = backendManager;
        this.preferences = preferences;
        this.messageStoreManager = messageStoreManager;
@@ -1640,22 +1636,6 @@ public class MessagingController {
        }
    }

    public int getUnreadMessageCount(Account account) {
        MessageCounts messageCounts = messageCountsProvider.getMessageCounts(account);
        return messageCounts.getUnread();
    }

    public int getUnreadMessageCount(SearchAccount searchAccount) {
        MessageCounts messageCounts = messageCountsProvider.getMessageCounts(searchAccount);
        return messageCounts.getUnread();
    }

    public int getFolderUnreadMessageCount(Account account, Long folderId) throws MessagingException {
        LocalStore localStore = localStoreProvider.getInstance(account);
        LocalFolder localFolder = localStore.getFolder(folderId);
        return localFolder.getUnreadMessageCount();
    }

    public boolean isMoveCapable(MessageReference messageReference) {
        return !messageReference.getUid().startsWith(K9.LOCAL_UID_PREFIX);
    }
@@ -2329,10 +2309,6 @@ public class MessagingController {
                            Timber.v("Clearing notification flag for %s", account);

                            clearFetchingMailNotification(account);

                            if (getUnreadMessageCount(account) == 0) {
                                notificationController.clearNewMailNotifications(account, false);
                            }
                        }
                    }
            );
+1 −68
Original line number Diff line number Diff line
@@ -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;
@@ -355,7 +354,7 @@ public class LocalStore {
    public List<LocalMessage> searchForMessages(LocalSearch search) throws MessagingException {
        StringBuilder query = new StringBuilder();
        List<String> queryArgs = new ArrayList<>();
        SqlQueryBuilder.buildWhereClause(account, search.getConditions(), query, queryArgs);
        SqlQueryBuilder.buildWhereClause(search.getConditions(), query, queryArgs);

        // Avoid "ambiguous column name" error by prefixing "id" with the message table name
        String where = SqlQueryBuilder.addPrefixToSelection(new String[] { "id" },
@@ -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(account, 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(account, 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(
Loading