From 94d683c3c1176802ca9095ddd84ca0c132fa299d Mon Sep 17 00:00:00 2001 From: DatDang Date: Wed, 17 Apr 2024 10:15:29 +0700 Subject: [PATCH] TF-2802 Add calendar event accept interactor to single email controller --- .../datasource/calendar_event_datasource.dart | 4 +- .../calendar_event_datasource_impl.dart | 4 +- .../local_calendar_event_datasource_impl.dart | 4 +- .../data/network/calendar_event_api.dart | 10 ++- .../calendar_event_repository_impl.dart | 10 +-- .../repository/calendar_event_repository.dart | 7 +- .../state/parse_calendar_event_state.dart | 11 ++- .../parse_calendar_event_interactor.dart | 24 +------ .../calendar_event_interactor_bindings.dart | 2 + .../controller/single_email_controller.dart | 65 +++++++++++++++-- .../email/presentation/email_view.dart | 10 ++- .../model/blob_calendar_event.dart | 13 ++++ .../calendar_event_action_button_widget.dart | 9 ++- .../calendar_event_detail_widget.dart | 6 +- .../calendar_event_information_widget.dart | 19 ++--- lib/l10n/intl_messages.arb | 24 +++++++ lib/main/localizations/app_localizations.dart | 28 ++++++++ .../single_email_controller_test.dart | 71 +++++++++++++++---- 18 files changed, 222 insertions(+), 99 deletions(-) create mode 100644 lib/features/email/presentation/model/blob_calendar_event.dart diff --git a/lib/features/email/data/datasource/calendar_event_datasource.dart b/lib/features/email/data/datasource/calendar_event_datasource.dart index 2d69cc756..8d22443b1 100644 --- a/lib/features/email/data/datasource/calendar_event_datasource.dart +++ b/lib/features/email/data/datasource/calendar_event_datasource.dart @@ -1,12 +1,12 @@ 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:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.dart'; import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; abstract class CalendarEventDataSource { - Future>> parse(AccountId accountId, Set blobIds); + Future> parse(AccountId accountId, Set blobIds); Future> getListEventAction(String emailContents); 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 index 5edca91c5..b7acfab19 100644 --- a/lib/features/email/data/datasource_impl/calendar_event_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/calendar_event_datasource_impl.dart @@ -1,11 +1,11 @@ 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:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.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/features/email/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class CalendarEventDataSourceImpl extends CalendarEventDataSource { @@ -16,7 +16,7 @@ class CalendarEventDataSourceImpl extends CalendarEventDataSource { CalendarEventDataSourceImpl(this._calendarEventAPI, this._exceptionThrower); @override - Future>> parse(AccountId accountId, Set blobIds) { + Future> parse(AccountId accountId, Set blobIds) { return Future.sync(() async { return await _calendarEventAPI.parse(accountId, blobIds); }).catchError(_exceptionThrower.throwException); diff --git a/lib/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart b/lib/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart index b289e70bc..f72a4d559 100644 --- a/lib/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart @@ -1,11 +1,11 @@ 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:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.dart'; import 'package:tmail_ui_user/features/email/data/datasource/calendar_event_datasource.dart'; import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class LocalCalendarEventDataSourceImpl extends CalendarEventDataSource { @@ -16,7 +16,7 @@ class LocalCalendarEventDataSourceImpl extends CalendarEventDataSource { LocalCalendarEventDataSourceImpl(this._htmlAnalyzer, this._exceptionThrower); @override - Future>> parse(AccountId accountId, Set blobIds) { + Future> parse(AccountId accountId, Set blobIds) { throw UnimplementedError(); } diff --git a/lib/features/email/data/network/calendar_event_api.dart b/lib/features/email/data/network/calendar_event_api.dart index ebb38dcda..58926cd12 100644 --- a/lib/features/email/data/network/calendar_event_api.dart +++ b/lib/features/email/data/network/calendar_event_api.dart @@ -4,12 +4,12 @@ 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:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_method.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/calendar_event_exceptions.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; class CalendarEventAPI { @@ -17,7 +17,7 @@ class CalendarEventAPI { CalendarEventAPI(this._httpClient); - Future>> parse(AccountId accountId, Set blobIds) async { + Future> parse(AccountId accountId, Set blobIds) async { final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); final calendarEventParseMethod = CalendarEventParseMethod(accountId, blobIds); final calendarEventParseInvocation = requestBuilder.invocation(calendarEventParseMethod); @@ -31,7 +31,11 @@ class CalendarEventAPI { CalendarEventParseResponse.deserialize); if (calendarEventParseResponse?.parsed?.isNotEmpty == true) { - return calendarEventParseResponse!.parsed!; + return calendarEventParseResponse!.parsed!.entries + .map((entry) => BlobCalendarEvent( + blobId: entry.key, + calendarEventList: entry.value)) + .toList(); } else if (calendarEventParseResponse?.notParsable?.isNotEmpty == true) { throw NotParsableCalendarEventException(); } else if (calendarEventParseResponse?.notFound?.isNotEmpty == true) { diff --git a/lib/features/email/data/repository/calendar_event_repository_impl.dart b/lib/features/email/data/repository/calendar_event_repository_impl.dart index c62384f4f..5e66fb533 100644 --- a/lib/features/email/data/repository/calendar_event_repository_impl.dart +++ b/lib/features/email/data/repository/calendar_event_repository_impl.dart @@ -2,11 +2,10 @@ import 'package:core/data/model/source_type/data_source_type.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/mail/calendar/calendar_event.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.dart'; import 'package:tmail_ui_user/features/email/data/datasource/calendar_event_datasource.dart'; -import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/domain/repository/calendar_event_repository.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; class CalendarEventRepositoryImpl extends CalendarEventRepository { @@ -15,15 +14,10 @@ class CalendarEventRepositoryImpl extends CalendarEventRepository { CalendarEventRepositoryImpl(this._calendarEventDataSource); @override - Future>> parse(AccountId accountId, Set blobIds) { + Future> parse(AccountId accountId, Set blobIds) { return _calendarEventDataSource[DataSourceType.network]!.parse(accountId, blobIds); } - @override - Future> getListEventAction(String emailContents) { - return _calendarEventDataSource[DataSourceType.local]!.getListEventAction(emailContents); - } - @override Future acceptEventInvitation(AccountId accountId, Set blobIds) { return _calendarEventDataSource[DataSourceType.network]!.acceptEventInvitation(accountId, blobIds); diff --git a/lib/features/email/domain/repository/calendar_event_repository.dart b/lib/features/email/domain/repository/calendar_event_repository.dart index 302ac75b8..95847476c 100644 --- a/lib/features/email/domain/repository/calendar_event_repository.dart +++ b/lib/features/email/domain/repository/calendar_event_repository.dart @@ -1,14 +1,11 @@ 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:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_response.dart'; -import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; abstract class CalendarEventRepository { - Future>> parse(AccountId accountId, Set blobIds); - - Future> getListEventAction(String emailContents); + Future> parse(AccountId accountId, Set blobIds); Future acceptEventInvitation(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 index 75b260b19..e1db48004 100644 --- a/lib/features/email/domain/state/parse_calendar_event_state.dart +++ b/lib/features/email/domain/state/parse_calendar_event_state.dart @@ -1,20 +1,17 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.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/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; class ParseCalendarEventLoading extends LoadingState {} class ParseCalendarEventSuccess extends UIState { - final Map> calendarEventMap; - final List eventActionList; + final List blobCalendarEventList; - ParseCalendarEventSuccess(this.calendarEventMap, this.eventActionList); + ParseCalendarEventSuccess(this.blobCalendarEventList); @override - List get props => [calendarEventMap, eventActionList]; + List get props => [blobCalendarEventList]; } class ParseCalendarEventFailure extends FeatureFailure { diff --git a/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart b/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart index 43772c298..55b11e5fb 100644 --- a/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart +++ b/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart @@ -3,9 +3,7 @@ import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.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/mail/calendar/calendar_event.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/calendar_event_exceptions.dart'; -import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/domain/repository/calendar_event_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart'; @@ -22,26 +20,10 @@ class ParseCalendarEventInteractor { try { yield Right(ParseCalendarEventLoading()); - final listResult = await Future.wait( - [ - _calendarEventRepository.parse(accountId, blobIds), - _calendarEventRepository.getListEventAction(emailContents), - ], - eagerError: true - ); + final listBlobCalendarEvent = await _calendarEventRepository.parse(accountId, blobIds); - final mapCalendarEvent = >{}; - final listEventAction = List.empty(growable: true); - - if (listResult[0] is Map>) { - mapCalendarEvent.addAll(listResult[0] as Map>); - } - if (listResult[1] is List) { - listEventAction.addAll(listResult[1] as List); - } - - if (mapCalendarEvent.isNotEmpty) { - yield Right(ParseCalendarEventSuccess(mapCalendarEvent, listEventAction)); + if (listBlobCalendarEvent.isNotEmpty) { + yield Right(ParseCalendarEventSuccess(listBlobCalendarEvent)); } else { yield Left(ParseCalendarEventFailure(NotFoundCalendarEventException())); } diff --git a/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart b/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart index fdf4369a2..788d05119 100644 --- a/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart +++ b/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart @@ -9,6 +9,7 @@ import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/calendar_event_api.dart'; import 'package:tmail_ui_user/features/email/data/repository/calendar_event_repository_impl.dart'; import 'package:tmail_ui_user/features/email/domain/repository/calendar_event_repository.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; @@ -34,6 +35,7 @@ class CalendarEventInteractorBindings extends InteractorsBindings { @override void bindingsInteractor() { Get.lazyPut(() => ParseCalendarEventInteractor(Get.find())); + Get.lazyPut(() => AcceptCalendarEventInteractor(Get.find())); } @override diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 479cdc230..23c7c541c 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -36,6 +36,8 @@ import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart' import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; +import 'package:tmail_ui_user/features/email/domain/state/calendar_event_accept_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/calendar_event_reply_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachments_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart'; @@ -48,6 +50,7 @@ import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/view_attachment_for_web_state.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; @@ -63,6 +66,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/view_attachment_for import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/calendar_event_interactor_bindings.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart'; @@ -119,11 +123,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin { CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor; SendReceiptToSenderInteractor? _sendReceiptToSenderInteractor; ParseCalendarEventInteractor? _parseCalendarEventInteractor; + AcceptCalendarEventInteractor? _acceptCalendarEventInteractor; final emailContents = RxnString(); final attachments = [].obs; - final calendarEvent = Rxn(); - final eventActions = [].obs; + final blobCalendarEvent = Rxn(); final emailLoadedViewState = Rx>(Right(UIState.idle)); final emailUnsubscribe = Rxn(); final attachmentsViewState = RxMap>(); @@ -141,6 +145,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin { EmailLoaded? get currentEmailLoaded => _currentEmailLoaded; + bool get calendarEventProcessing => viewState.value is CalendarEventReplying; + + CalendarEvent? get calendarEvent => blobCalendarEvent.value?.calendarEventList.firstOrNull; + Id? get _displayingEventBlobId => blobCalendarEvent.value?.blobId; + SingleEmailController( this._getEmailContentInteractor, this._markAsEmailReadInteractor, @@ -212,6 +221,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _showMessageWhenStartingEmailPrinting(); } else if (success is PrintEmailSuccess) { _handlePrintEmailSuccess(success); + } else if (success is CalendarEventReplySuccess) { + _calendarEventSuccess(success); } } @@ -234,6 +245,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { emailLoadedViewState.value = Left(failure); } else if (failure is PrintEmailFailure) { _showMessageWhenEmailPrintingFailed(failure); + } else if (failure is CalendarEventReplyFailure) { + _calendarEventFailure(); } } @@ -373,6 +386,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _createNewEmailRuleFilterInteractor = getBinding(); _sendReceiptToSenderInteractor = getBinding(); _parseCalendarEventInteractor = getBinding(); + _acceptCalendarEventInteractor = getBinding(); } void _injectCalendarEventBindings(Session? session, AccountId? accountId) { @@ -593,8 +607,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _currentEmailLoaded = null; attachments.clear(); attachmentsViewState.value = {}; - calendarEvent.value = null; - eventActions.clear(); + blobCalendarEvent.value = null; emailUnsubscribe.value = null; _printEmailAction = null; if (isEmailClosing) { @@ -1465,8 +1478,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _handleParseCalendarEventSuccess(ParseCalendarEventSuccess success) { emailLoadedViewState.value = Right(success); - calendarEvent.value = success.calendarEventMap.values.first.first; - eventActions.value = success.eventActionList; + blobCalendarEvent.value = success.blobCalendarEventList.first; if (PlatformInfo.isMobile) { _enableScrollPageView(); } @@ -1671,4 +1683,45 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ) ); } + + void onCalendarEventReplyAction(EventAction eventAction) { + switch (eventAction.actionType) { + case EventActionType.yes: + _acceptCalendarEventAction(); + break; + default: + break; + } + } + + void _acceptCalendarEventAction() { + if (_acceptCalendarEventInteractor == null || _displayingEventBlobId == null) return; + + if (mailboxDashBoardController.accountId.value != null) { + consumeState(_acceptCalendarEventInteractor!.execute( + mailboxDashBoardController.accountId.value!, + {_displayingEventBlobId!})); + } else { + consumeState(Stream.value(Left(CalendarEventAcceptFailure()))); + } + } + + void _calendarEventSuccess(CalendarEventReplySuccess success) { + if (currentOverlayContext != null && currentContext != null) { + final appLocalization = AppLocalizations.of(currentContext!); + if (success is CalendarEventAccepted) { + appToast.showToastSuccessMessage( + currentOverlayContext!, + appLocalization.youWillAttendThisMeeting); + } + } + } + + void _calendarEventFailure() { + if (currentOverlayContext != null && currentContext != null) { + appToast.showToastErrorMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).eventReplyWasSentUnsuccessfully); + } + } } \ No newline at end of file diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 3af984622..57f2ed36a 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -147,14 +147,14 @@ class EmailView extends GetWidget { child: Obx(() => _buildEmailMessage( context: context, presentationEmail: currentEmail, - calendarEvent: controller.calendarEvent.value, + calendarEvent: controller.calendarEvent, maxBodyHeight: constraints.maxHeight )) ) ); } else { return Obx(() { - final calendarEvent = controller.calendarEvent.value; + final calendarEvent = controller.calendarEvent; if (currentEmail.hasCalendarEvent && calendarEvent != null) { return Padding( padding: const EdgeInsetsDirectional.symmetric(horizontal: 4), @@ -199,14 +199,14 @@ class EmailView extends GetWidget { child: Obx(() => _buildEmailMessage( context: context, presentationEmail: currentEmail, - calendarEvent: controller.calendarEvent.value, + calendarEvent: controller.calendarEvent, maxBodyHeight: constraints.maxHeight )) ) ); } else { return Obx(() { - final calendarEvent = controller.calendarEvent.value; + final calendarEvent = controller.calendarEvent; if (currentEmail.hasCalendarEvent && calendarEvent != null) { return Padding( padding: const EdgeInsetsDirectional.symmetric(horizontal: 4), @@ -373,7 +373,6 @@ class EmailView extends GetWidget { children: [ CalendarEventInformationWidget( calendarEvent: calendarEvent, - eventActions: controller.eventActions, onOpenComposerAction: controller.openNewComposerAction, onOpenNewTabAction: controller.openNewTabAction, ), @@ -384,7 +383,6 @@ class EmailView extends GetWidget { ), CalendarEventDetailWidget( calendarEvent: calendarEvent, - eventActions: controller.eventActions, emailContent: controller.currentEmailLoaded?.htmlContent ?? '', isDraggableAppActive: controller.mailboxDashBoardController.isDraggableAppActive, onOpenComposerAction: controller.openNewComposerAction, diff --git a/lib/features/email/presentation/model/blob_calendar_event.dart b/lib/features/email/presentation/model/blob_calendar_event.dart new file mode 100644 index 000000000..5a333ef86 --- /dev/null +++ b/lib/features/email/presentation/model/blob_calendar_event.dart @@ -0,0 +1,13 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; + +class BlobCalendarEvent with EquatableMixin { + final Id blobId; + final List calendarEventList; + + BlobCalendarEvent({required this.blobId, required this.calendarEventList}); + + @override + List get props => [blobId, calendarEventList]; +} \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/calendar_event/calendar_event_action_button_widget.dart b/lib/features/email/presentation/widgets/calendar_event/calendar_event_action_button_widget.dart index 4288fad81..609764bd6 100644 --- a/lib/features/email/presentation/widgets/calendar_event/calendar_event_action_button_widget.dart +++ b/lib/features/email/presentation/widgets/calendar_event/calendar_event_action_button_widget.dart @@ -8,12 +8,10 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart'; class CalendarEventActionButtonWidget extends StatelessWidget { - final List eventActions; final EdgeInsetsGeometry? margin; const CalendarEventActionButtonWidget({ super.key, - required this.eventActions, this.margin, }); @@ -29,9 +27,9 @@ class CalendarEventActionButtonWidget extends StatelessWidget { child: Wrap( spacing: CalendarEventActionButtonWidgetStyles.space, runSpacing: CalendarEventActionButtonWidgetStyles.space, - children: eventActions + children: EventActionType.values .map((action) => TMailButtonWidget( - text: action.actionType.getLabelButton(context), + text: action.getLabelButton(context), backgroundColor: CalendarEventActionButtonWidgetStyles.backgroundColor, borderRadius: CalendarEventActionButtonWidgetStyles.borderRadius, padding: CalendarEventActionButtonWidgetStyles.buttonPadding, @@ -47,7 +45,8 @@ class CalendarEventActionButtonWidget extends StatelessWidget { width: CalendarEventActionButtonWidgetStyles.borderWidth, color: CalendarEventActionButtonWidgetStyles.textColor ), - onTapActionCallback: () => AppUtils.launchLink(action.link), + // TODO: Handle in part 4 + onTapActionCallback: () => AppUtils.launchLink(''), )) .toList(), ), diff --git a/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart b/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart index 75324a69e..4908b3ac6 100644 --- a/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart +++ b/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart @@ -2,7 +2,6 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; -import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/styles/calendar_event_detail_widget_styles.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_action_button_widget.dart'; @@ -17,7 +16,6 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart'; class CalendarEventDetailWidget extends StatelessWidget { final CalendarEvent calendarEvent; - final List eventActions; final String emailContent; final OnOpenNewTabAction? onOpenNewTabAction; final OnOpenComposerAction? onOpenComposerAction; @@ -27,7 +25,6 @@ class CalendarEventDetailWidget extends StatelessWidget { const CalendarEventDetailWidget({ super.key, required this.calendarEvent, - required this.eventActions, required this.emailContent, this.isDraggableAppActive, this.onOpenNewTabAction, @@ -92,8 +89,7 @@ class CalendarEventDetailWidget extends StatelessWidget { organizer: calendarEvent.organizer!, ), ), - if (eventActions.isNotEmpty) - CalendarEventActionButtonWidget(eventActions: eventActions), + const CalendarEventActionButtonWidget(), ], ), ); diff --git a/lib/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart b/lib/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart index d2ab65b8b..e47949cb8 100644 --- a/lib/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart +++ b/lib/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart @@ -4,7 +4,6 @@ import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; -import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/styles/calendar_event_information_widget_styles.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_date_icon_widget.dart'; @@ -20,14 +19,12 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart'; class CalendarEventInformationWidget extends StatelessWidget { final CalendarEvent calendarEvent; - final List eventActions; final OnOpenNewTabAction? onOpenNewTabAction; final OnOpenComposerAction? onOpenComposerAction; const CalendarEventInformationWidget({ super.key, required this.calendarEvent, - required this.eventActions, this.onOpenNewTabAction, this.onOpenComposerAction, }); @@ -113,11 +110,9 @@ class CalendarEventInformationWidget extends StatelessWidget { organizer: calendarEvent.organizer!, ), ), - if (eventActions.isNotEmpty) - CalendarEventActionButtonWidget( - eventActions: eventActions, - margin: EdgeInsetsDirectional.zero, - ), + const CalendarEventActionButtonWidget( + margin: EdgeInsetsDirectional.zero, + ), ], ), ) @@ -183,11 +178,9 @@ class CalendarEventInformationWidget extends StatelessWidget { organizer: calendarEvent.organizer!, ), ), - if (eventActions.isNotEmpty) - CalendarEventActionButtonWidget( - eventActions: eventActions, - margin: EdgeInsetsDirectional.zero, - ), + const CalendarEventActionButtonWidget( + margin: EdgeInsetsDirectional.zero, + ), ], ), )) diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 7d4629b12..8b095991f 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -3695,5 +3695,29 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "eventReplyWasSentUnsuccessfully": "Event reply was sent unsuccessfully!", + "@eventReplyWasSentUnsuccessfully": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "youWillAttendThisMeeting": "You will attend this meeting", + "@youWillAttendThisMeeting": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "youWillNotAttendThisMeeting": "You will not attend this meeting", + "@youWillNotAttendThisMeeting": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "youMayAttendThisMeeting": "You may attend this meeting", + "@youMayAttendThisMeeting": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 86450eae0..176ff8a04 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -3851,4 +3851,32 @@ class AppLocalizations { name: 'noSuitableBrowserForOIDC' ); } + + String get eventReplyWasSentUnsuccessfully { + return Intl.message( + 'Event reply was sent unsuccessfully!', + name: 'eventReplyWasSentUnsuccessfully', + ); + } + + String get youWillAttendThisMeeting { + return Intl.message( + 'You will attend this meeting', + name: 'youWillAttendThisMeeting', + ); + } + + String get youWillNotAttendThisMeeting { + return Intl.message( + 'You will not attend this meeting', + name: 'youWillNotAttendThisMeeting', + ); + } + + String get youMayAttendThisMeeting { + return Intl.message( + 'You may attend this meeting', + name: 'youMayAttendThisMeeting', + ); + } } \ No newline at end of file diff --git a/test/features/email/presentation/controller/single_email_controller_test.dart b/test/features/email/presentation/controller/single_email_controller_test.dart index c3233e3d4..ecbca6555 100644 --- a/test/features/email/presentation/controller/single_email_controller_test.dart +++ b/test/features/email/presentation/controller/single_email_controller_test.dart @@ -9,11 +9,15 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; +import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; +import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/view_attachment_for_web_state.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; @@ -26,6 +30,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_ import 'package:tmail_ui_user/features/email/domain/usecases/view_attachment_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/features/login/data/network/interceptors/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'; @@ -71,6 +76,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -103,20 +109,7 @@ void main() { final uuid = MockUuid(); final printEmailInteractor = MockPrintEmailInteractor(); - late SingleEmailController singleEmailController = SingleEmailController( - getEmailContentInteractor, - markAsEmailReadInteractor, - downloadAttachmentsInteractor, - deviceManager, - exportAttachmentInteractor, - moveToMailboxInteractor, - markAsStarEmailInteractor, - downloadAttachmentForWebInteractor, - getAllIdentitiesInteractor, - storeOpenedEmailInteractor, - viewAttachmentForWebInteractor, - printEmailInteractor, - ); + late SingleEmailController singleEmailController; final testAccountId = AccountId(Id('123')); final google = Uri.parse('https://www.google.com'); @@ -150,6 +143,23 @@ void main() { when(uuid.v4()).thenReturn(testTaskId); }); + setUp(() { + singleEmailController = SingleEmailController( + getEmailContentInteractor, + markAsEmailReadInteractor, + downloadAttachmentsInteractor, + deviceManager, + exportAttachmentInteractor, + moveToMailboxInteractor, + markAsStarEmailInteractor, + downloadAttachmentForWebInteractor, + getAllIdentitiesInteractor, + storeOpenedEmailInteractor, + viewAttachmentForWebInteractor, + printEmailInteractor, + ); + }); + group('single email controller', () { test( 'should call execute on ViewAttachmentForWebInteractor ' @@ -252,4 +262,37 @@ void main() { }, ); }); + + group('calendar event reply test:', () { + final blobId = Id('abc123'); + final calendarEvent = CalendarEvent(); + + group('accept test:', () { + final acceptCalendarEventInteractor = MockAcceptCalendarEventInteractor(); + + test('should call execute on AcceptCalendarEventInteractor ' + 'when onCalendarEventReplyAction is called on EventActionType.yes', () async { + // arrange + when(mailboxDashboardController.selectedEmail).thenReturn(Rxn(null)); + when(mailboxDashboardController.emailUIAction).thenReturn(Rxn(null)); + when(mailboxDashboardController.viewState).thenReturn(Rx(Right(UIState.idle))); + singleEmailController.onInit(); + Get.put(acceptCalendarEventInteractor); + mailboxDashboardController.accountId.refresh(); + singleEmailController.handleSuccessViewState( + ParseCalendarEventSuccess([ + BlobCalendarEvent( + blobId: blobId, + calendarEventList: [calendarEvent])])); + + // act + singleEmailController.onCalendarEventReplyAction( + EventAction(EventActionType.yes, '')); + await untilCalled(acceptCalendarEventInteractor.execute(any, any)); + + // assert + verify(acceptCalendarEventInteractor.execute(testAccountId, {blobId})).called(1); + }); + }); + }); }