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 aabcc5193..2dfca5a8e 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 @@ -4,6 +4,7 @@ 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/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class CalendarEventDataSourceImpl extends CalendarEventDataSource { @@ -19,4 +20,9 @@ class CalendarEventDataSourceImpl extends CalendarEventDataSource { return await _calendarEventAPI.parse(accountId, blobIds); }).catchError(_exceptionThrower.throwException); } + + @override + Future> getListEventAction(String emailContents) { + throw UnimplementedError(); + } } \ No newline at end of file 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 new file mode 100644 index 000000000..54f2cb8be --- /dev/null +++ b/lib/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart @@ -0,0 +1,36 @@ + +import 'package:collection/collection.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/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/main/exceptions/exception_thrower.dart'; + +class LocalCalendarEventDataSourceImpl extends CalendarEventDataSource { + + final HtmlAnalyzer _htmlAnalyzer; + final ExceptionThrower _exceptionThrower; + + LocalCalendarEventDataSourceImpl(this._htmlAnalyzer, this._exceptionThrower); + + @override + Future> parse(AccountId accountId, Set blobIds) { + throw UnimplementedError(); + } + + @override + Future> getListEventAction(String emailContents) { + return Future.sync(() async { + final listLink = await _htmlAnalyzer.getListLinkCalendarEvent(emailContents); + if (listLink.length >= EventActionType.values.length) { + return EventActionType.values + .mapIndexed((index, type) => EventAction(type, listLink[index])) + .toList(); + } else { + return []; + } + }).catchError(_exceptionThrower.throwException); + } +} \ No newline at end of file diff --git a/lib/features/email/data/local/html_analyzer.dart b/lib/features/email/data/local/html_analyzer.dart index ef9531227..c7127a81a 100644 --- a/lib/features/email/data/local/html_analyzer.dart +++ b/lib/features/email/data/local/html_analyzer.dart @@ -1,11 +1,13 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:core/data/network/dio_client.dart'; import 'package:core/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart'; import 'package:core/presentation/utils/html_transformer/html_transform.dart'; import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; +import 'package:html/parser.dart'; import 'package:model/email/email_content.dart'; import 'package:model/email/email_content_type.dart'; @@ -61,4 +63,14 @@ class HtmlAnalyzer { return emailContent; } } + + Future> getListLinkCalendarEvent(String emailContents) async { + final document = parse(emailContents); + final linkElements = document.querySelectorAll('a.part-button'); + final listLink = linkElements + .map((element) => element.attributes['href']) + .whereNotNull() + .toList(); + return listLink; + } } \ 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 index 9d94ecc74..e88e8dc4a 100644 --- a/lib/features/email/data/repository/calendar_event_repository_impl.dart +++ b/lib/features/email/data/repository/calendar_event_repository_impl.dart @@ -1,18 +1,25 @@ +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: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'; class CalendarEventRepositoryImpl extends CalendarEventRepository { - final CalendarEventDataSource _calendarEventDataSource; + final Map _calendarEventDataSource; CalendarEventRepositoryImpl(this._calendarEventDataSource); @override Future> parse(AccountId accountId, Set blobIds) { - return _calendarEventDataSource.parse(accountId, blobIds); + return _calendarEventDataSource[DataSourceType.network]!.parse(accountId, blobIds); + } + + @override + Future> getListEventAction(String emailContents) { + return _calendarEventDataSource[DataSourceType.local]!.getListEventAction(emailContents); } } \ No newline at end of file diff --git a/lib/features/email/domain/model/event_action.dart b/lib/features/email/domain/model/event_action.dart new file mode 100644 index 000000000..e2368bb64 --- /dev/null +++ b/lib/features/email/domain/model/event_action.dart @@ -0,0 +1,31 @@ + +import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +enum EventActionType { + yes, + maybe, + no; + + String getLabelButton(BuildContext context) { + switch(this) { + case EventActionType.yes: + return AppLocalizations.of(context).yes; + case EventActionType.maybe: + return AppLocalizations.of(context).maybe; + case EventActionType.no: + return AppLocalizations.of(context).no; + } + } +} + +class EventAction with EquatableMixin { + final EventActionType actionType; + final String link; + + EventAction(this.actionType, this.link); + + @override + List get props => [actionType, link]; +} \ 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 4d1be2026..769f20e8d 100644 --- a/lib/features/email/domain/state/parse_calendar_event_state.dart +++ b/lib/features/email/domain/state/parse_calendar_event_state.dart @@ -1,17 +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'; +import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; class ParseCalendarEventLoading extends LoadingState {} class ParseCalendarEventSuccess extends UIState { final List calendarEventList; + final List eventActionList; - ParseCalendarEventSuccess(this.calendarEventList); + ParseCalendarEventSuccess(this.calendarEventList, this.eventActionList); @override - List get props => [calendarEventList]; + List get props => [calendarEventList, eventActionList]; } 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 2c6c9adb1..93752f3dc 100644 --- a/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart +++ b/lib/features/email/domain/usecases/parse_calendar_event_interactor.dart @@ -3,6 +3,8 @@ 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/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'; @@ -11,11 +13,26 @@ class ParseCalendarEventInteractor { ParseCalendarEventInteractor(this._calendarEventRepository); - Stream> execute(AccountId accountId, Set blobIds) async* { + Stream> execute( + AccountId accountId, + Set blobIds, + String emailContents + ) async* { try { yield Right(ParseCalendarEventLoading()); - final calendarEventList = await _calendarEventRepository.parse(accountId, blobIds); - yield Right(ParseCalendarEventSuccess(calendarEventList)); + + final result = await Future.wait( + [ + _calendarEventRepository.parse(accountId, blobIds), + _calendarEventRepository.getListEventAction(emailContents), + ], + eagerError: true + ); + + final calendarEventList = result.first as List; + final eventActionList = result.last as List; + + yield Right(ParseCalendarEventSuccess(calendarEventList, eventActionList)); } catch (e) { yield Left(ParseCalendarEventFailure(e)); } 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 dc1fa15f5..fdf4369a2 100644 --- a/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart +++ b/lib/features/email/presentation/bindings/calendar_event_interactor_bindings.dart @@ -1,12 +1,16 @@ +import 'package:core/data/model/source_type/data_source_type.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/http/http_client.dart'; import 'package:tmail_ui_user/features/base/interactors_bindings.dart'; import 'package:tmail_ui_user/features/email/data/datasource/calendar_event_datasource.dart'; import 'package:tmail_ui_user/features/email/data/datasource_impl/calendar_event_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/local_calendar_event_datasource_impl.dart'; +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/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'; class CalendarEventInteractorBindings extends InteractorsBindings { @@ -22,6 +26,9 @@ class CalendarEventInteractorBindings extends InteractorsBindings { Get.lazyPut(() => CalendarEventDataSourceImpl( Get.find(), Get.find())); + Get.lazyPut(() => LocalCalendarEventDataSourceImpl( + Get.find(), + Get.find())); } @override @@ -36,6 +43,11 @@ class CalendarEventInteractorBindings extends InteractorsBindings { @override void bindingsRepositoryImpl() { - Get.lazyPut(() => CalendarEventRepositoryImpl(Get.find())); + Get.lazyPut(() => CalendarEventRepositoryImpl( + { + DataSourceType.network: Get.find(), + DataSourceType.local: Get.find(), + } + )); } } \ No newline at end of file