Only remove notifications for messages currently displayed

This only works for the Unified Inbox, the "new messages" view, and when viewing a single folder. Search views are currently not supported.
This commit is contained in:
cketti 2022-01-11 01:19:24 +01:00
parent 2dff253d43
commit 6e6fd8623a
10 changed files with 138 additions and 21 deletions

View file

@ -127,6 +127,7 @@ public class MessagingController {
private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
private final MessageCountsProvider messageCountsProvider;
private final DraftOperations draftOperations;
private final NotificationOperations notificationOperations;
private MessagingListener checkMailListener = null;
@ -166,6 +167,7 @@ public class MessagingController {
initializeControllerExtensions(controllerExtensions);
draftOperations = new DraftOperations(this, messageStoreManager, saveMessageDataCreator);
notificationOperations = new NotificationOperations(notificationController, preferences, messageStoreManager);
}
private void initializeControllerExtensions(List<ControllerExtension> controllerExtensions) {
@ -2553,9 +2555,9 @@ public class MessagingController {
}
}
public void removeNotificationsForAccount(Account account) {
put("removeNotificationsForAccount", null, () -> {
notificationController.clearNewMailNotifications(account, false);
public void clearNotifications(LocalSearch search) {
put("clearNotifications", null, () -> {
notificationOperations.clearNotifications(search);
});
}

View file

@ -0,0 +1,63 @@
package com.fsck.k9.controller
import com.fsck.k9.Account
import com.fsck.k9.Preferences
import com.fsck.k9.mailstore.MessageStoreManager
import com.fsck.k9.notification.NotificationController
import com.fsck.k9.search.LocalSearch
import com.fsck.k9.search.isNewMessages
import com.fsck.k9.search.isSingleFolder
import com.fsck.k9.search.isUnifiedInbox
internal class NotificationOperations(
private val notificationController: NotificationController,
private val preferences: Preferences,
private val messageStoreManager: MessageStoreManager
) {
fun clearNotifications(search: LocalSearch) {
if (search.isUnifiedInbox) {
clearUnifiedInboxNotifications()
} else if (search.isNewMessages) {
clearAllNotifications()
} else if (search.isSingleFolder) {
val account = search.firstAccount() ?: return
val folderId = search.folderIds.first()
clearNotifications(account, folderId)
} else {
// TODO: Remove notifications when updating the message list. That way we can easily remove only
// notifications for messages that are currently displayed in the list.
}
}
private fun clearUnifiedInboxNotifications() {
for (account in preferences.accounts) {
val messageStore = messageStoreManager.getMessageStore(account)
val folderIds = messageStore.getFolders(excludeLocalOnly = true) { folderDetails ->
if (folderDetails.isIntegrate) folderDetails.id else null
}.filterNotNull().toSet()
if (folderIds.isNotEmpty()) {
notificationController.clearNewMailNotifications(account) { messageReferences ->
messageReferences.filter { messageReference -> messageReference.folderId in folderIds }
}
}
}
}
private fun clearAllNotifications() {
for (account in preferences.accounts) {
notificationController.clearNewMailNotifications(account, clearNewMessageState = false)
}
}
private fun clearNotifications(account: Account, folderId: Long) {
notificationController.clearNewMailNotifications(account) { messageReferences ->
messageReferences.filter { messageReference -> messageReference.folderId == folderId }
}
}
private fun LocalSearch.firstAccount(): Account? {
return preferences.getAccount(accountUuids.first())
}
}

View file

@ -30,8 +30,16 @@ internal class NewMailNotificationController(
processNewMailNotificationData(notificationData)
}
fun removeNewMailNotifications(account: Account, selector: (List<MessageReference>) -> List<MessageReference>) {
val notificationData = newMailNotificationManager.removeNewMailNotifications(account, selector)
fun removeNewMailNotifications(
account: Account,
clearNewMessageState: Boolean,
selector: (List<MessageReference>) -> List<MessageReference>
) {
val notificationData = newMailNotificationManager.removeNewMailNotifications(
account,
clearNewMessageState,
selector
)
if (notificationData != null) {
processNewMailNotificationData(notificationData)

View file

@ -65,9 +65,10 @@ internal class NewMailNotificationManager(
fun removeNewMailNotifications(
account: Account,
clearNewMessageState: Boolean,
selector: (List<MessageReference>) -> List<MessageReference>
): NewMailNotificationData? {
val result = notificationRepository.removeNotifications(account, selector) ?: return null
val result = notificationRepository.removeNotifications(account, clearNewMessageState, selector) ?: return null
val cancelNotificationIds = when {
result.notificationData.isEmpty() -> {

View file

@ -65,7 +65,13 @@ class NotificationController internal constructor(
}
fun removeNewMailNotification(account: Account, messageReference: MessageReference) {
newMailNotificationController.removeNewMailNotifications(account) { listOf(messageReference) }
newMailNotificationController.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(messageReference)
}
}
fun clearNewMailNotifications(account: Account, selector: (List<MessageReference>) -> List<MessageReference>) {
newMailNotificationController.removeNewMailNotifications(account, clearNewMessageState = false, selector)
}
fun clearNewMailNotifications(account: Account, clearNewMessageState: Boolean) {

View file

@ -46,10 +46,13 @@ internal class NotificationRepository(
@Synchronized
fun removeNotifications(
account: Account,
clearNewMessageState: Boolean = true,
selector: (List<MessageReference>) -> List<MessageReference>
): RemoveNotificationsResult? {
return notificationDataStore.removeNotifications(account, selector)?.also { result ->
persistNotificationDataStoreChanges(account, result.notificationStoreOperations)
if (clearNewMessageState) {
persistNotificationDataStoreChanges(account, result.notificationStoreOperations)
}
}
}

View file

@ -5,6 +5,18 @@ package com.fsck.k9.search
import com.fsck.k9.Account
import com.fsck.k9.Preferences
val LocalSearch.isUnifiedInbox: Boolean
get() = id == SearchAccount.UNIFIED_INBOX
val LocalSearch.isNewMessages: Boolean
get() = id == SearchAccount.NEW_MESSAGES
val LocalSearch.isSingleAccount: Boolean
get() = accountUuids.size == 1
val LocalSearch.isSingleFolder: Boolean
get() = isSingleAccount && folderIds.size == 1
@JvmName("getAccountsFromLocalSearch")
fun LocalSearch.getAccounts(preferences: Preferences): List<Account> {
val accounts = preferences.accounts

View file

@ -128,7 +128,9 @@ class NewMailNotificationManagerTest {
@Test
fun `remove notification when none was added before should return null`() {
val result = manager.removeNewMailNotifications(account) { listOf(createMessageReference("any")) }
val result = manager.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(createMessageReference("any"))
}
assertThat(result).isNull()
}
@ -144,7 +146,9 @@ class NewMailNotificationManagerTest {
)
manager.addNewMailNotification(account, message, silent = false)
val result = manager.removeNewMailNotifications(account) { listOf(createMessageReference("untracked")) }
val result = manager.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(createMessageReference("untracked"))
}
assertThat(result).isNull()
}
@ -160,7 +164,9 @@ class NewMailNotificationManagerTest {
)
manager.addNewMailNotification(account, message, silent = false)
val result = manager.removeNewMailNotifications(account) { listOf(createMessageReference("msg-1")) }
val result = manager.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(createMessageReference("msg-1"))
}
assertNotNull(result) { data ->
assertThat(data.cancelNotificationIds).containsExactly(
@ -200,7 +206,9 @@ class NewMailNotificationManagerTest {
)
manager.addNewMailNotification(account, messageThree, silent = true)
val result = manager.removeNewMailNotifications(account) { listOf(createMessageReference("msg-2")) }
val result = manager.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(createMessageReference("msg-2"))
}
assertNotNull(result) { data ->
assertThat(data.cancelNotificationIds).isEqualTo(listOf(notificationIdTwo))
@ -230,7 +238,9 @@ class NewMailNotificationManagerTest {
manager.addNewMailNotification(account, message, silent = false)
addMaximumNumberOfNotifications()
val result = manager.removeNewMailNotifications(account) { listOf(createMessageReference("msg-1")) }
val result = manager.removeNewMailNotifications(account, clearNewMessageState = true) {
listOf(createMessageReference("msg-1"))
}
assertNotNull(result) { data ->
assertThat(data.cancelNotificationIds).hasSize(1)

View file

@ -32,6 +32,7 @@ import com.fsck.k9.Preferences
import com.fsck.k9.account.BackgroundAccountRemover
import com.fsck.k9.activity.compose.MessageActions
import com.fsck.k9.controller.MessageReference
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.fragment.MessageListFragment
import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener
import com.fsck.k9.helper.Contacts
@ -44,6 +45,7 @@ import com.fsck.k9.search.SearchAccount
import com.fsck.k9.search.SearchSpecification
import com.fsck.k9.search.SearchSpecification.SearchCondition
import com.fsck.k9.search.SearchSpecification.SearchField
import com.fsck.k9.search.isUnifiedInbox
import com.fsck.k9.ui.BuildConfig
import com.fsck.k9.ui.K9Drawer
import com.fsck.k9.ui.R
@ -92,6 +94,7 @@ open class MessageList :
private val defaultFolderProvider: DefaultFolderProvider by inject()
private val accountRemover: BackgroundAccountRemover by inject()
private val generalSettingsManager: GeneralSettingsManager by inject()
private val messagingController: MessagingController by inject()
private val permissionUiHelper: PermissionUiHelper = K9PermissionUiHelper(this)
@ -347,6 +350,7 @@ open class MessageList :
}
}
setDrawerLockState()
onMessageListDisplayed()
}
}
}
@ -541,6 +545,10 @@ open class MessageList :
recreate()
}
if (displayMode != DisplayMode.MESSAGE_VIEW) {
onMessageListDisplayed()
}
if (this !is Search) {
// necessary b/c no guarantee Search.onStop will be called before MessageList.onResume
// when returning from search results
@ -613,6 +621,8 @@ open class MessageList :
search.addAllowedFolder(folderId)
performSearch(search)
onMessageListDisplayed()
}
private fun openFolderImmediately(folderId: Long) {
@ -1462,6 +1472,8 @@ open class MessageList :
showDefaultTitleView()
configureMenu(menu)
onMessageListDisplayed()
}
private fun setDrawerLockState() {
@ -1519,6 +1531,14 @@ open class MessageList :
}
}
private fun onMessageListDisplayed() {
clearNotifications()
}
private fun clearNotifications() {
messagingController.clearNotifications(search)
}
override fun startIntentSenderForResult(
intent: IntentSender,
requestCode: Int,
@ -1591,9 +1611,6 @@ open class MessageList :
}
}
private val LocalSearch.isUnifiedInbox: Boolean
get() = id == SearchAccount.UNIFIED_INBOX
private fun MessageReference.toLocalSearch(): LocalSearch {
return LocalSearch().apply {
addAccountUuid(accountUuid)

View file

@ -475,11 +475,6 @@ class MessageListFragment :
messagingController.addListener(activityListener)
for (account in localSearch.getAccounts(preferences)) {
// TODO: Only remove notifications for messages in the currently displayed message list
messagingController.removeNotificationsForAccount(account)
}
updateTitle()
}