diff --git a/contact/pubspec.lock b/contact/pubspec.lock index 0392eca2f2..9e14d21c45 100644 --- a/contact/pubspec.lock +++ b/contact/pubspec.lock @@ -492,7 +492,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index be56651b36..f6d927a9b7 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -191,6 +191,9 @@ extension AppColor on Color { static const colorUpdatedEventActionText = Color(0xFF4BB34B); static const colorCanceledEventActionText = Color(0xFFFF3347); static const colorSubTitleEventActionText = Color(0xFF939393); + static const colorCalendarEventInformationBackground = Color(0x0A000000); + static const colorCalendarEventInformationStroke = Color(0x1F000000); + static const colorShadowCalendarDateIcon = Color(0x26000000); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/fcm/pubspec.lock b/fcm/pubspec.lock index 0d9a767442..22fedc3afe 100644 --- a/fcm/pubspec.lock +++ b/fcm/pubspec.lock @@ -296,7 +296,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" diff --git a/forward/pubspec.lock b/forward/pubspec.lock index 0d9a767442..22fedc3afe 100644 --- a/forward/pubspec.lock +++ b/forward/pubspec.lock @@ -296,7 +296,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" diff --git a/lib/features/base/reloadable/reloadable_controller.dart b/lib/features/base/reloadable/reloadable_controller.dart index 35684e353b..e72d65fd79 100644 --- a/lib/features/base/reloadable/reloadable_controller.dart +++ b/lib/features/base/reloadable/reloadable_controller.dart @@ -140,7 +140,7 @@ abstract class ReloadableController extends BaseController { } void updateAuthenticationAccount(Session session, AccountId accountId, UserName userName) { - final apiUrl = session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors.jmapUrl);; + final apiUrl = session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors.jmapUrl); log('ReloadableController::updateAuthenticationAccount():apiUrl: $apiUrl'); if (apiUrl.isNotEmpty) { consumeState(_updateAuthenticationAccountInteractor.execute(accountId, apiUrl, userName)); diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index efe6113bfd..f3d821b208 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -29,6 +29,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_w import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_file_tile_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event_action_banner_widget.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event_information_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart'; @@ -282,6 +283,15 @@ class EmailView extends GetWidget with AppLoaderMixin { ), _buildLoadingContentView(), _buildAttachments(context), + Obx(() { + if (controller.calendarEvent.value != null) { + return CalendarEventInformationWidget( + calendarEvent: controller.calendarEvent.value! + ); + } else { + return const SizedBox.shrink(); + } + }), Obx(() { if (controller.calendarEvent.value != null) { return CalendarEventActionBannerWidget( diff --git a/lib/features/email/presentation/extensions/calendar_event_extension.dart b/lib/features/email/presentation/extensions/calendar_event_extension.dart index 92f1428f95..f6f50a122f 100644 --- a/lib/features/email/presentation/extensions/calendar_event_extension.dart +++ b/lib/features/email/presentation/extensions/calendar_event_extension.dart @@ -3,12 +3,14 @@ import 'package:collection/collection.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:date_format/date_format.dart' as date_format; import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/properties/attendee/calendar_attendee.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/properties/attendee/calendar_attendee_participation_status.dart'; import 'package:jmap_dart_client/jmap/mail/calendar/properties/event_method.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/utils/app_utils.dart'; extension CalendarEventExtension on CalendarEvent { @@ -175,4 +177,42 @@ extension CalendarEventExtension on CalendarEvent { return Colors.transparent; } } + + DateTime? get localStartDate => startUtcDate?.value.toLocal(); + + String get monthStartDateAsString { + if (localStartDate != null) { + return date_format.formatDate( + localStartDate!, + [date_format.M], + locale: AppUtils.getCurrentDateLocale() + ); + } else { + return ''; + } + } + + String get dayStartDateAsString { + if (localStartDate != null) { + return date_format.formatDate( + localStartDate!, + [date_format.d], + locale: AppUtils.getCurrentDateLocale() + ); + } else { + return ''; + } + } + + String get weekDayStartDateAsString { + if (localStartDate != null) { + return date_format.formatDate( + localStartDate!, + [date_format.D], + locale: AppUtils.getCurrentDateLocale() + ); + } else { + return ''; + } + } } \ No newline at end of file diff --git a/lib/features/email/presentation/styles/calendar_date_icon_widget_styles.dart b/lib/features/email/presentation/styles/calendar_date_icon_widget_styles.dart new file mode 100644 index 0000000000..73d502defc --- /dev/null +++ b/lib/features/email/presentation/styles/calendar_date_icon_widget_styles.dart @@ -0,0 +1,10 @@ + +class CalendarIconWidgetStyles { + static const double borderRadius = 8; + static const double headerVerticalContentPadding = 4; + static const double headerHorizontalContentPadding = 8; + static const double headerTextSize = 14; + static const double bodyDayTextSize = 40; + static const double bodyWeekDayTextSize = 14; + static const double bodyContentPadding = 8; +} \ No newline at end of file diff --git a/lib/features/email/presentation/styles/calendar_event_action_banner_styles.dart b/lib/features/email/presentation/styles/calendar_event_action_banner_styles.dart index dd23222d54..fc4203ca57 100644 --- a/lib/features/email/presentation/styles/calendar_event_action_banner_styles.dart +++ b/lib/features/email/presentation/styles/calendar_event_action_banner_styles.dart @@ -3,6 +3,7 @@ class CalendarEventActionBannerStyles { static const double borderRadius = 12; static const double contentPadding = 12; static const double viewHorizontalMargin = 16; + static const double viewVerticalMargin = 12; static const double titleTextSize = 16; static const double subTileTextSize = 13; static const double iconSize = 20; diff --git a/lib/features/email/presentation/styles/calendar_event_information_widget_styles.dart b/lib/features/email/presentation/styles/calendar_event_information_widget_styles.dart new file mode 100644 index 0000000000..32fe47b79a --- /dev/null +++ b/lib/features/email/presentation/styles/calendar_event_information_widget_styles.dart @@ -0,0 +1,12 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; + +class CalendarEventInformationWidgetStyles { + static const double borderRadius = 16; + static const double contentPadding = 16; + static const double verticalMargin = 12; + static const double horizontalMargin = 16; + static const double calendarDateIconMargin = 16; + static const Color calendarDateIconBackgroundColor = AppColor.colorCalendarEventInformationBackground; +} \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/calendar_date_icon_widget.dart b/lib/features/email/presentation/widgets/calendar_date_icon_widget.dart new file mode 100644 index 0000000000..4b628f4a29 --- /dev/null +++ b/lib/features/email/presentation/widgets/calendar_date_icon_widget.dart @@ -0,0 +1,92 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; +import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart'; +import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/styles/calendar_date_icon_widget_styles.dart'; + +class CalendarDateIconWidget extends StatelessWidget { + + final CalendarEvent calendarEvent; + final double width; + + const CalendarDateIconWidget({ + super.key, + required this.calendarEvent, + this.width = 100 + }); + + @override + Widget build(BuildContext context) { + return Container( + clipBehavior: Clip.antiAlias, + width: width, + decoration: const ShapeDecoration( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(CalendarIconWidgetStyles.borderRadius))), + color: Colors.white, + shadows: [ + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + blurRadius: 80, + offset: Offset(0, 1), + spreadRadius: 0, + ), + BoxShadow( + color: AppColor.colorShadowCalendarDateIcon, + blurRadius: 3, + offset: Offset(0, 1), + spreadRadius: 1, + ) + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + color: AppColor.primaryColor, + padding: const EdgeInsetsDirectional.symmetric( + vertical: CalendarIconWidgetStyles.headerVerticalContentPadding, + horizontal: CalendarIconWidgetStyles.headerHorizontalContentPadding + ), + width: width, + child: Text( + calendarEvent.monthStartDateAsString, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: CalendarIconWidgetStyles.headerTextSize, + fontWeight: FontWeight.w400, + color: Colors.white + ), + ), + ), + Padding( + padding: const EdgeInsets.all(CalendarIconWidgetStyles.bodyContentPadding), + child: Text( + calendarEvent.dayStartDateAsString, + style: const TextStyle( + fontSize: CalendarIconWidgetStyles.bodyDayTextSize, + fontWeight: FontWeight.w700, + color: Colors.black + ), + ), + ), + const Padding( + padding: EdgeInsets.symmetric(horizontal: CalendarIconWidgetStyles.bodyContentPadding), + child: Divider(color: AppColor.colorCalendarEventInformationStroke, height: 2) + ), + Padding( + padding: const EdgeInsets.all(CalendarIconWidgetStyles.bodyContentPadding), + child: Text( + calendarEvent.weekDayStartDateAsString, + style: const TextStyle( + fontSize: CalendarIconWidgetStyles.bodyWeekDayTextSize, + fontWeight: FontWeight.w400, + color: Colors.black + ), + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/calendar_event_action_banner_widget.dart b/lib/features/email/presentation/widgets/calendar_event_action_banner_widget.dart index 7d60888388..389ad6d962 100644 --- a/lib/features/email/presentation/widgets/calendar_event_action_banner_widget.dart +++ b/lib/features/email/presentation/widgets/calendar_event_action_banner_widget.dart @@ -33,6 +33,7 @@ class CalendarEventActionBannerWidget extends StatelessWidget { padding: const EdgeInsets.all(CalendarEventActionBannerStyles.contentPadding), margin: const EdgeInsets.symmetric( horizontal: CalendarEventActionBannerStyles.viewHorizontalMargin, + vertical: CalendarEventActionBannerStyles.viewVerticalMargin, ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/features/email/presentation/widgets/calendar_event_information_widget.dart b/lib/features/email/presentation/widgets/calendar_event_information_widget.dart new file mode 100644 index 0000000000..6b8f0ef9c4 --- /dev/null +++ b/lib/features/email/presentation/widgets/calendar_event_information_widget.dart @@ -0,0 +1,63 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +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/presentation/styles/calendar_event_information_widget_styles.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_date_icon_widget.dart'; + +class CalendarEventInformationWidget extends StatelessWidget { + + final CalendarEvent calendarEvent; + + const CalendarEventInformationWidget({ + super.key, + required this.calendarEvent + }); + + @override + Widget build(BuildContext context) { + final responsiveUtils = Get.find(); + return Container( + clipBehavior: Clip.antiAlias, + decoration: const ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 0.5, + color: AppColor.colorCalendarEventInformationStroke, + ), + borderRadius: BorderRadius.all(Radius.circular(CalendarEventInformationWidgetStyles.borderRadius)), + ), + ), + margin: const EdgeInsetsDirectional.symmetric( + vertical: CalendarEventInformationWidgetStyles.verticalMargin, + horizontal: CalendarEventInformationWidgetStyles.horizontalMargin), + child: responsiveUtils.isPortraitMobile(context) + ? Column( + children: [ + Container( + padding: const EdgeInsets.all(CalendarEventInformationWidgetStyles.calendarDateIconMargin), + color: CalendarEventInformationWidgetStyles.calendarDateIconBackgroundColor, + child: CalendarDateIconWidget( + calendarEvent: calendarEvent, + width: double.infinity, + ), + ) + ], + ) + : Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.all(CalendarEventInformationWidgetStyles.calendarDateIconMargin), + color: CalendarEventInformationWidgetStyles.calendarDateIconBackgroundColor, + child: CalendarDateIconWidget(calendarEvent: calendarEvent), + ), + Expanded(child: Container(color: Colors.white)) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart index 569bc19399..e1af349057 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart @@ -61,7 +61,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { children: [ SizedBox( width: ResponsiveUtils.defaultSizeLeftMenuMobile, - child: _buildScaffoldHaveDrawer(body: SendingQueueView())), + child: _buildScaffoldHaveDrawer(body: const SendingQueueView())), Expanded(child: EmailView()), ], ); @@ -70,7 +70,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { desktop: bodyView, tabletLarge: bodyView, landscapeTablet: bodyView, - mobile: _buildScaffoldHaveDrawer(body: SendingQueueView())); + mobile: _buildScaffoldHaveDrawer(body: const SendingQueueView())); case DashboardRoutes.waiting: return const Center( child: SizedBox( diff --git a/lib/main/localizations/language_code_constants.dart b/lib/main/localizations/language_code_constants.dart new file mode 100644 index 0000000000..7b84b16be2 --- /dev/null +++ b/lib/main/localizations/language_code_constants.dart @@ -0,0 +1,9 @@ + +class LanguageCodeConstants { + static const String english = 'en'; + static const String french = 'fr'; + static const String vietnamese = 'vi'; + static const String italian = 'it'; + static const String russian = 'ru'; + static const String arabic = 'ar'; +} diff --git a/lib/main/localizations/localization_service.dart b/lib/main/localizations/localization_service.dart index 18f1e48c88..9d17d32bf4 100644 --- a/lib/main/localizations/localization_service.dart +++ b/lib/main/localizations/localization_service.dart @@ -4,28 +4,29 @@ import 'dart:ui'; import 'package:core/utils/app_logger.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; +import 'package:tmail_ui_user/main/localizations/language_code_constants.dart'; class LocalizationService extends Translations { - static const defaultLocale = Locale('en', 'US'); - static const fallbackLocale = Locale('en', 'US'); + static const defaultLocale = Locale(LanguageCodeConstants.english, 'US'); + static const fallbackLocale = Locale(LanguageCodeConstants.english, 'US'); static final supportedLanguageCodes = [ - 'fr', - 'en', - 'vi', - 'ru', - 'ar', - 'it' + LanguageCodeConstants.french, + LanguageCodeConstants.english, + LanguageCodeConstants.vietnamese, + LanguageCodeConstants.russian, + LanguageCodeConstants.arabic, + LanguageCodeConstants.italian ]; static const List supportedLocales = [ - Locale('fr', 'FR'), - Locale('en', 'US'), - Locale('vi', 'VN'), - Locale('ru', 'RU'), - Locale('ar', 'TN'), - Locale('it', 'IT') + Locale(LanguageCodeConstants.french, 'FR'), + Locale(LanguageCodeConstants.english, 'US'), + Locale(LanguageCodeConstants.vietnamese, 'VN'), + Locale(LanguageCodeConstants.russian, 'RU'), + Locale(LanguageCodeConstants.arabic, 'TN'), + Locale(LanguageCodeConstants.italian, 'IT') ]; static final locale = _getLocaleFromLanguage(); diff --git a/lib/main/utils/app_utils.dart b/lib/main/utils/app_utils.dart index 4f62d697e2..6314a1f178 100644 --- a/lib/main/utils/app_utils.dart +++ b/lib/main/utils/app_utils.dart @@ -2,10 +2,13 @@ import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:get/get.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/localizations/language_code_constants.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:intl/intl.dart' as intl; +import 'package:date_format/date_format.dart' as date_format; class AppUtils { @@ -48,4 +51,23 @@ class AppUtils { ); }); } + + static date_format.DateLocale getCurrentDateLocale() { + final currentLanguageCode = Get.locale?.languageCode; + if (currentLanguageCode == LanguageCodeConstants.french) { + return const date_format.FrenchDateLocale(); + } else if (currentLanguageCode == LanguageCodeConstants.english) { + return const date_format.EnglishDateLocale(); + } else if (currentLanguageCode == LanguageCodeConstants.vietnamese) { + return const date_format.VietnameseDateLocale(); + } else if (currentLanguageCode == LanguageCodeConstants.russian) { + return const date_format.RussianDateLocale(); + } else if (currentLanguageCode == LanguageCodeConstants.arabic) { + return const date_format.ArabicDateLocale(); + } else if (currentLanguageCode == LanguageCodeConstants.italian) { + return const date_format.ItalianDateLocale(); + } else { + return const date_format.EnglishDateLocale(); + } + } } \ No newline at end of file diff --git a/model/pubspec.lock b/model/pubspec.lock index 561d09bf3f..8b5e80c348 100644 --- a/model/pubspec.lock +++ b/model/pubspec.lock @@ -484,7 +484,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" diff --git a/pubspec.lock b/pubspec.lock index d1d06fa8a2..a271466280 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -312,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.1" + date_format: + dependency: "direct main" + description: + name: date_format + sha256: "8e5154ca363411847220c8cbc43afcf69c08e8debe40ba09d57710c25711760c" + url: "https://pub.dev" + source: hosted + version: "2.0.7" dbus: dependency: transitive description: @@ -971,7 +979,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index a2990bb897..731746f21b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -203,6 +203,8 @@ dependencies: flutter_app_badger: 1.5.0 + date_format: 2.0.7 + dev_dependencies: flutter_test: sdk: flutter diff --git a/rule_filter/pubspec.lock b/rule_filter/pubspec.lock index 0d9a767442..22fedc3afe 100644 --- a/rule_filter/pubspec.lock +++ b/rule_filter/pubspec.lock @@ -296,7 +296,7 @@ packages: description: path: "." ref: master - resolved-ref: "751c09a96a98f96141acdc2f592f183ac9e1a911" + resolved-ref: "63d47945f676adca3bf48b3940b21b77546e309e" url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1"