Skip to content

Commit

Permalink
TF-3219 display limits of email recovery in a yellow banner and filte…
Browse files Browse the repository at this point in the history
…r out invalid suggestions
  • Loading branch information
florentos17 authored and hoangdat committed Dec 9, 2024
1 parent 5094fd4 commit aa99995
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 13 deletions.
2 changes: 1 addition & 1 deletion lib/features/base/mixin/date_range_picker_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mixin DateRangePickerMixin {
last7daysTitle: AppLocalizations.of(context).last7Days,
last30daysTitle: AppLocalizations.of(context).last30Days,
last6monthsTitle: AppLocalizations.of(context).last6Months,
lastYearTitle: AppLocalizations.of(context).lastYears,
lastYearTitle: AppLocalizations.of(context).last1Year,
initStartDate: initStartDate,
initEndDate: initEndDate,
autoClose: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/autocomplete/auto_complete_pattern.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:model/model.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:super_tag_editor/tag_editor.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
Expand All @@ -25,6 +23,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/controller/in
import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_arguments.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_field.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_time_type.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/model/session_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';
Expand All @@ -34,7 +33,7 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin {
GetAutoCompleteInteractor? _getAutoCompleteInteractor;
GetDeviceContactSuggestionsInteractor? _getDeviceContactSuggestionsInteractor;

final deletionDateFieldSelected = EmailRecoveryTimeType.last1Year.obs;
final deletionDateFieldSelected = EmailRecoveryTimeType.last7Days.obs;
final receptionDateFieldSelected = EmailRecoveryTimeType.allTime.obs;
final startDeletionDate = Rxn<DateTime>();
final endDeletionDate = Rxn<DateTime>();
Expand Down Expand Up @@ -348,6 +347,10 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin {
popBack();
}

String getRestorationHorizonAsString() => arguments!.session.getRestorationHorizonAsString();

DateTime getRestorationHorizonAsDateTime() => arguments!.session.getRestorationHorizonAsDateTime();

@override
void dispose() {
focusManager.subjectFieldFocusNode.removeListener(_onSubjectFieldFocusChanged);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum EmailRecoveryField {
String getHintText(BuildContext context) {
switch (this) {
case EmailRecoveryField.deletionDate:
return AppLocalizations.of(context).last1Year;
return AppLocalizations.of(context).last7Days;
case EmailRecoveryField.receptionDate:
return AppLocalizations.of(context).allTime;
case EmailRecoveryField.subject:
Expand All @@ -40,16 +40,20 @@ enum EmailRecoveryField {
}
}

List<EmailRecoveryTimeType> getSupportedTimeTypes() {
List<EmailRecoveryTimeType> getSupportedTimeTypes(DateTime restorationHorizon) {
switch (this) {
case EmailRecoveryField.deletionDate:
return [
EmailRecoveryTimeType.last1Year,
final supportedTypes = [
EmailRecoveryTimeType.last7Days,
EmailRecoveryTimeType.last15Days,
EmailRecoveryTimeType.last30Days,
EmailRecoveryTimeType.last6Months,
EmailRecoveryTimeType.customRange,
];
EmailRecoveryTimeType.last1Year,
].where((type) => restorationHorizon
.subtract(const Duration(seconds: 2)) // to allow "15 days" if restorationHorizon is exactly 15
.isBefore(type.toOldestUTCDate()!.value)).toList();

return [...supportedTypes, EmailRecoveryTimeType.customRange];
case EmailRecoveryField.receptionDate:
return [
EmailRecoveryTimeType.allTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:jmap_dart_client/jmap/core/utc_date.dart';
enum EmailRecoveryTimeType {
allTime,
last7Days,
last15Days,
last30Days,
last6Months,
last1Year,
Expand All @@ -18,6 +19,8 @@ enum EmailRecoveryTimeType {
return AppLocalizations.of(context).allTime;
case EmailRecoveryTimeType.last7Days:
return AppLocalizations.of(context).last7Days;
case EmailRecoveryTimeType.last15Days:
return AppLocalizations.of(context).last15Days;
case EmailRecoveryTimeType.last30Days:
return AppLocalizations.of(context).last30Days;
case EmailRecoveryTimeType.last6Months:
Expand Down Expand Up @@ -47,6 +50,10 @@ enum EmailRecoveryTimeType {
final today = DateTime.now();
final last7Days = today.subtract(const Duration(days: 7));
return last7Days.toUTCDate();
case EmailRecoveryTimeType.last15Days:
final today = DateTime.now();
final last15Days = today.subtract(const Duration(days: 15));
return last15Days.toUTCDate();
case EmailRecoveryTimeType.last30Days:
final today = DateTime.now();
final last30Days = today.subtract(const Duration(days: 30));
Expand All @@ -68,6 +75,7 @@ enum EmailRecoveryTimeType {
UTCDate? toLatestUTCDate() {
switch(this) {
case EmailRecoveryTimeType.last7Days:
case EmailRecoveryTimeType.last15Days:
case EmailRecoveryTimeType.last30Days:
case EmailRecoveryTimeType.last6Months:
case EmailRecoveryTimeType.last1Year:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

import 'package:duration/duration.dart';
import 'package:email_recovery/email_recovery/capability_deleted_messages_vault.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/extensions/session_extension.dart';

extension SessionExtension on Session {

String getRestorationHorizonAsString() {
String restorationHorizon = 'restorationHorizon';
String defaultHorizon = "15 days";

return (getCapabilityProperties(accountId, capabilityDeletedMessagesVault)
?.props[0] as Map<String, dynamic>?)
?[restorationHorizon]
?? defaultHorizon;
}

Duration getRestorationHorizonAsDuration() {
try {
String horizonWithCorrectFormat = getRestorationHorizonAsString()
.replaceAll(" days", "d")
.replaceAll(" day", "d")
.replaceAll(" hours", "h")
.replaceAll(" hour", "h")
.replaceAll(" minutes", "m")
.replaceAll(" minute", "m")
.replaceAll(" seconds", "s")
.replaceAll(" second", "s")
.replaceAll(" milliseconds", "ms")
.replaceAll(" millisecond", "ms");

return parseDuration(horizonWithCorrectFormat, separator: ' ');
} catch (e) {
return const Duration(days: 15);
}
}

DateTime getRestorationHorizonAsDateTime() {
return DateTime.now().subtract(getRestorationHorizonAsDuration());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class DateSelectionFieldWebWidget extends StatelessWidget {
final EmailRecoveryTimeType? recoveryTimeSelected;
final OnRecoveryTimeSelected? onRecoveryTimeSelected;
final VoidCallback? onTapCalendar;
final DateTime restorationHorizon;

const DateSelectionFieldWebWidget({
super.key,
Expand All @@ -29,6 +30,7 @@ class DateSelectionFieldWebWidget extends StatelessWidget {
this.recoveryTimeSelected,
this.onRecoveryTimeSelected,
this.onTapCalendar,
required this.restorationHorizon
});

@override
Expand All @@ -54,7 +56,7 @@ class DateSelectionFieldWebWidget extends StatelessWidget {
endDate: endDate,
recoveryTimeSelected: recoveryTimeSelected,
onRecoveryTimeSelected: onRecoveryTimeSelected,
items: field.getSupportedTimeTypes(),
items: field.getSupportedTimeTypes(restorationHorizon),
),
),
const SizedBox(width: DateSelectionFieldStyles.icCalenderSpace),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_r
import 'package:tmail_ui_user/features/email_recovery/presentation/styles/email_recovery_form_styles.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/check_box_has_attachment_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/date_selection_field/date_selection_field_web_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/limits_banner.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/list_button_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_widget.dart';
Expand Down Expand Up @@ -41,6 +42,10 @@ class EmailRecoveryFormDesktopBuilder extends GetWidget<EmailRecoveryController>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LimitsBanner(
bannerContent: AppLocalizations.of(context).recoverDeletedMessagesBannerContent(controller.getRestorationHorizonAsString()),
),
const SizedBox(height: 16.0),
Obx(() => DateSelectionFieldWebWidget(
field: EmailRecoveryField.deletionDate,
imagePaths: controller.imagePaths,
Expand All @@ -50,6 +55,7 @@ class EmailRecoveryFormDesktopBuilder extends GetWidget<EmailRecoveryController>
recoveryTimeSelected: controller.deletionDateFieldSelected.value,
onTapCalendar: () => controller.onSelectDeletionDateRange(context),
onRecoveryTimeSelected: (type) => controller.onDeletionDateTypeSelected(context, type),
restorationHorizon: controller.getRestorationHorizonAsDateTime(),
)),
Obx(() => DateSelectionFieldWebWidget(
field: EmailRecoveryField.receptionDate,
Expand All @@ -60,6 +66,7 @@ class EmailRecoveryFormDesktopBuilder extends GetWidget<EmailRecoveryController>
recoveryTimeSelected: controller.receptionDateFieldSelected.value,
onTapCalendar: () => controller.onSelectReceptionDateRange(context),
onRecoveryTimeSelected: (type) => controller.onReceptionDateTypeSelected(context, type),
restorationHorizon: controller.getRestorationHorizonAsDateTime(),
)),
TextInputFieldWidget(
field: EmailRecoveryField.subject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_r
import 'package:tmail_ui_user/features/email_recovery/presentation/styles/email_recovery_form_styles.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/check_box_has_attachment_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/date_selection_field/date_selection_field_mobile_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/limits_banner.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/list_button_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_widget.dart';
Expand Down Expand Up @@ -41,6 +42,10 @@ class EmailRecoveryFormMobileBuilder extends GetWidget<EmailRecoveryController>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LimitsBanner(
bannerContent: AppLocalizations.of(context).recoverDeletedMessagesBannerContent(controller.getRestorationHorizonAsString()),
),
const SizedBox(height: 16.0),
Obx(() => DateSelectionFieldMobileWidget(
field: EmailRecoveryField.deletionDate,
recoveryTimeSelected: controller.deletionDateFieldSelected.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_r
import 'package:tmail_ui_user/features/email_recovery/presentation/styles/email_recovery_form_styles.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/check_box_has_attachment_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/date_selection_field/date_selection_field_web_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/limits_banner.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/list_button_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/text_input_field_widget.dart';
Expand Down Expand Up @@ -41,6 +42,10 @@ class EmailRecoveryFormTabletBuilder extends GetWidget<EmailRecoveryController>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LimitsBanner(
bannerContent: AppLocalizations.of(context).recoverDeletedMessagesBannerContent(controller.getRestorationHorizonAsString()),
),
const SizedBox(height: 16.0),
Obx(() => DateSelectionFieldWebWidget(
field: EmailRecoveryField.deletionDate,
imagePaths: controller.imagePaths,
Expand All @@ -50,6 +55,7 @@ class EmailRecoveryFormTabletBuilder extends GetWidget<EmailRecoveryController>
recoveryTimeSelected: controller.deletionDateFieldSelected.value,
onTapCalendar: () => controller.onSelectDeletionDateRange(context),
onRecoveryTimeSelected: (type) => controller.onDeletionDateTypeSelected(context, type),
restorationHorizon: controller.getRestorationHorizonAsDateTime(),
)),
Obx(() => DateSelectionFieldWebWidget(
field: EmailRecoveryField.receptionDate,
Expand All @@ -60,6 +66,7 @@ class EmailRecoveryFormTabletBuilder extends GetWidget<EmailRecoveryController>
recoveryTimeSelected: controller.receptionDateFieldSelected.value,
onTapCalendar: () => controller.onSelectReceptionDateRange(context),
onRecoveryTimeSelected: (type) => controller.onReceptionDateTypeSelected(context, type),
restorationHorizon: controller.getRestorationHorizonAsDateTime(),
)),
TextInputFieldWidget(
field: EmailRecoveryField.subject,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';

class LimitsBanner extends StatelessWidget {
final String bannerContent;

const LimitsBanner({
super.key,
required this.bannerContent,
});

@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
decoration: BoxDecoration(
color: Colors.yellow[400],
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
),
child: Center(
child: Text(
bannerContent,
style: const TextStyle(
fontSize: 16,
color: Colors.black,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
);
}
}
18 changes: 17 additions & 1 deletion lib/l10n/intl_messages.arb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"@@last_modified": "2024-11-25T10:57:37.546143",
"@@last_modified": "2024-12-03T10:03:02.076482",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
Expand Down Expand Up @@ -1368,6 +1368,12 @@
"placeholders_order": [],
"placeholders": {}
},
"last15Days": "Last 15 days",
"@last15Days": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"fromMe": "From me",
"@fromMe": {
"type": "text",
Expand Down Expand Up @@ -3598,6 +3604,16 @@
"placeholders_order": [],
"placeholders": {}
},
"recoverDeletedMessagesBannerContent": "You can recover messages deleted during the past {period}",
"@recoverDeletedMessagesBannerContent": {
"type": "text",
"placeholders_order": [
"period"
],
"placeholders": {
"period": {}
}
},
"deletionDate": "Deletion date",
"@deletionDate": {
"type": "text",
Expand Down
14 changes: 14 additions & 0 deletions lib/main/localizations/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,12 @@ class AppLocalizations {
name: 'last7Days');
}

String get last15Days {
return Intl.message(
'Last 15 days',
name: 'last15Days');
}

String get fromMe {
return Intl.message(
'From me',
Expand Down Expand Up @@ -3750,6 +3756,14 @@ class AppLocalizations {
);
}

String recoverDeletedMessagesBannerContent(String period) {
return Intl.message(
'You can recover messages deleted during the past $period',
name: 'recoverDeletedMessagesBannerContent',
args: [period]
);
}

String get deletionDate {
return Intl.message(
'Deletion date',
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
duration:
dependency: "direct main"
description:
name: duration
sha256: "13e5d20723c9c1dde8fb318cf86716d10ce294734e81e44ae1a817f3ae714501"
url: "https://pub.dev"
source: hosted
version: "4.0.3"
email_recovery:
dependency: "direct main"
description:
Expand Down
Loading

0 comments on commit aa99995

Please sign in to comment.