Skip to content

Commit a1cea26

Browse files
committed
chore(notifications): dismiss sent folder not found notification when user switches account
1 parent c76b358 commit a1cea26

3 files changed

Lines changed: 76 additions & 3 deletions

File tree

feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/command/outcome/NotificationCommandOutcome.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ typealias NotificationCommandOutcome<TNotification> = Outcome<Success<TNotificat
2424
*/
2525
sealed interface Success<out TNotification : Notification> {
2626
val notificationId: NotificationId
27+
val rawNotificationId: Int
28+
@Discouraged("This is a utility getter to enable usage in Java code. Use notificationId instead.")
29+
get() = notificationId.value
2730
val command: NotificationCommand<out TNotification>?
2831

2932
/**

feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/dismisser/compat/NotificationDismisserCompat.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlinx.coroutines.SupervisorJob
99
import kotlinx.coroutines.cancel
1010
import kotlinx.coroutines.flow.launchIn
1111
import kotlinx.coroutines.flow.onEach
12+
import net.thunderbird.feature.notification.api.NotificationId
1213
import net.thunderbird.feature.notification.api.command.outcome.NotificationCommandOutcome
1314
import net.thunderbird.feature.notification.api.content.Notification
1415
import net.thunderbird.feature.notification.api.dismisser.NotificationDismisser
@@ -32,6 +33,12 @@ class NotificationDismisserCompat @JvmOverloads constructor(
3233
) : DisposableHandle {
3334
private val scope = CoroutineScope(SupervisorJob() + mainImmediateDispatcher)
3435

36+
fun dismiss(notificationId: Int, onResultListener: OnResultListener) {
37+
notificationDismisser.dismiss(NotificationId(notificationId))
38+
.onEach { outcome -> onResultListener.onResult(outcome) }
39+
.launchIn(scope)
40+
}
41+
3542
fun dismiss(notification: Notification, onResultListener: OnResultListener) {
3643
notificationDismisser.dismiss(notification)
3744
.onEach { outcome -> onResultListener.onResult(outcome) }

legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageCompose.java

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import java.util.ArrayList;
66
import java.util.Date;
77
import java.util.HashMap;
8+
import java.util.HashSet;
89
import java.util.List;
910
import java.util.Locale;
1011
import java.util.Map;
12+
import java.util.Set;
1113
import java.util.regex.Pattern;
1214
import android.annotation.SuppressLint;
1315
import android.app.Activity;
@@ -56,6 +58,7 @@
5658
import com.bumptech.glide.Glide;
5759
import com.bumptech.glide.load.engine.DiskCacheStrategy;
5860
import com.fsck.k9.activity.compose.MessageComposeInAppNotificationFragment;
61+
import kotlin.Unit;
5962
import net.thunderbird.core.android.account.LegacyAccountDto;
6063
import app.k9mail.legacy.di.DI;
6164
import net.thunderbird.core.android.account.Identity;
@@ -127,10 +130,14 @@
127130
import net.thunderbird.core.android.contact.ContactIntentHelper;
128131
import net.thunderbird.core.featureflag.FeatureFlagProvider;
129132
import net.thunderbird.core.featureflag.compat.FeatureFlagProviderCompat;
133+
import net.thunderbird.core.outcome.OutcomeKt;
130134
import net.thunderbird.core.preference.GeneralSettingsManager;
131135
import net.thunderbird.core.ui.theme.manager.ThemeManager;
136+
import net.thunderbird.feature.notification.api.command.outcome.CommandExecutionFailed;
132137
import net.thunderbird.feature.notification.api.content.NotificationFactoryCoroutineCompat;
133138
import net.thunderbird.feature.notification.api.content.SentFolderNotFoundNotification;
139+
import net.thunderbird.feature.notification.api.dismisser.NotificationDismisser;
140+
import net.thunderbird.feature.notification.api.dismisser.compat.NotificationDismisserCompat;
134141
import net.thunderbird.feature.notification.api.sender.NotificationSender;
135142
import net.thunderbird.feature.notification.api.sender.compat.NotificationSenderCompat;
136143
import net.thunderbird.feature.search.legacy.LocalMessageSearch;
@@ -178,6 +185,8 @@ public class MessageCompose extends K9Activity implements OnClickListener,
178185
private static final String STATE_KEY_READ_RECEIPT = "com.fsck.k9.activity.MessageCompose.messageReadReceipt";
179186
private static final String STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE = "com.fsck.k9.activity.MessageCompose.changesMadeSinceLastSave";
180187
private static final String STATE_ALREADY_NOTIFIED_USER_OF_EMPTY_SUBJECT = "alreadyNotifiedUserOfEmptySubject";
188+
private static final String STATE_ACTIVE_IN_APP_NOTIFICATIONS =
189+
"com.fsck.k9.activity.MessageCompose.activeInAppNotifications";
181190

182191
private static final String FRAGMENT_WAITING_FOR_ATTACHMENT = "waitingForAttachment";
183192

@@ -216,6 +225,11 @@ public class MessageCompose extends K9Activity implements OnClickListener,
216225
private final FeatureFlagProvider featureFlagProvider = DI.get(FeatureFlagProvider.class);
217226
private final NotificationSender notificationSender = DI.get(NotificationSender.class);
218227
private final NotificationSenderCompat notificationSenderCompat = new NotificationSenderCompat(notificationSender);
228+
private final NotificationDismisser notificationDismisser = DI.get(NotificationDismisser.class);
229+
private final NotificationDismisserCompat notificationDismisserCompat =
230+
new NotificationDismisserCompat(notificationDismisser);
231+
232+
private final Set<Integer> activeInAppNotifications = new HashSet<>();
219233

220234
private QuotedMessagePresenter quotedMessagePresenter;
221235
private MessageLoaderHelper messageLoaderHelper;
@@ -561,16 +575,56 @@ protected void onResume() {
561575
fetchAccount(getIntent());
562576
}
563577

578+
dismissActiveInAppNotifications();
579+
triggerIfNeededSentFolderNotFoundInAppNotification();
580+
}
581+
582+
private void triggerIfNeededSentFolderNotFoundInAppNotification() {
564583
if (account != null && account.getSentFolderId() == null) {
565584
final SentFolderNotFoundNotification notification = NotificationFactoryCoroutineCompat.create(
566-
continuation -> SentFolderNotFoundNotification(account.getUuid(), continuation)
585+
continuation -> SentFolderNotFoundNotification(account.getUuid(), continuation)
567586
);
568587
notificationSenderCompat.send(notification, outcome -> {
569-
Log.v("notificationSender outcome = " + outcome);
588+
OutcomeKt.handle(
589+
outcome,
590+
success -> {
591+
activeInAppNotifications.add(success.getRawNotificationId());
592+
return Unit.INSTANCE;
593+
},
594+
failure -> {
595+
final Throwable throwable = failure instanceof CommandExecutionFailed<?>
596+
? ((CommandExecutionFailed<?>) failure).getThrowable()
597+
: null;
598+
Log.e(throwable, "Failed to send in-app notification. Failure = " + failure);
599+
return Unit.INSTANCE;
600+
});
570601
});
571602
}
572603
}
573604

605+
private void dismissActiveInAppNotifications() {
606+
for (Integer notificationId : activeInAppNotifications) {
607+
notificationDismisserCompat.dismiss(
608+
notificationId,
609+
outcome -> {
610+
OutcomeKt.handle(
611+
outcome,
612+
success -> {
613+
activeInAppNotifications.remove(success.getRawNotificationId());
614+
return Unit.INSTANCE;
615+
},
616+
failure -> {
617+
final Throwable throwable = failure instanceof CommandExecutionFailed<?>
618+
? ((CommandExecutionFailed<?>) failure).getThrowable()
619+
: null;
620+
Log.e(throwable, "Failed to dismiss in-app notification. Failure = " + failure);
621+
return Unit.INSTANCE;
622+
}
623+
);
624+
});
625+
}
626+
}
627+
574628
@Override
575629
public void onPause() {
576630
super.onPause();
@@ -596,7 +650,7 @@ public void onPause() {
596650
* Quoted text,
597651
*/
598652
@Override
599-
protected void onSaveInstanceState(Bundle outState) {
653+
protected void onSaveInstanceState(@NonNull Bundle outState) {
600654
super.onSaveInstanceState(outState);
601655

602656
outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, relatedMessageProcessed);
@@ -610,6 +664,7 @@ protected void onSaveInstanceState(Bundle outState) {
610664
outState.putBoolean(STATE_KEY_READ_RECEIPT, requestReadReceipt);
611665
outState.putBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE, changesMadeSinceLastSave);
612666
outState.putBoolean(STATE_ALREADY_NOTIFIED_USER_OF_EMPTY_SUBJECT, alreadyNotifiedUserOfEmptySubject);
667+
outState.putIntegerArrayList(STATE_ACTIVE_IN_APP_NOTIFICATIONS, new ArrayList<>(activeInAppNotifications));
613668

614669
replyToPresenter.onSaveInstanceState(outState);
615670
recipientPresenter.onSaveInstanceState(outState);
@@ -649,6 +704,11 @@ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
649704
referencedMessageIds = savedInstanceState.getString(STATE_REFERENCES);
650705
changesMadeSinceLastSave = savedInstanceState.getBoolean(STATE_KEY_CHANGES_MADE_SINCE_LAST_SAVE);
651706
alreadyNotifiedUserOfEmptySubject = savedInstanceState.getBoolean(STATE_ALREADY_NOTIFIED_USER_OF_EMPTY_SUBJECT);
707+
final List<Integer> activeInAppNotifications = savedInstanceState
708+
.getIntegerArrayList(STATE_ACTIVE_IN_APP_NOTIFICATIONS);
709+
if (activeInAppNotifications != null && !activeInAppNotifications.isEmpty()) {
710+
this.activeInAppNotifications.addAll(activeInAppNotifications);
711+
}
652712

653713
updateFrom();
654714

@@ -912,6 +972,9 @@ private void onAccountChosen(LegacyAccountDto account, Identity identity) {
912972
this.account = account;
913973
}
914974

975+
dismissActiveInAppNotifications();
976+
triggerIfNeededSentFolderNotFoundInAppNotification();
977+
915978
// Show CC/BCC text input field when switching to an account that always wants them
916979
// displayed.
917980
// Please note that we're not hiding the fields if the user switches back to an account

0 commit comments

Comments
 (0)