diff --git a/core/lib/domain/extensions/datetime_extension.dart b/core/lib/domain/extensions/datetime_extension.dart index f7d602fcd..9b7d39026 100644 --- a/core/lib/domain/extensions/datetime_extension.dart +++ b/core/lib/domain/extensions/datetime_extension.dart @@ -15,6 +15,12 @@ extension DateTimeExtension on DateTime { final now = DateTime.now(); return now.year == this.year; } + + int daysBetween(DateTime from) { + from = DateTime(from.year, from.month, from.day); + final to = DateTime(year, month, day); + return (to.difference(from).inHours / 24).round().abs(); + } } extension DateTimeNullableExtension on DateTime? { diff --git a/core/pubspec.yaml b/core/pubspec.yaml index 7d87eb532..88fbe806f 100644 --- a/core/pubspec.yaml +++ b/core/pubspec.yaml @@ -72,6 +72,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + + test: 1.16.8 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/core/test/datetime_test.dart b/core/test/datetime_test.dart new file mode 100644 index 000000000..4cc2f1604 --- /dev/null +++ b/core/test/datetime_test.dart @@ -0,0 +1,29 @@ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:core/core.dart'; + +void main() { + group('datetime test', () { + + test('daysBetween should return 1 day2 when day2 > day1', () async { + DateTime date1 = DateTime.parse("2021-10-20 12:59:12.000"); + DateTime date2 = DateTime.parse("2021-10-21 10:29:03.000"); + + expect(date2.daysBetween(date1), 1); + }); + + test('daysBetween should return 1 days when day1 > day2', () async { + DateTime date1 = DateTime.parse("2021-10-22 12:59:12.000"); + DateTime date2 = DateTime.parse("2021-10-21 10:29:03.000"); + + expect(date2.daysBetween(date1), 1); + }); + + test('daysBetween should return 0 day when day1 = day2', () async { + DateTime date1 = DateTime.parse("2021-10-22 12:59:12.000"); + DateTime date2 = DateTime.parse("2021-10-22 10:29:03.000"); + + expect(date2.daysBetween(date1), 0); + }); + }); +} \ No newline at end of file diff --git a/lib/features/cleanup/data/datasource/cleanup_datasource.dart b/lib/features/cleanup/data/datasource/cleanup_datasource.dart new file mode 100644 index 000000000..279c975ee --- /dev/null +++ b/lib/features/cleanup/data/datasource/cleanup_datasource.dart @@ -0,0 +1,10 @@ + +import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; + +abstract class CleanupDataSource { + Future cleanEmailCache(CleanupRule cleanupRule); + + Future saveTimeCleanEmail(DateTime lastTime); + + Future getTimeCleanEmail(); +} \ No newline at end of file diff --git a/lib/features/cleanup/data/datasource_impl/cleanup_datasource_impl.dart b/lib/features/cleanup/data/datasource_impl/cleanup_datasource_impl.dart new file mode 100644 index 000000000..e33d978fe --- /dev/null +++ b/lib/features/cleanup/data/datasource_impl/cleanup_datasource_impl.dart @@ -0,0 +1,42 @@ + +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:tmail_ui_user/features/cleanup/data/datasource/cleanup_datasource.dart'; +import 'package:tmail_ui_user/features/cleanup/data/utils/cleanup_constant.dart'; +import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; +import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; + +class CleanupDataSourceImpl extends CleanupDataSource { + + final EmailCacheManager emailCacheManager; + final SharedPreferences sharedPreferences; + + CleanupDataSourceImpl(this.emailCacheManager, this.sharedPreferences); + + @override + Future cleanEmailCache(CleanupRule cleanupRule) { + return Future.sync(() async { + return await emailCacheManager.clean(cleanupRule); + }).catchError((error) { + throw error; + }); + } + + @override + Future saveTimeCleanEmail(DateTime lastTime) { + return Future.sync(() async { + await sharedPreferences.setString(CleanupConstant.keyTimeCleanupEmail, lastTime.toIso8601String()); + }).catchError((error) { + throw error; + }); + } + + @override + Future getTimeCleanEmail() { + return Future.sync(() async { + final lastTime = sharedPreferences.getString(CleanupConstant.keyTimeCleanupEmail); + return DateTime.tryParse(lastTime ?? ''); + }).catchError((error) { + throw error; + }); + } +} \ No newline at end of file diff --git a/lib/features/cleanup/data/repository/cleanup_repository_impl.dart b/lib/features/cleanup/data/repository/cleanup_repository_impl.dart new file mode 100644 index 000000000..290c7a030 --- /dev/null +++ b/lib/features/cleanup/data/repository/cleanup_repository_impl.dart @@ -0,0 +1,23 @@ + +import 'package:core/core.dart'; +import 'package:tmail_ui_user/features/cleanup/data/datasource/cleanup_datasource.dart'; +import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; +import 'package:tmail_ui_user/features/cleanup/domain/repository/cleanup_repository.dart'; + +class CleanupRepositoryImpl extends CleanupRepository { + + final CleanupDataSource cleanupDataSource; + + CleanupRepositoryImpl(this.cleanupDataSource); + + @override + Future cleanEmailCache(CleanupRule cleanupRule) async { + final lastTimeCleanup = await cleanupDataSource.getTimeCleanEmail(); + if (lastTimeCleanup == null || !lastTimeCleanup.isToday()) { + final isSuccess = await cleanupDataSource.cleanEmailCache(cleanupRule); + if (isSuccess) { + await cleanupDataSource.saveTimeCleanEmail(DateTime.now()); + } + } + } +} \ No newline at end of file diff --git a/lib/features/cleanup/data/utils/cleanup_constant.dart b/lib/features/cleanup/data/utils/cleanup_constant.dart new file mode 100644 index 000000000..7827ccd31 --- /dev/null +++ b/lib/features/cleanup/data/utils/cleanup_constant.dart @@ -0,0 +1,3 @@ +class CleanupConstant { + static const keyTimeCleanupEmail = 'KEY_TIME_CLEANUP_EMAIL'; +} \ No newline at end of file diff --git a/lib/features/thread/data/extensions/email_cache_extension.dart b/lib/features/thread/data/extensions/email_cache_extension.dart index 397dd2306..96d453c67 100644 --- a/lib/features/thread/data/extensions/email_cache_extension.dart +++ b/lib/features/thread/data/extensions/email_cache_extension.dart @@ -1,10 +1,12 @@ +import 'package:core/core.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/email_address_hive_cache_extension.dart'; @@ -31,4 +33,15 @@ extension EmailCacheExtension on EmailCache { : null, ); } + + bool expireTimeCaching(CleanupRule cleanupRule) { + final currentTime = DateTime.now(); + if (receivedAt != null) { + final countDay = currentTime.daysBetween(receivedAt!.toLocal()); + if (countDay >= cleanupRule.cachingEmailPeriod.countDay) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/lib/features/thread/data/local/email_cache_manager.dart b/lib/features/thread/data/local/email_cache_manager.dart index 804c1a53e..29a112c9a 100644 --- a/lib/features/thread/data/local/email_cache_manager.dart +++ b/lib/features/thread/data/local/email_cache_manager.dart @@ -3,6 +3,7 @@ import 'package:model/model.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/caching/email_cache_client.dart'; +import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/email_cache_extension.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/email_extension.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/list_email_cache_extension.dart'; @@ -49,5 +50,17 @@ class EmailCacheManager { } } - + Future clean(CleanupRule cleanupRule) async { + final emailCacheExist = await _emailCacheClient.isExistTable(); + if (emailCacheExist) { + final listEmailCache = await _emailCacheClient.getAll(); + final listEmailIdCacheExpire = listEmailCache + .where((emailCache) => emailCache.expireTimeCaching(cleanupRule)) + .map((emailCache) => emailCache.id) + .toList(); + await _emailCacheClient.deleteMultipleItem(listEmailIdCacheExpire); + return true; + } + return false; + } } \ No newline at end of file