diff --git a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart index 5ee3a93f0..37292f792 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart'; import 'package:core/core.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_date_range_picker/multiple_view_date_range_picker.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; @@ -19,7 +20,9 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -45,12 +48,20 @@ class AdvancedFilterController extends BaseController { final SearchController searchController = Get.find(); final MailboxDashBoardController _mailboxDashBoardController = Get.find(); + final _appToast = Get.find(); + final _imagePaths = Get.find(); SearchEmailFilter get searchEmailFilter => searchController.searchEmailFilter.value; final focusManager = InputFieldFocusManager.initial(); + DateTime? _startDate, _endDate; + + DateTime? get startDate => _startDate; + + DateTime? get endDate => _endDate; + @override void onReady() { if (!BuildUtils.isWeb) { @@ -71,6 +82,7 @@ class AdvancedFilterController extends BaseController { void cleanSearchFilter(BuildContext context) { searchController.cleanSearchFilter(); dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime; + clearDateRangeOfFilter(); subjectFilterInputController.text = ''; hasKeyWordFilterInputController.text = ''; notKeyWordFilterInputController.text = ''; @@ -117,6 +129,8 @@ class AdvancedFilterController extends BaseController { StringConvert.writeEmptyToNull(subjectFilterInputController.text), emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value, hasAttachment: hasAttachment.value, + endDate: _endDate.toUTCDate(), + startDate: _startDate.toUTCDate() ); } @@ -227,7 +241,10 @@ class AdvancedFilterController extends BaseController { notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty( searchEmailFilter.notKeyword.firstOrNull); dateFilterInputController.text = StringConvert.writeNullToEmpty( - searchEmailFilter.emailReceiveTimeType.getTitle(context)); + searchEmailFilter.emailReceiveTimeType.getTitle( + context, + startDate: _startDate, + endDate: _endDate)); mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.mailbox?.name?.name); dateFilterSelectedFormAdvancedSearch.value = @@ -235,6 +252,91 @@ class AdvancedFilterController extends BaseController { hasAttachment.value = searchEmailFilter.hasAttachment; } + void selectDateRange(BuildContext context) { + showGeneralDialog( + context: context, + barrierDismissible: true, + barrierLabel: '', + barrierColor: Colors.black54, + pageBuilder: (context, animation, secondaryAnimation) { + return Dialog( + elevation: 0, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0)), + child: MultipleViewDateRangePicker( + confirmText: AppLocalizations.of(context).setDate, + cancelText: AppLocalizations.of(context).cancel, + last7daysTitle: AppLocalizations.of(context).last7Days, + last30daysTitle: AppLocalizations.of(context).last30Days, + last6monthsTitle: AppLocalizations.of(context).last6Months, + lastYearTitle: AppLocalizations.of(context).lastYears, + startDate: _startDate, + endDate: _endDate, + setDateActionCallback: ({startDate, endDate}) { + _handleSelectDateRangeResult(context, startDate, endDate); + }, + ) + ); + } + ); + } + + void _handleSelectDateRangeResult( + BuildContext context, + DateTime? startDate, + DateTime? endDate + ) { + log('AdvancedFilterController::_handleSelectDateRangeResult(): startDate: $startDate'); + log('AdvancedFilterController::_handleSelectDateRangeResult(): endDate: $endDate'); + if (startDate == null) { + _appToast.showToastWithIcon( + context, + textColor: Colors.black, + message: AppLocalizations.of(context).toastMessageErrorWhenSelectStartDateIsEmpty, + icon: _imagePaths.icNotConnection); + return; + } + if (endDate == null) { + _appToast.showToastWithIcon( + context, + textColor: Colors.black, + message: AppLocalizations.of(context).toastMessageErrorWhenSelectEndDateIsEmpty, + icon: _imagePaths.icNotConnection); + return; + } + + if (endDate.isBefore(startDate)) { + _appToast.showToastWithIcon( + context, + textColor: Colors.black, + message: AppLocalizations.of(context).toastMessageErrorWhenSelectDateIsInValid, + icon: _imagePaths.icNotConnection); + return; + } + + _startDate = startDate; + _endDate = endDate; + dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.customRange; + dateFilterInputController.text = EmailReceiveTimeType.customRange.getTitle( + context, + startDate: startDate, + endDate: endDate); + dateFilterSelectedFormAdvancedSearch.refresh(); + + popBack(); + } + + void clearDateRangeOfFilter() { + _startDate = null; + _endDate = null; + + searchController.searchEmailFilter.value = + searchController.searchEmailFilter.value.withDateRange( + startDate: _startDate.toUTCDate(), + endDate: _endDate.toUTCDate()); + } + @override void onClose() { focusManager.dispose(); diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index 74ade426f..361b054b4 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -129,6 +129,8 @@ class SearchController extends BaseController { EmailReceiveTimeType? emailReceiveTimeType, bool? hasAttachment, UTCDate? before, + UTCDate? startDate, + UTCDate? endDate, }) { searchEmailFilter.value = searchEmailFilter.value.copyWith( from: from, @@ -140,6 +142,8 @@ class SearchController extends BaseController { emailReceiveTimeType: emailReceiveTimeType, hasAttachment: hasAttachment, before: before, + startDate: startDate, + endDate: endDate, ); } diff --git a/lib/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart b/lib/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart index 71accf2ab..2add052b4 100644 --- a/lib/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart +++ b/lib/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; enum EmailReceiveTimeType { @@ -8,9 +9,10 @@ enum EmailReceiveTimeType { last7Days, last30Days, last6Months, - lastYear; + lastYear, + customRange; - String getTitle(BuildContext context) { + String getTitle(BuildContext context, {DateTime? startDate, DateTime? endDate}) { switch(this) { case EmailReceiveTimeType.allTime: return AppLocalizations.of(context).allTime; @@ -22,6 +24,16 @@ enum EmailReceiveTimeType { return AppLocalizations.of(context).last6Months; case EmailReceiveTimeType.lastYear: return AppLocalizations.of(context).lastYears; + case EmailReceiveTimeType.customRange: + if (startDate != null && endDate != null) { + final startDateString = startDate.formatDate(pattern: 'yyyy-dd-MM'); + final endDateString = endDate.formatDate(pattern: 'yyyy-dd-MM'); + return AppLocalizations.of(context).dateRangeAdvancedSearchFilter( + startDateString, + endDateString); + } else { + return AppLocalizations.of(context).customRange; + } } } @@ -30,13 +42,23 @@ enum EmailReceiveTimeType { case EmailReceiveTimeType.allTime: return null; case EmailReceiveTimeType.last7Days: - return UTCDate(DateTime.now().subtract(const Duration(days: 7))); + final today = DateTime.now(); + final last7Days = today.subtract(const Duration(days: 7)); + return last7Days.toUTCDate(); case EmailReceiveTimeType.last30Days: - return UTCDate(DateTime.now().subtract(const Duration(days: 30))); + final today = DateTime.now(); + final last30Days = today.subtract(const Duration(days: 30)); + return last30Days.toUTCDate(); case EmailReceiveTimeType.last6Months: - return UTCDate(DateTime.now().subtract(const Duration(days: 180))); + final today = DateTime.now(); + final last6months = DateTime(today.year, today.month - 6, today.day); + return last6months.toUTCDate(); case EmailReceiveTimeType.lastYear: - return UTCDate(DateTime.now().subtract(const Duration(days: 365))); + final today = DateTime.now(); + final lastYear = DateTime(today.year - 1, today.month, today.day); + return lastYear.toUTCDate(); + case EmailReceiveTimeType.customRange: + return null; } } } diff --git a/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart b/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart index d1b4c6267..bb72df097 100644 --- a/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart +++ b/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart @@ -17,6 +17,8 @@ class SearchEmailFilter { final EmailReceiveTimeType emailReceiveTimeType; final bool hasAttachment; final UTCDate? before; + final UTCDate? startDate; + final UTCDate? endDate; SearchEmailFilter({ Set? from, @@ -28,6 +30,8 @@ class SearchEmailFilter { Set? notKeyword, this.mailbox, this.before, + this.startDate, + this.endDate, }) : from = from ?? {}, to = to ?? {}, notKeyword = notKeyword ?? {}, @@ -45,6 +49,8 @@ class SearchEmailFilter { EmailReceiveTimeType? emailReceiveTimeType, bool? hasAttachment, UTCDate? before, + UTCDate? startDate, + UTCDate? endDate, }) { return SearchEmailFilter( from: from ?? this.from, @@ -56,6 +62,8 @@ class SearchEmailFilter { emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType, hasAttachment: hasAttachment ?? this.hasAttachment, before: before ?? this.before, + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, ); } @@ -67,10 +75,14 @@ class SearchEmailFilter { inMailbox: mailbox == PresentationMailbox.unifiedMailbox ? null : mailbox?.id, - after: emailReceiveTimeType.toUTCDate(), + after: emailReceiveTimeType == EmailReceiveTimeType.customRange + ? startDate + : emailReceiveTimeType.toUTCDate(), hasAttachment: hasAttachment == false ? null : hasAttachment, subject: subject, - before: before, + before: emailReceiveTimeType == EmailReceiveTimeType.customRange + ? endDate + : before, ); final listEmailCondition = { @@ -113,4 +125,20 @@ extension SearchEmailFilterExtension on SearchEmailFilter { before: newBefore, ); } + + SearchEmailFilter withDateRange({UTCDate? startDate, UTCDate? endDate}) { + return SearchEmailFilter( + from: from, + to: to, + text: text, + subject: subject, + notKeyword: notKeyword, + mailbox: mailbox, + emailReceiveTimeType: emailReceiveTimeType, + hasAttachment: hasAttachment, + before: before, + startDate: startDate, + endDate: endDate, + ); + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart index 4478d485f..bcf71f467 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart @@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/sear import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class AdvancedSearchInputForm extends GetWidget with PopupContextMenuActionMixin { @@ -70,18 +71,30 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode, mouseCursor: SystemMouseCursors.click, onTap: () => controller.selectedMailBox()), - _buildFilterField( - textEditingController: controller.dateFilterInputController, - context: context, - advancedSearchFilterField: AdvancedSearchFilterField.date, - isSelectFormList: true, - onTap: () { - openContextMenuAction( - context, - _buildEmailReceiveTimeTypeActionTiles(context), - ); - }, - ), + Row(children: [ + Expanded(child: _buildFilterField( + textEditingController: controller.dateFilterInputController, + context: context, + advancedSearchFilterField: AdvancedSearchFilterField.date, + isSelectFormList: true, + onTap: () { + openContextMenuAction( + context, + _buildEmailReceiveTimeTypeActionTiles(context), + ); + }, + )), + const SizedBox(width: 10), + buildIconWeb( + icon: SvgPicture.asset( + _imagePaths.icCalendarSB, + width: 24, + height: 24, + fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).selectDate, + iconPadding: EdgeInsets.zero, + onTap: () => controller.selectDateRange(context)), + ]), AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager) ], ); @@ -95,7 +108,11 @@ class AdvancedSearchInputForm extends GetWidget child: Row(children: [ const SizedBox(width: 12), Expanded( - child: Text(e.getTitle(context), + child: Text( + e.getTitle( + context, + startDate: controller.startDate, + endDate: controller.endDate), style: const TextStyle( fontSize: 15, color: Colors.black, @@ -112,8 +129,14 @@ class AdvancedSearchInputForm extends GetWidget ] ]), onTap: () { + if (e != EmailReceiveTimeType.customRange) { + controller.clearDateRangeOfFilter(); + } controller.dateFilterSelectedFormAdvancedSearch.value = e; - controller.dateFilterInputController.text = e.getTitle(context); + controller.dateFilterInputController.text = e.getTitle( + context, + startDate: controller.startDate, + endDate: controller.endDate); }, ), ), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart index 4afffa262..8298c917e 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart @@ -17,8 +17,17 @@ class DateDropDownButton extends GetWidget { items: EmailReceiveTimeType.values, itemSelected: controller.dateFilterSelectedFormAdvancedSearch.value, context: context, + startDate: controller.startDate, + endDate: controller.endDate, onChanged: (item) { + if (item != EmailReceiveTimeType.customRange) { + controller.clearDateRangeOfFilter(); + } controller.dateFilterSelectedFormAdvancedSearch.value = item!; + controller.dateFilterInputController.text = item.getTitle( + context, + startDate: controller.startDate, + endDate: controller.endDate); }, ), ); @@ -30,6 +39,8 @@ Widget _buildDropDownButton({ required T itemSelected, required BuildContext context, required Function(T?)? onChanged, + DateTime? startDate, + DateTime? endDate }) { final ImagePaths _imagePaths = Get.find(); @@ -43,6 +54,8 @@ Widget _buildDropDownButton({ StringConvert.writeNullToEmpty(_getTextItemDropdown( item: item, context: context, + startDate: startDate, + endDate: endDate, )), style: const TextStyle( fontSize: 16, @@ -81,10 +94,13 @@ Widget _buildDropDownButton({ ); } -String? _getTextItemDropdown( - {required T item, required BuildContext context}) { +String? _getTextItemDropdown({required T item, + required BuildContext context, + DateTime? startDate, + DateTime? endDate +}) { if (item is EmailReceiveTimeType) { - return item.getTitle(context); + return item.getTitle(context, startDate: startDate, endDate: endDate); } if (item is Mailbox) { diff --git a/lib/features/manage_account/presentation/extensions/datetime_extension.dart b/lib/features/manage_account/presentation/extensions/datetime_extension.dart index e96bf8070..e0dad2148 100644 --- a/lib/features/manage_account/presentation/extensions/datetime_extension.dart +++ b/lib/features/manage_account/presentation/extensions/datetime_extension.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:jmap_dart_client/jmap/core/utc_date.dart'; extension DateTimeExtension on DateTime? { @@ -17,6 +18,14 @@ extension DateTimeExtension on DateTime? { } return null; } + + UTCDate? toUTCDate() { + if (this != null) { + return UTCDate(this!.toUtc()); + } else { + return null; + } + } } extension TimeOfDayExtension on TimeOfDay? { diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index c9935fec8..fd4ccd480 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-09-30T17:54:08.425416", + "@@last_modified": "2022-10-05T22:55:58.696295", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2245,5 +2245,53 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "selectDate": "Select date", + "@selectDate": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "setDate": "Set date", + "@setDate": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageErrorWhenSelectStartDateIsEmpty": "The start date cannot be null.", + "@toastMessageErrorWhenSelectStartDateIsEmpty": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageErrorWhenSelectEndDateIsEmpty": "The end date cannot be null.", + "@toastMessageErrorWhenSelectEndDateIsEmpty": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageErrorWhenSelectDateIsInValid": "The end time cannot be less than the start time.", + "@toastMessageErrorWhenSelectDateIsInValid": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "dateRangeAdvancedSearchFilter": "From {startDate} to {endDate}", + "@dateRangeAdvancedSearchFilter": { + "type": "text", + "placeholders_order": [ + "startDate", + "endDate" + ], + "placeholders": { + "startDate": {}, + "endDate": {} + } + }, + "customRange": "Custom range", + "@customRange": { + "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 012bae111..fc42394b6 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2327,4 +2327,54 @@ class AppLocalizations { name: 'titleForeground' ); } + + String get selectDate { + return Intl.message( + 'Select date', + name: 'selectDate', + ); + } + + String get setDate { + return Intl.message( + 'Set date', + name: 'setDate', + ); + } + + String get toastMessageErrorWhenSelectStartDateIsEmpty { + return Intl.message( + 'The start date cannot be null.', + name: 'toastMessageErrorWhenSelectStartDateIsEmpty', + ); + } + + String get toastMessageErrorWhenSelectEndDateIsEmpty { + return Intl.message( + 'The end date cannot be null.', + name: 'toastMessageErrorWhenSelectEndDateIsEmpty', + ); + } + + String get toastMessageErrorWhenSelectDateIsInValid { + return Intl.message( + 'The end time cannot be less than the start time.', + name: 'toastMessageErrorWhenSelectDateIsInValid', + ); + } + + String dateRangeAdvancedSearchFilter(String startDate, String endDate) { + return Intl.message( + 'From $startDate to $endDate', + name: 'dateRangeAdvancedSearchFilter', + args: [startDate, endDate] + ); + } + + String get customRange { + return Intl.message( + 'Custom range', + name: 'customRange'); + } + } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 6b63e9653..21d0eca62 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -481,6 +481,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" + flutter_date_range_picker: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: c04608f5daad5e96daf0f419946ad0db23c46811 + url: "https://github.com/linagora/flutter-date-range-picker.git" + source: git + version: "1.0.0" flutter_dotenv: dependency: "direct main" description: @@ -891,7 +900,7 @@ packages: name: package_info_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.0.6" package_info_plus_windows: dependency: transitive description: @@ -955,6 +964,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + pattern_formatter: + dependency: transitive + description: + name: pattern_formatter + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" pedantic: dependency: transitive description: @@ -989,7 +1005,7 @@ packages: name: permission_handler_apple url: "https://pub.dartlang.org" source: hosted - version: "9.0.4" + version: "9.0.6" permission_handler_platform_interface: dependency: transitive description: @@ -1003,7 +1019,7 @@ packages: name: permission_handler_windows url: "https://pub.dartlang.org" source: hosted - version: "0.1.0" + version: "0.1.1" petitparser: dependency: transitive description: @@ -1088,7 +1104,7 @@ packages: description: path: "." ref: master - resolved-ref: "85fe10cd4d3b29bbf803ac796ebe722710fa1d36" + resolved-ref: "45ed9a973331ac4209917e365792967d7ca7b5bb" url: "https://github.com/linagora/rich-text-composer.git" source: git version: "0.0.1" @@ -1251,6 +1267,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.1" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + url: "https://pub.dartlang.org" + source: hosted + version: "20.3.48" + syncfusion_flutter_datepicker: + dependency: transitive + description: + name: syncfusion_flutter_datepicker + url: "https://pub.dartlang.org" + source: hosted + version: "20.3.48" synchronized: dependency: transitive description: @@ -1425,7 +1455,7 @@ packages: name: webview_flutter_android url: "https://pub.dartlang.org" source: hosted - version: "2.10.3" + version: "2.10.4" webview_flutter_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e698da906..397ef7387 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -191,6 +191,11 @@ dependencies: byte_converter: 1.3.0 + flutter_date_range_picker: + git: + url: https://github.com/linagora/flutter-date-range-picker.git + ref: master + dev_dependencies: flutter_test: sdk: flutter