diff --git a/assets/images/ic_event_canceled.svg b/assets/images/ic_event_canceled.svg
new file mode 100644
index 0000000000..7b011b5a95
--- /dev/null
+++ b/assets/images/ic_event_canceled.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/ic_event_invited.svg b/assets/images/ic_event_invited.svg
new file mode 100644
index 0000000000..4497cc4d99
--- /dev/null
+++ b/assets/images/ic_event_invited.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/ic_event_updated.svg b/assets/images/ic_event_updated.svg
new file mode 100644
index 0000000000..c339cd6a42
--- /dev/null
+++ b/assets/images/ic_event_updated.svg
@@ -0,0 +1,5 @@
+
diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart
index b2282e779c..be56651b36 100644
--- a/core/lib/presentation/extensions/color_extension.dart
+++ b/core/lib/presentation/extensions/color_extension.dart
@@ -186,6 +186,11 @@ extension AppColor on Color {
static const colorNetworkConnectionLabel = Color(0xFF818C99);
static const colorCalendarEventRead = Color(0xFF818C99);
static const colorCalendarEventUnread = Color(0xFF1C1B1F);
+ static const colorMaybeEventActionText = Color(0xFFFFC107);
+ static const colorInvitedEventActionText = Color(0xFF007AFF);
+ static const colorUpdatedEventActionText = Color(0xFF4BB34B);
+ static const colorCanceledEventActionText = Color(0xFFFF3347);
+ static const colorSubTitleEventActionText = Color(0xFF939393);
static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)],
diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart
index 4508fc577e..d5a010dd7c 100644
--- a/core/lib/presentation/resources/image_paths.dart
+++ b/core/lib/presentation/resources/image_paths.dart
@@ -195,6 +195,9 @@ class ImagePaths {
String get icArrowRight => _getImagePath('ic_arrow_right.svg');
String get icAddPicture => _getImagePath('ic_add_picture.svg');
String get icCalendarEvent => _getImagePath('ic_calendar_event.svg');
+ String get icEventInvited => _getImagePath('ic_event_invited.svg');
+ String get icEventUpdated => _getImagePath('ic_event_updated.svg');
+ String get icEventCanceled => _getImagePath('ic_event_canceled.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart
index 6ca202abc2..b3555b5b1d 100644
--- a/lib/features/base/base_controller.dart
+++ b/lib/features/base/base_controller.dart
@@ -22,7 +22,7 @@ import 'package:rule_filter/rule_filter/capability_rule_filter.dart';
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
-import 'package:tmail_ui_user/features/email/presentation/mdn_interactor_bindings.dart';
+import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart';
import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
diff --git a/lib/features/email/data/datasource/calendar_event_datasource.dart b/lib/features/email/data/datasource/calendar_event_datasource.dart
new file mode 100644
index 0000000000..3f34688d1b
--- /dev/null
+++ b/lib/features/email/data/datasource/calendar_event_datasource.dart
@@ -0,0 +1,8 @@
+
+import 'package:jmap_dart_client/jmap/account_id.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+
+abstract class CalendarEventDataSource {
+ Future> parse(AccountId accountId, Set blobIds);
+}
\ No newline at end of file
diff --git a/lib/features/email/data/datasource_impl/calendar_event_datasource_impl.dart b/lib/features/email/data/datasource_impl/calendar_event_datasource_impl.dart
new file mode 100644
index 0000000000..aabcc5193a
--- /dev/null
+++ b/lib/features/email/data/datasource_impl/calendar_event_datasource_impl.dart
@@ -0,0 +1,22 @@
+
+import 'package:jmap_dart_client/jmap/account_id.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+import 'package:tmail_ui_user/features/email/data/datasource/calendar_event_datasource.dart';
+import 'package:tmail_ui_user/features/email/data/network/calendar_event_api.dart';
+import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
+
+class CalendarEventDataSourceImpl extends CalendarEventDataSource {
+
+ final CalendarEventAPI _calendarEventAPI;
+ final ExceptionThrower _exceptionThrower;
+
+ CalendarEventDataSourceImpl(this._calendarEventAPI, this._exceptionThrower);
+
+ @override
+ Future> parse(AccountId accountId, Set blobIds) {
+ return Future.sync(() async {
+ return await _calendarEventAPI.parse(accountId, blobIds);
+ }).catchError(_exceptionThrower.throwException);
+ }
+}
\ No newline at end of file
diff --git a/lib/features/email/data/network/calendar_event_api.dart b/lib/features/email/data/network/calendar_event_api.dart
new file mode 100644
index 0000000000..19ce720465
--- /dev/null
+++ b/lib/features/email/data/network/calendar_event_api.dart
@@ -0,0 +1,41 @@
+import 'dart:async';
+
+import 'package:jmap_dart_client/http/http_client.dart';
+import 'package:jmap_dart_client/jmap/account_id.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
+import 'package:jmap_dart_client/jmap/jmap_request.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/parse/calendar_event_parse_method.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/parse/calendar_event_parse_response.dart';
+import 'package:tmail_ui_user/features/email/domain/exceptions/calendar_event_exceptions.dart';
+
+class CalendarEventAPI {
+
+ final HttpClient _httpClient;
+
+ CalendarEventAPI(this._httpClient);
+
+ Future> parse(AccountId accountId, Set blobIds) async {
+ final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation());
+ final calendarEventParseMethod = CalendarEventParseMethod(accountId, blobIds);
+ final calendarEventParseInvocation = requestBuilder.invocation(calendarEventParseMethod);
+ final response = await (requestBuilder
+ ..usings(calendarEventParseMethod.requiredCapabilities))
+ .build()
+ .execute();
+
+ final calendarEventParseResponse = response.parse(
+ calendarEventParseInvocation.methodCallId,
+ CalendarEventParseResponse.deserialize);
+
+ if (calendarEventParseResponse?.parsed?.isNotEmpty == true) {
+ return calendarEventParseResponse!.parsed!.values.toList();
+ } else if (calendarEventParseResponse?.notParsable?.isNotEmpty == true) {
+ throw NotParsableCalendarEventException();
+ } else if (calendarEventParseResponse?.notFound?.isNotEmpty == true) {
+ throw NotFoundCalendarEventException();
+ } else {
+ throw NotParsableCalendarEventException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/features/email/data/repository/calendar_event_repository_impl.dart b/lib/features/email/data/repository/calendar_event_repository_impl.dart
new file mode 100644
index 0000000000..9d94ecc749
--- /dev/null
+++ b/lib/features/email/data/repository/calendar_event_repository_impl.dart
@@ -0,0 +1,18 @@
+
+import 'package:jmap_dart_client/jmap/account_id.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+import 'package:tmail_ui_user/features/email/data/datasource/calendar_event_datasource.dart';
+import 'package:tmail_ui_user/features/email/domain/repository/calendar_event_repository.dart';
+
+class CalendarEventRepositoryImpl extends CalendarEventRepository {
+
+ final CalendarEventDataSource _calendarEventDataSource;
+
+ CalendarEventRepositoryImpl(this._calendarEventDataSource);
+
+ @override
+ Future> parse(AccountId accountId, Set blobIds) {
+ return _calendarEventDataSource.parse(accountId, blobIds);
+ }
+}
\ No newline at end of file
diff --git a/lib/features/email/domain/exceptions/calendar_event_exceptions.dart b/lib/features/email/domain/exceptions/calendar_event_exceptions.dart
new file mode 100644
index 0000000000..1129d36f55
--- /dev/null
+++ b/lib/features/email/domain/exceptions/calendar_event_exceptions.dart
@@ -0,0 +1,4 @@
+
+class NotFoundCalendarEventException implements Exception {}
+
+class NotParsableCalendarEventException implements Exception {}
\ No newline at end of file
diff --git a/lib/features/email/domain/extensions/list_attachments_extension.dart b/lib/features/email/domain/extensions/list_attachments_extension.dart
index 1cbfc601a3..bd9a0fc08a 100644
--- a/lib/features/email/domain/extensions/list_attachments_extension.dart
+++ b/lib/features/email/domain/extensions/list_attachments_extension.dart
@@ -1,8 +1,17 @@
+import 'package:collection/collection.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:model/email/attachment.dart';
import 'package:tmail_ui_user/features/email/domain/extensions/attachment_extension.dart';
import 'package:tmail_ui_user/features/offline_mode/model/attachment_hive_cache.dart';
extension ListAttachmentsExtension on List {
List toHiveCache() => map((attachment) => attachment.toHiveCache()).toList();
+
+ Set get calendarAttachments => where((attachment) => attachment.isCalendarEvent).toSet();
+
+ Set get calendarEventBlobIds => calendarAttachments
+ .map((attachment) => attachment.blobId)
+ .whereNotNull()
+ .toSet();
}
\ No newline at end of file
diff --git a/lib/features/email/domain/repository/calendar_event_repository.dart b/lib/features/email/domain/repository/calendar_event_repository.dart
new file mode 100644
index 0000000000..809b12c7e3
--- /dev/null
+++ b/lib/features/email/domain/repository/calendar_event_repository.dart
@@ -0,0 +1,8 @@
+
+import 'package:jmap_dart_client/jmap/account_id.dart';
+import 'package:jmap_dart_client/jmap/core/id.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+
+abstract class CalendarEventRepository {
+ Future> parse(AccountId accountId, Set blobIds);
+}
\ No newline at end of file
diff --git a/lib/features/email/domain/state/parse_calendar_event_state.dart b/lib/features/email/domain/state/parse_calendar_event_state.dart
new file mode 100644
index 0000000000..4d1be20264
--- /dev/null
+++ b/lib/features/email/domain/state/parse_calendar_event_state.dart
@@ -0,0 +1,19 @@
+import 'package:core/presentation/state/failure.dart';
+import 'package:core/presentation/state/success.dart';
+import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
+
+class ParseCalendarEventLoading extends LoadingState {}
+
+class ParseCalendarEventSuccess extends UIState {
+
+ final List calendarEventList;
+
+ ParseCalendarEventSuccess(this.calendarEventList);
+
+ @override
+ List