TF-4385 Fix spam banner show it once per day

This commit is contained in:
dab246
2026-03-25 15:43:33 +07:00
committed by Dat H. Pham
parent cee2dd9d14
commit e4107c7363
11 changed files with 54 additions and 44 deletions
@@ -284,7 +284,7 @@ class MailboxController extends BaseMailboxController
mailboxDashBoardController.updateRefreshAllMailboxState(Right(RefreshAllMailboxSuccess()));
_handleCreateDefaultFolderIfMissing(mailboxDashBoardController.mapDefaultMailboxIdByRole);
_handleDataFromNavigationRouter();
mailboxDashBoardController.getSpamReportBanner();
mailboxDashBoardController.refreshSpamReportBanner();
if (PlatformInfo.isIOS) {
_updateMailboxIdsBlockNotificationToKeychain(success.mailboxList);
}
@@ -10,7 +10,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/unread_spa
abstract class SpamReportDataSource {
Future<void> storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported);
Future<DateTime> getLastTimeDismissedSpamReported();
Future<int> getLastTimeDismissedSpamReportedMilliseconds();
Future<void> deleteLastTimeDismissedSpamReported();
@@ -28,7 +28,7 @@ class HiveSpamReportDataSourceImpl extends SpamReportDataSource {
}
@override
Future<DateTime> getLastTimeDismissedSpamReported() {
Future<int> getLastTimeDismissedSpamReportedMilliseconds() {
throw UnimplementedError();
}
@@ -21,12 +21,10 @@ class LocalSpamReportDataSourceImpl extends SpamReportDataSource {
);
@override
Future<DateTime> getLastTimeDismissedSpamReported() async {
Future<int> getLastTimeDismissedSpamReportedMilliseconds() async {
return Future.sync(() async {
final spamReportConfig = await _preferencesSettingManager.getSpamReportConfig();
return DateTime.fromMillisecondsSinceEpoch(
spamReportConfig.lastTimeDismissedMilliseconds,
);
return spamReportConfig.lastTimeDismissedMilliseconds;
}).catchError(_exceptionThrower.throwException);
}
@@ -12,8 +12,8 @@ class SpamReportRepositoryImpl extends SpamReportRepository {
SpamReportRepositoryImpl(this.mapDataSource);
@override
Future<DateTime> getLastTimeDismissedSpamReported() async {
return await mapDataSource[DataSourceType.local]!.getLastTimeDismissedSpamReported();
Future<int> getLastTimeDismissedSpamReportedMilliseconds() async {
return await mapDataSource[DataSourceType.local]!.getLastTimeDismissedSpamReportedMilliseconds();
}
@override
@@ -1,10 +1,10 @@
import 'package:core/domain/exceptions/app_base_exception.dart';
class NotFoundLastTimeDismissedSpamReportException extends AppBaseException {
NotFoundLastTimeDismissedSpamReportException([super.message]);
class SpamDismissCooldownActiveException extends AppBaseException {
SpamDismissCooldownActiveException([super.message]);
@override
String get exceptionName => 'NotFoundLastTimeDismissedSpamReportException';
String get exceptionName => 'SpamDismissCooldownActiveException';
}
class NotFoundSpamMailboxCachedException extends AppBaseException {
@@ -20,3 +20,10 @@ class NotFoundSpamMailboxException extends AppBaseException {
@override
String get exceptionName => 'NotFoundSpamMailboxException';
}
class NoUnreadSpamEmailsException extends AppBaseException {
NoUnreadSpamEmailsException([super.message]);
@override
String get exceptionName => 'NoUnreadSpamEmailsException';
}
@@ -6,7 +6,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_repor
abstract class SpamReportRepository {
Future<void> storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported);
Future<DateTime> getLastTimeDismissedSpamReported();
Future<int> getLastTimeDismissedSpamReportedMilliseconds();
Future<void> deleteLastTimeDismissedSpamReported();
@@ -18,5 +18,3 @@ class GetSpamMailboxCachedFailure extends FeatureFailure {
GetSpamMailboxCachedFailure(exception) : super(exception: exception);
}
class InvalidSpamReportCondition extends FeatureFailure {}
@@ -1,15 +1,15 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/spam_report_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_spam_mailbox_cached_state.dart';
class GetSpamMailboxCachedInteractor {
static const int spamReportBannerDisplayIntervalInHour = 12;
static const int spamReportBannerDisplayIntervalInHours = 24;
final SpamReportRepository _spamReportRepository;
@@ -19,15 +19,19 @@ class GetSpamMailboxCachedInteractor {
try {
yield Right<Failure, Success>(GetSpamMailboxCachedLoading());
if (await _validateIntervalToShowBanner()) {
final spamMailbox = await _spamReportRepository.getSpamMailboxCached(accountId, userName);
final spamMailbox = await _spamReportRepository.getSpamMailboxCached(accountId, userName);
final countUnreadSpamMailbox = spamMailbox.unreadEmails?.value.value.toInt() ?? 0;
if (countUnreadSpamMailbox > 0) {
yield Right<Failure, Success>(GetSpamMailboxCachedSuccess(spamMailbox));
} else {
yield Left<Failure, Success>(InvalidSpamReportCondition());
yield Left<Failure, Success>(
GetSpamMailboxCachedFailure(NoUnreadSpamEmailsException()),
);
}
} else {
yield Left<Failure, Success>(InvalidSpamReportCondition());
yield Left<Failure, Success>(
GetSpamMailboxCachedFailure(SpamDismissCooldownActiveException()),
);
}
} catch (e) {
yield Left<Failure, Success>(GetSpamMailboxCachedFailure(e));
@@ -35,9 +39,19 @@ class GetSpamMailboxCachedInteractor {
}
Future<bool> _validateIntervalToShowBanner() async {
final lastTimeDismissedSpamReported = await _spamReportRepository.getLastTimeDismissedSpamReported();
final currentTime = DateTime.now().difference(lastTimeDismissedSpamReported);
log('GetSpamMailboxCachedInteractor::_compareSpamReportTime:lastTimeDismissedSpamReported: $lastTimeDismissedSpamReported | currentTime: $currentTime');
return currentTime.inHours > spamReportBannerDisplayIntervalInHour;
final lastTimeDismissedMs = await _spamReportRepository
.getLastTimeDismissedSpamReportedMilliseconds();
if (lastTimeDismissedMs <= 0) {
return true;
}
final lastTime = DateTime.fromMillisecondsSinceEpoch(lastTimeDismissedMs);
final now = DateTime.now();
final elapsed = now.difference(lastTime);
final isIntervalElapsed =
elapsed.inHours > spamReportBannerDisplayIntervalInHours;
return isIntervalElapsed;
}
}
}
@@ -2534,24 +2534,6 @@ class MailboxDashBoardController extends ReloadableController
bool get enableSpamReport => spamReportController.enableSpamReport;
void getSpamReportBanner() {
if (enableSpamReport) {
final spamId = spamMailboxId;
if (spamId == null) {
spamReportController.setSpamPresentationMailbox(null);
return;
}
final spamMailbox = mapMailboxById[spamId];
final unreadEmails = spamMailbox?.unreadEmails?.value.value ?? 0;
if (unreadEmails > 0) {
spamReportController.setSpamPresentationMailbox(spamMailbox);
} else {
spamReportController.setSpamPresentationMailbox(null);
}
}
}
void refreshSpamReportBanner() {
if (enableSpamReport && sessionCurrent != null && accountId.value != null) {
spamReportController.getSpamMailboxCached(accountId.value!, sessionCurrent!.username);
@@ -9,6 +9,7 @@ import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_spam_mailbox_cached_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_spam_report_state.dart';
@@ -75,7 +76,7 @@ class SpamReportController extends BaseController {
@override
void handleFailureViewState(Failure failure) {
if (failure is GetSpamMailboxCachedFailure) {
presentationSpamMailbox.value = null;
_validateSpamMailboxChanged(failure);
} else if (failure is GetSpamReportStateFailure) {
_spamReportLoaderStatus = LoaderStatus.completed;
} else {
@@ -147,6 +148,16 @@ class SpamReportController extends BaseController {
presentationSpamMailbox.value = spamMailbox;
}
void _validateSpamMailboxChanged(GetSpamMailboxCachedFailure failure) {
if (failure.exception is NoUnreadSpamEmailsException) {
final currentSpamMailbox = presentationSpamMailbox.value;
if (currentSpamMailbox != null && currentSpamMailbox.countUnreadEmails > 0) {
_storeLastTimeDismissedSpamReportedAction();
}
}
setSpamPresentationMailbox(null);
}
@override
void onClose() {
_appLifecycleListener?.dispose();