TF-524 Apply quick search for mobile and tablet

This commit is contained in:
dab246
2022-05-24 11:56:50 +07:00
committed by Dat H. Pham
parent 9a142a0e23
commit 11c9a8713a
30 changed files with 647 additions and 2429 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ export 'presentation/views/modal_sheets/edit_text_modal_sheet_builder.dart';
export 'presentation/views/search/search_bar_view.dart'; export 'presentation/views/search/search_bar_view.dart';
export 'presentation/views/popup_menu/popup_menu_item_widget.dart'; export 'presentation/views/popup_menu/popup_menu_item_widget.dart';
export 'presentation/views/tab_bar/custom_tab_indicator.dart'; export 'presentation/views/tab_bar/custom_tab_indicator.dart';
export 'presentation/views/typeahead/typeahead_for_quick_search.dart'; export 'presentation/views/quick_search/quick_search_input_form.dart';
// Resources // Resources
export 'presentation/resources/assets_paths.dart'; export 'presentation/resources/assets_paths.dart';
File diff suppressed because it is too large Load Diff
@@ -1,15 +0,0 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
typedef FutureOr<Iterable<T>> SuggestionsCallback<T>(String pattern);
typedef FutureOr<Iterable<R>> FetchRecentActionCallback<R>(String pattern);
typedef Widget ItemBuilder<T>(BuildContext context, T itemData);
typedef void SuggestionSelectionCallback<T>(T suggestion);
typedef void RecentSelectionCallback<R>(R recent);
typedef Widget ErrorBuilder(BuildContext context, Object? error);
typedef Widget ButtonActionBuilder(BuildContext context, dynamic action);
typedef void ButtonActionCallback(dynamic action);
typedef Widget AnimationTransitionBuilder(
BuildContext context, Widget child, AnimationController? controller);
@@ -1,5 +0,0 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
final supportedPlatform = (kIsWeb || Platform.isAndroid || Platform.isIOS);
@@ -7,6 +7,10 @@ class RecentSearch with EquatableMixin {
RecentSearch(this.value, this.creationDate); RecentSearch(this.value, this.creationDate);
factory RecentSearch.now(String word) {
return RecentSearch(word, DateTime.now());
}
@override @override
List<Object?> get props => [value, creationDate]; List<Object?> get props => [value, creationDate];
} }
@@ -1,9 +1,9 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:model/email/email_action_type.dart'; import 'package:model/email/email_action_type.dart';
import 'package:model/email/filter_message_option.dart';
import 'package:model/email/presentation_email.dart'; import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/routes/router_arguments.dart'; import 'package:tmail_ui_user/main/routes/router_arguments.dart';
class DashBoardAction extends UIAction { class DashBoardAction extends UIAction {
@@ -97,4 +97,12 @@ class OpenEmailDetailedAction extends DashBoardAction {
@override @override
List<Object?> get props => [presentationEmail]; List<Object?> get props => [presentationEmail];
}
class DisableSearchEmailAction extends DashBoardAction {
DisableSearchEmailAction();
@override
List<Object?> get props => [];
} }
@@ -1,34 +0,0 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension FilterMessageOptionExtension on FilterMessageOption {
String getName(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return AppLocalizations.of(context).unread;
case FilterMessageOption.attachments:
return AppLocalizations.of(context).with_attachments;
case FilterMessageOption.starred:
return AppLocalizations.of(context).starred;
}
}
String getIcon(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return imagePaths.icUnread;
case FilterMessageOption.attachments:
return imagePaths.icAttachment;
case FilterMessageOption.starred:
return imagePaths.icStar;
}
}
}
@@ -50,6 +50,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/emai
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart';
@@ -82,7 +83,6 @@ class MailboxDashBoardController extends ReloadableController {
final accountId = Rxn<AccountId>(); final accountId = Rxn<AccountId>();
final userProfile = Rxn<UserProfile>(); final userProfile = Rxn<UserProfile>();
final searchState = SearchState.initial().obs; final searchState = SearchState.initial().obs;
final suggestionSearch = <String>[].obs;
final dashBoardAction = Rxn<UIAction>(); final dashBoardAction = Rxn<UIAction>();
final routePath = AppRoutes.MAILBOX_DASHBOARD.obs; final routePath = AppRoutes.MAILBOX_DASHBOARD.obs;
final appInformation = Rxn<PackageInfo>(); final appInformation = Rxn<PackageInfo>();
@@ -286,35 +286,40 @@ class MailboxDashBoardController extends ReloadableController {
void disableSearch() { void disableSearch() {
searchState.value = searchState.value.disableSearchState(); searchState.value = searchState.value.disableSearchState();
searchQuery = SearchQuery.initial(); searchQuery = SearchQuery.initial();
clearSuggestionSearch();
searchInputController.clear(); searchInputController.clear();
listFilterQuickSearch.clear(); listFilterQuickSearch.clear();
emailReceiveTimeType.value = null;
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
} }
void clearSearchText() { void clearTextSearch() {
searchQuery = SearchQuery.initial(); searchQuery = SearchQuery.initial();
clearSuggestionSearch(); searchInputController.clear();
searchFocus.requestFocus(); searchFocus.requestFocus();
} }
void clearSuggestionSearch() { void updateTextSearch(String value) {
suggestionSearch.clear(); searchInputController.text = value;
}
void addSuggestionSearch(String query) {
if (query.trim().isNotEmpty) {
suggestionSearch.value = [query];
} else {
clearSearchText();
}
} }
void searchEmail(BuildContext context, String value) { void searchEmail(BuildContext context, String value) {
searchQuery = SearchQuery(value); searchQuery = SearchQuery(value);
dispatchState(Right(SearchEmailNewQuery(searchQuery ?? SearchQuery.initial()))); dispatchState(Right(SearchEmailNewQuery(searchQuery ?? SearchQuery.initial())));
clearSuggestionSearch();
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
if (searchInsideEmailDetailedViewIsActive(context)) {
closeEmailDetailedView();
}
}
bool searchInsideEmailDetailedViewIsActive(BuildContext context) {
return BuildUtils.isWeb
&& _responsiveUtils.isDesktop(context)
&& routePath.value == AppRoutes.EMAIL;
}
void closeEmailDetailedView() {
dispatchRoute(AppRoutes.THREAD);
clearSelectedEmail();
} }
void _saveEmailAsDraftsSuccess(SaveEmailAsDraftsSuccess success) { void _saveEmailAsDraftsSuccess(SaveEmailAsDraftsSuccess success) {
@@ -472,6 +477,36 @@ class MailboxDashBoardController extends ReloadableController {
emailReceiveTimeType.value = receiveTimeType; emailReceiveTimeType.value = receiveTimeType;
} }
bool quickSearchFilterForLast7DaysIsActive () {
return listFilterQuickSearch.contains(QuickSearchFilter.last7Days)
&& emailReceiveTimeType.value != null;
}
bool quickSearchFilterForHasAttachmentIsActive () {
return listFilterQuickSearch.contains(QuickSearchFilter.hasAttachment)
|| filterMessageOption.value == FilterMessageOption.attachments;
}
bool quickSearchFilterForFromMeIsActive () {
return listFilterQuickSearch.contains(QuickSearchFilter.fromMe);
}
bool filterForHasAttachmentIsActive () {
return quickSearchFilterForHasAttachmentIsActive() || filterMessageWithAttachmentIsActive();
}
bool filterMessageWithAttachmentIsActive () {
return filterMessageOption.value == FilterMessageOption.attachments;
}
bool filterMessageUnreadIsActive () {
return filterMessageOption.value == FilterMessageOption.unread;
}
bool filterMessageStarredIsActive () {
return filterMessageOption.value == FilterMessageOption.starred;
}
void composeEmailAction() { void composeEmailAction() {
if (kIsWeb) { if (kIsWeb) {
if (dashBoardAction.value is! ComposeEmailAction) { if (dashBoardAction.value is! ComposeEmailAction) {
@@ -1,7 +1,6 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart';
@@ -15,7 +14,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/em
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/app_setting.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.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/app_routes.dart';
@@ -396,17 +395,17 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return Row( return Row(
children: [ children: [
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset(imagePaths.icBack, color: AppColor.colorTextButton, fit: BoxFit.fill), icon: SvgPicture.asset(
onTap: () { imagePaths.icBack,
controller.disableSearch(); color: AppColor.colorTextButton,
controller.dispatchAction(CancelSelectionAllEmailAction()); fit: BoxFit.fill),
}), onTap: () => controller.dispatchAction(DisableSearchEmailAction())),
Expanded(child: Container( Expanded(child: Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)), borderRadius: BorderRadius.all(Radius.circular(10)),
color: AppColor.colorBgSearchBar), color: AppColor.colorBgSearchBar),
height: 45, height: 45,
child: TypeAheadFormFieldQuickSearch<PresentationEmail, RecentSearch>( child: QuickSearchInputForm<PresentationEmail, RecentSearch>(
textFieldConfiguration: QuickSearchTextFieldConfiguration( textFieldConfiguration: QuickSearchTextFieldConfiguration(
controller: controller.searchInputController, controller: controller.searchInputController,
autofocus: true, autofocus: true,
@@ -414,7 +413,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
onSubmitted: (keyword) { onSubmitted: (keyword) {
if (keyword.trim().isNotEmpty) { if (keyword.trim().isNotEmpty) {
controller.saveRecentSearch(RecentSearch(keyword, DateTime.now())); controller.saveRecentSearch(RecentSearch.now(keyword));
} }
controller.searchEmail(context, keyword); controller.searchEmail(context, keyword);
}, },
@@ -424,30 +423,43 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
hintText: AppLocalizations.of(context).search_mail, hintText: AppLocalizations.of(context).search_mail,
hintStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0), hintStyle: const TextStyle(
labelStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0) color: AppColor.colorHintSearchBar,
fontSize: 17.0),
labelStyle: const TextStyle(
color: AppColor.colorHintSearchBar,
fontSize: 17.0)
), ),
leftButton: buildIconWeb( leftButton: buildIconWeb(
icon: SvgPicture.asset(imagePaths.icSearchBar, width: 16, height: 16, fit: BoxFit.fill), icon: SvgPicture.asset(
imagePaths.icSearchBar,
width: 16,
height: 16,
fit: BoxFit.fill),
onTap: () { onTap: () {
final keyword = controller.searchInputController.text; final keyword = controller.searchInputController.text;
if (keyword.trim().isNotEmpty) { if (keyword.trim().isNotEmpty) {
controller.saveRecentSearch(RecentSearch(keyword, DateTime.now())); controller.saveRecentSearch(RecentSearch.now(keyword));
} }
controller.searchEmail(context, keyword); controller.searchEmail(context, keyword);
}), }),
clearTextButton: buildIconWeb( clearTextButton: buildIconWeb(
icon: SvgPicture.asset(imagePaths.icClearTextSearch, width: 16, height: 16, fit: BoxFit.fill), icon: SvgPicture.asset(
imagePaths.icClearTextSearch,
width: 16,
height: 16,
fit: BoxFit.fill),
onTap: () { onTap: () {
controller.searchInputController.clear(); controller.clearTextSearch();
controller.clearSearchText();
}) })
), ),
suggestionsBoxDecoration: QuickSearchSuggestionsBoxDecoration( suggestionsBoxDecoration: QuickSearchSuggestionsBoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(16)), borderRadius: const BorderRadius.all(Radius.circular(16)),
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: responsiveUtils.isDesktop(context) ? 556 : double.infinity), maxWidth: responsiveUtils.isDesktop(context)
? 556
: double.infinity),
), ),
debounceDuration: const Duration(milliseconds: 500), debounceDuration: const Duration(milliseconds: 500),
listActionButton: const [ listActionButton: const [
@@ -463,12 +475,18 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
}, },
buttonActionCallback: (filterAction) { buttonActionCallback: (filterAction) {
if (filterAction is QuickSearchFilter) { if (filterAction is QuickSearchFilter) {
controller.selectQuickSearchFilter(filterAction, fromSuggestionBox: true); controller.selectQuickSearchFilter(
filterAction,
fromSuggestionBox: true);
} }
}, },
listActionPadding: const EdgeInsets.only(left: 24, top: 24, right: 24, bottom: 16), listActionPadding: const EdgeInsets.only(
left: 24,
top: 24,
right: 24,
bottom: 16),
titleHeaderRecent: Padding( titleHeaderRecent: Padding(
padding: const EdgeInsets.only(left: 24, right: 24, bottom: 8, top: 8), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: Text(AppLocalizations.of(context).recent, child: Text(AppLocalizations.of(context).recent,
style: const TextStyle(fontSize: 13.0, style: const TextStyle(fontSize: 13.0,
color: AppColor.colorTextButtonHeaderThread, color: AppColor.colorTextButtonHeaderThread,
@@ -480,12 +498,14 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return InkWell( return InkWell(
onTap: () { onTap: () {
if (keyword.trim().isNotEmpty) { if (keyword.trim().isNotEmpty) {
controller.saveRecentSearch(RecentSearch(keyword, DateTime.now())); controller.saveRecentSearch(RecentSearch.now(keyword));
} }
controller.searchEmail(context, keyword); controller.searchEmail(context, keyword);
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 24, right: 24, top: 14, bottom: 14), padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 14),
child: Row(children: [ child: Row(children: [
Text(AppLocalizations.of(context).showingResultsFor, Text(AppLocalizations.of(context).showingResultsFor,
style: const TextStyle(fontSize: 13.0, style: const TextStyle(fontSize: 13.0,
@@ -523,10 +543,12 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return controller.quickSearchEmailsAction(pattern); return controller.quickSearchEmailsAction(pattern);
}, },
itemBuilder: (context, email) { itemBuilder: (context, email) {
return EmailQuickSearchItemTileWidget(email, controller.selectedMailbox.value); return EmailQuickSearchItemTileWidget(
email, controller.selectedMailbox.value);
}, },
onSuggestionSelected: (presentationEmail) async { onSuggestionSelected: (presentationEmail) async {
controller.dispatchAction(OpenEmailDetailedAction(context, presentationEmail)); controller.dispatchAction(
OpenEmailDetailedAction(context, presentationEmail));
}), }),
)), )),
const SizedBox(width: 16), const SizedBox(width: 16),
@@ -3,8 +3,7 @@ import 'package:core/core.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:model/model.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/filter_message_option_extension.dart';
mixin FilterEmailPopupMenuMixin { mixin FilterEmailPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>(); final _imagePaths = Get.find<ImagePaths>();
@@ -38,15 +37,24 @@ mixin FilterEmailPopupMenuMixin {
width: 20, width: 20,
height: 20, height: 20,
fit: BoxFit.fill, fit: BoxFit.fill,
color: option != FilterMessageOption.starred ? AppColor.colorTextButton : null), color: option != FilterMessageOption.starred
? AppColor.colorTextButton
: null),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded(child: Text( Expanded(child: Text(
option.getName(context), option.getName(context),
style: const TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))), style: const TextStyle(
fontSize: 15,
color: Colors.black,
fontWeight: FontWeight.w500))),
if (optionSelected == option) if (optionSelected == option)
const SizedBox(width: 12), ... [
if (optionSelected == option) const SizedBox(width: 12),
SvgPicture.asset(_imagePaths.icFilterSelected, width: 16, height: 16, fit: BoxFit.fill), SvgPicture.asset(_imagePaths.icFilterSelected,
width: 16,
height: 16,
fit: BoxFit.fill),
]
]) ])
), ),
) )
@@ -6,9 +6,9 @@ import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
abstract class ThreadDataSource { abstract class ThreadDataSource {
Future<EmailsResponse> getAllEmail( Future<EmailsResponse> getAllEmail(
@@ -6,11 +6,11 @@ import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class LocalThreadDataSourceImpl extends ThreadDataSource { class LocalThreadDataSourceImpl extends ThreadDataSource {
@@ -6,11 +6,11 @@ import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class ThreadDataSourceImpl extends ThreadDataSource { class ThreadDataSourceImpl extends ThreadDataSource {
@@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/thread/data/extensions/email_extension.da
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_cache_extension.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/list_email_cache_extension.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class EmailCacheManager { class EmailCacheManager {
@@ -21,7 +21,9 @@ import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart'; import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart';
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
@@ -2,7 +2,7 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class EmailFilter with EquatableMixin { class EmailFilter with EquatableMixin {
@@ -1,9 +1,17 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum FilterMessageOption {
all,
unread,
attachments,
starred,
}
extension FilterMessageOptionExtension on FilterMessageOption { extension FilterMessageOptionExtension on FilterMessageOption {
String getIconToast(ImagePaths imagePaths) { String getIconToast(ImagePaths imagePaths) {
@@ -44,4 +52,56 @@ extension FilterMessageOptionExtension on FilterMessageOption {
return AppLocalizations.of(context).with_starred; return AppLocalizations.of(context).with_starred;
} }
} }
bool filterPresentationEmail(PresentationEmail email) {
switch(this) {
case FilterMessageOption.all:
return true;
case FilterMessageOption.unread:
return !email.hasRead;
case FilterMessageOption.attachments:
return email.withAttachments;
case FilterMessageOption.starred:
return email.hasStarred;
}
}
bool filterEmail(Email email) {
switch(this) {
case FilterMessageOption.all:
return true;
case FilterMessageOption.unread:
return !email.hasRead;
case FilterMessageOption.attachments:
return email.withAttachments;
case FilterMessageOption.starred:
return email.hasStarred;
}
}
String getName(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return AppLocalizations.of(context).unread;
case FilterMessageOption.attachments:
return AppLocalizations.of(context).with_attachments;
case FilterMessageOption.starred:
return AppLocalizations.of(context).starred;
}
}
String getIcon(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return imagePaths.icUnread;
case FilterMessageOption.attachments:
return imagePaths.icAttachment;
case FilterMessageOption.starred:
return imagePaths.icStar;
}
}
} }
@@ -6,8 +6,9 @@ import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart'; import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart';
abstract class ThreadRepository { abstract class ThreadRepository {
@@ -4,6 +4,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart';
@@ -5,6 +5,7 @@ import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
@@ -42,6 +42,8 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_da
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/email_receive_time_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart'; import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart';
@@ -62,7 +64,6 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/move_multiple_emai
import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart';
@@ -92,7 +93,7 @@ class ThreadController extends BaseController {
final MoveToMailboxInteractor _moveToMailboxInteractor; final MoveToMailboxInteractor _moveToMailboxInteractor;
final emailList = <PresentationEmail>[].obs; final emailList = <PresentationEmail>[].obs;
final emailListSearch = <PresentationEmail>[].obs; final searchIsActive = RxBool(false);
bool canLoadMore = true; bool canLoadMore = true;
bool canSearchMore = true; bool canSearchMore = true;
@@ -113,6 +114,10 @@ class ThreadController extends BaseController {
PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value; PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value;
TextEditingController get searchController => mailboxDashBoardController.searchInputController;
String get currentTextSearch => mailboxDashBoardController.searchInputController.text;
ThreadController( ThreadController(
this._getEmailsInMailboxInteractor, this._getEmailsInMailboxInteractor,
this._markAsMultipleEmailReadInteractor, this._markAsMultipleEmailReadInteractor,
@@ -154,7 +159,7 @@ class ThreadController extends BaseController {
newState.fold( newState.fold(
(failure) { (failure) {
if (failure is SearchEmailFailure) { if (failure is SearchEmailFailure) {
emailListSearch.clear(); emailList.clear();
} else if (failure is SearchMoreEmailFailure || failure is LoadMoreEmailsFailure) { } else if (failure is SearchMoreEmailFailure || failure is LoadMoreEmailsFailure) {
_isLoadingMore = false; _isLoadingMore = false;
} }
@@ -181,7 +186,6 @@ class ThreadController extends BaseController {
void onDone() { void onDone() {
viewState.value.fold( viewState.value.fold(
(failure) { (failure) {
log('ThreadController::onDone(): failure: $failure');
if (failure is MarkAsMultipleEmailReadAllFailure if (failure is MarkAsMultipleEmailReadAllFailure
|| failure is MarkAsMultipleEmailReadFailure) { || failure is MarkAsMultipleEmailReadFailure) {
_markAsReadSelectedMultipleEmailFailure(failure); _markAsReadSelectedMultipleEmailFailure(failure);
@@ -197,7 +201,6 @@ class ThreadController extends BaseController {
(success) { (success) {
if (success is MarkAsMultipleEmailReadAllSuccess if (success is MarkAsMultipleEmailReadAllSuccess
|| success is MarkAsMultipleEmailReadHasSomeEmailFailure) { || success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
log('ThreadController::onDone(): success: $success');
_markAsReadSelectedMultipleEmailSuccess(success); _markAsReadSelectedMultipleEmailSuccess(success);
} else if (success is MoveMultipleEmailToMailboxAllSuccess } else if (success is MoveMultipleEmailToMailboxAllSuccess
|| success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { || success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
@@ -239,9 +242,7 @@ class ThreadController extends BaseController {
searchWorker = ever(mailboxDashBoardController.searchState, (searchState) { searchWorker = ever(mailboxDashBoardController.searchState, (searchState) {
if (searchState is SearchState) { if (searchState is SearchState) {
if (searchState.searchStatus == SearchStatus.INACTIVE) { if (searchState.searchStatus == SearchStatus.ACTIVE) {
emailListSearch.clear();
} else if (searchState.searchStatus == SearchStatus.ACTIVE) {
cancelSelectEmail(); cancelSelectEmail();
} }
} }
@@ -270,6 +271,9 @@ class ThreadController extends BaseController {
} if (action is OpenEmailDetailedAction) { } if (action is OpenEmailDetailedAction) {
pressEmailAction(action.context, EmailActionType.preview, action.presentationEmail); pressEmailAction(action.context, EmailActionType.preview, action.presentationEmail);
mailboxDashBoardController.clearDashBoardAction(); mailboxDashBoardController.clearDashBoardAction();
} if (action is DisableSearchEmailAction) {
closeSearchEmailAction();
mailboxDashBoardController.clearDashBoardAction();
} }
} }
}); });
@@ -318,7 +322,6 @@ class ThreadController extends BaseController {
} }
void _getAllEmailSuccess(GetAllEmailSuccess success) { void _getAllEmailSuccess(GetAllEmailSuccess success) {
log('ThreadController::_getAllEmailSuccess(): ${success.emailList.length}');
_currentEmailState = success.currentEmailState; _currentEmailState = success.currentEmailState;
emailList.value = success.emailList; emailList.value = success.emailList;
if (listEmailController.hasClients) { if (listEmailController.hasClients) {
@@ -327,7 +330,6 @@ class ThreadController extends BaseController {
} }
void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) {
log('ThreadController::_refreshChangesAllEmailSuccess(): ${success.emailList.length}');
_currentEmailState = success.currentEmailState; _currentEmailState = success.currentEmailState;
final emailsBeforeChanges = emailList; final emailsBeforeChanges = emailList;
@@ -341,7 +343,6 @@ class ThreadController extends BaseController {
} }
void _getAllEmailAction(AccountId accountId, {MailboxId? mailboxId}) { void _getAllEmailAction(AccountId accountId, {MailboxId? mailboxId}) {
log('ThreadController::_getAllEmailAction(): mailboxId = $mailboxId');
consumeState(_getEmailsInMailboxInteractor.execute( consumeState(_getEmailsInMailboxInteractor.execute(
accountId, accountId,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
@@ -394,37 +395,30 @@ class ThreadController extends BaseController {
} }
void _refreshEmailChanges() { void _refreshEmailChanges() {
log('ThreadController::_refreshEmailChanges(): ');
if (isSearchActive()) { if (isSearchActive()) {
if (_accountId != null && searchQuery != null) { if (_accountId != null && searchQuery != null) {
final limit = emailListSearch.isNotEmpty ? UnsignedInt(emailListSearch.length) : ThreadConstants.defaultLimit; final limit = emailList.isNotEmpty
consumeState(_searchEmailInteractor.execute( ? UnsignedInt(emailList.length)
_accountId!, : ThreadConstants.defaultLimit;
limit: limit, _searchEmail(limit: limit);
sort: _sortOrder, }
filter: EmailFilterCondition( } else {
text: searchQuery!.value, if (_accountId != null && _currentEmailState != null) {
inMailbox: _currentMailboxId), consumeState(_refreshChangesEmailsInMailboxInteractor.execute(
properties: ThreadConstants.propertiesDefault, _accountId!,
_currentEmailState!,
sort: _sortOrder,
propertiesCreated: ThreadConstants.propertiesDefault,
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
inMailboxId: _currentMailboxId,
filterOption: mailboxDashBoardController.filterMessageOption.value
)); ));
} }
} }
if (_accountId != null && _currentEmailState != null) {
consumeState(_refreshChangesEmailsInMailboxInteractor.execute(
_accountId!,
_currentEmailState!,
sort: _sortOrder,
propertiesCreated: ThreadConstants.propertiesDefault,
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
inMailboxId: _currentMailboxId,
filterOption: mailboxDashBoardController.filterMessageOption.value
));
}
} }
void loadMoreEmails() { void loadMoreEmails() {
if (canLoadMore && _accountId != null) { if (canLoadMore && _accountId != null) {
log('ThreadController::loadMoreEmails(): latest: ${emailList.last.receivedAt}');
startFpsMeter(); startFpsMeter();
consumeState(_loadMoreEmailsInMailboxInteractor.execute( consumeState(_loadMoreEmailsInMailboxInteractor.execute(
GetEmailRequest( GetEmailRequest(
@@ -439,11 +433,8 @@ class ThreadController extends BaseController {
} }
void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) { void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) {
log('ThreadController::_loadMoreEmailsSuccess(): [BEFORE] totalEmailList = ${emailList.length}');
if (success.emailList.isNotEmpty) { if (success.emailList.isNotEmpty) {
log('ThreadController::_loadMoreEmailsSuccess(): add success: ${success.emailList.length}');
emailList.addAll(success.emailList); emailList.addAll(success.emailList);
log('ThreadController::_loadMoreEmailsSuccess(): [AFTER] totalEmailList = ${emailList.length}');
} else { } else {
canLoadMore = false; canLoadMore = false;
} }
@@ -466,15 +457,9 @@ class ThreadController extends BaseController {
} }
void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) { void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) {
if (isSearchActive()) { emailList.value = emailList
emailListSearch.value = emailListSearch .map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email) .toList();
.toList();
} else {
emailList.value = emailList
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
}
if (_isUnSelectedAll()) { if (_isUnSelectedAll()) {
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE; mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
@@ -492,41 +477,27 @@ class ThreadController extends BaseController {
} }
void setSelectAllEmailAction() { void setSelectAllEmailAction() {
if (isSearchActive()) { emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE)).toList();
emailListSearch.value = emailListSearch.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE)).toList();
} else {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE)).toList();
}
mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE; mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE;
mailboxDashBoardController.listEmailSelected.value = listEmailSelected; mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
} }
List<PresentationEmail> get listEmailSelected { List<PresentationEmail> get listEmailSelected {
if (isSearchActive()) { return emailList.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
return emailListSearch.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
} else {
return emailList.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
}
} }
bool _isUnSelectedAll() { bool _isUnSelectedAll() {
if (isSearchActive()) { return emailList.every((email) => email.selectMode == SelectMode.INACTIVE);
return emailListSearch.every((email) => email.selectMode == SelectMode.INACTIVE);
} else {
return emailList.every((email) => email.selectMode == SelectMode.INACTIVE);
}
} }
void cancelSelectEmail() { void cancelSelectEmail() {
emailListSearch.value = emailListSearch.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList(); emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE; mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
mailboxDashBoardController.listEmailSelected.clear(); mailboxDashBoardController.listEmailSelected.clear();
} }
void markAsReadAllEmails() { void markAsReadAllEmails() {
final listEmail = isSearchActive() ? emailListSearch.allEmailUnread : emailList.allEmailUnread; final listEmail = emailList.allEmailUnread;
log('ThreadController::markAsReadAllEmails(): ${listEmail.length}');
if (listEmail.isNotEmpty) { if (listEmail.isNotEmpty) {
markAsReadSelectedMultipleEmail(listEmail); markAsReadSelectedMultipleEmail(listEmail);
} }
@@ -534,12 +505,10 @@ class ThreadController extends BaseController {
void markAsReadSelectedMultipleEmail(List<PresentationEmail> listPresentationEmail) { void markAsReadSelectedMultipleEmail(List<PresentationEmail> listPresentationEmail) {
final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList(); final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList();
log('ThreadController::markAsReadSelectedMultipleEmail(): listPresentationEmail: ${listPresentationEmail.length}');
final readAction = listPresentationEmail.isAllEmailRead ? ReadActions.markAsUnread : ReadActions.markAsRead; final readAction = listPresentationEmail.isAllEmailRead ? ReadActions.markAsUnread : ReadActions.markAsRead;
final mailboxCurrent = mailboxDashBoardController.selectedMailbox.value; final mailboxCurrent = mailboxDashBoardController.selectedMailbox.value;
if (_accountId != null && mailboxCurrent != null) { if (_accountId != null && mailboxCurrent != null) {
cancelSelectEmail(); cancelSelectEmail();
log('ThreadController::markAsReadSelectedMultipleEmail(): listEmail: ${listEmail.length}');
consumeState(_markAsMultipleEmailReadInteractor.execute(_accountId!, listEmail, readAction)); consumeState(_markAsMultipleEmailReadInteractor.execute(_accountId!, listEmail, readAction));
} }
} }
@@ -564,7 +533,6 @@ class ThreadController extends BaseController {
message: message, message: message,
icon: readActions == ReadActions.markAsUnread ? _imagePaths.icUnreadToast : _imagePaths.icReadToast); icon: readActions == ReadActions.markAsUnread ? _imagePaths.icUnreadToast : _imagePaths.icReadToast);
} }
log('ThreadController::_markAsReadSelectedMultipleEmailSuccess(): _refreshEmailChanges');
_refreshEmailChanges(); _refreshEmailChanges();
} }
@@ -602,18 +570,18 @@ class ThreadController extends BaseController {
? FilterMessageOption.all ? FilterMessageOption.all
: filterOption; : filterOption;
log('ThreadController::filterMessagesAction(): newFilterOption: $newFilterOption');
mailboxDashBoardController.filterMessageOption.value = newFilterOption; mailboxDashBoardController.filterMessageOption.value = newFilterOption;
log('ThreadController::filterMessagesAction(): filterMessageOption: ${mailboxDashBoardController.filterMessageOption}');
_appToast.showToastWithIcon( _appToast.showToastWithIcon(
currentOverlayContext!, currentOverlayContext!,
message: newFilterOption.getMessageToast(context), message: newFilterOption.getMessageToast(context),
icon: newFilterOption.getIconToast(_imagePaths)); icon: newFilterOption.getIconToast(_imagePaths));
refreshAllEmail(); if (isSearchActive()) {
_searchEmail();
} else {
refreshAllEmail();
}
} }
void moveSelectedMultipleEmailToMailbox(List<PresentationEmail> listEmail) async { void moveSelectedMultipleEmailToMailbox(List<PresentationEmail> listEmail) async {
@@ -839,34 +807,62 @@ class ThreadController extends BaseController {
} }
void disableSearch() { void disableSearch() {
emailListSearch.clear(); searchIsActive.value = false;
mailboxDashBoardController.disableSearch(); mailboxDashBoardController.disableSearch();
cancelSelectEmail();
} }
void _searchEmail() { void closeSearchEmailAction() {
emailListSearch.clear(); disableSearch();
cancelSelectEmail();
refreshAllEmail();
}
void clearTextSearch() {
mailboxDashBoardController.clearTextSearch();
}
void _searchEmail({UnsignedInt? limit}) {
if (_accountId != null && searchQuery != null) { if (_accountId != null && searchQuery != null) {
searchIsActive.value = true;
UTCDate? afterTime; UTCDate? afterTime;
if (mailboxDashBoardController.listFilterQuickSearch.contains(QuickSearchFilter.last7Days) bool? hasAttachment;
&& mailboxDashBoardController.emailReceiveTimeType.value != null) { String? fromAddress;
String? keywordUnread;
String? keywordStarred;
if (mailboxDashBoardController.quickSearchFilterForLast7DaysIsActive()) {
afterTime = mailboxDashBoardController.emailReceiveTimeType.value!.toUTCDate(); afterTime = mailboxDashBoardController.emailReceiveTimeType.value!.toUTCDate();
} }
if (mailboxDashBoardController.filterForHasAttachmentIsActive()) {
hasAttachment = true;
}
if (mailboxDashBoardController.quickSearchFilterForFromMeIsActive()) {
fromAddress = mailboxDashBoardController.userProfile.value?.email;
}
if (mailboxDashBoardController.filterMessageUnreadIsActive()) {
keywordUnread = KeyWordIdentifier.emailSeen.value;
}
if (mailboxDashBoardController.filterMessageStarredIsActive()) {
keywordStarred = KeyWordIdentifier.emailFlagged.value;
}
final emailFilterCondition = EmailFilterCondition( final emailFilterCondition = EmailFilterCondition(
text: searchQuery!.value, text: searchQuery!.value,
hasAttachment: mailboxDashBoardController.listFilterQuickSearch.contains(QuickSearchFilter.hasAttachment) hasAttachment: hasAttachment,
? true : null, from: fromAddress,
from: mailboxDashBoardController.listFilterQuickSearch.contains(QuickSearchFilter.fromMe)
? mailboxDashBoardController.userProfile.value!.email
: null,
after: afterTime, after: afterTime,
hasKeyword: keywordStarred,
notKeyword: keywordUnread,
inMailbox: _currentMailboxId); inMailbox: _currentMailboxId);
consumeState(_searchEmailInteractor.execute( consumeState(_searchEmailInteractor.execute(
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: limit ?? ThreadConstants.defaultLimit,
sort: _sortOrder, sort: _sortOrder,
filter: emailFilterCondition, filter: emailFilterCondition,
properties: ThreadConstants.propertiesDefault, properties: ThreadConstants.propertiesDefault,
@@ -879,10 +875,10 @@ class ThreadController extends BaseController {
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox)) .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox))
.toList(); .toList();
final emailsSearchBeforeChanges = emailListSearch; final emailsSearchBeforeChanges = emailList;
final emailsSearchAfterChanges = resultEmailSearchList; final emailsSearchAfterChanges = resultEmailSearchList;
final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges); final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges);
emailListSearch.value = newListEmailSearch; emailList.value = newListEmailSearch;
} }
void searchMoreEmails() { void searchMoreEmails() {
@@ -893,9 +889,9 @@ class ThreadController extends BaseController {
sort: _sortOrder, sort: _sortOrder,
filter: EmailFilterCondition( filter: EmailFilterCondition(
text: searchQuery!.value, text: searchQuery!.value,
before: emailListSearch.last.receivedAt), before: emailList.last.receivedAt),
properties: ThreadConstants.propertiesDefault, properties: ThreadConstants.propertiesDefault,
lastEmailId: emailListSearch.last.id lastEmailId: emailList.last.id
)); ));
} }
} }
@@ -904,9 +900,9 @@ class ThreadController extends BaseController {
if (success.emailList.isNotEmpty) { if (success.emailList.isNotEmpty) {
final resultEmailSearchList = success.emailList final resultEmailSearchList = success.emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox)) .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox))
.where((email) => !emailListSearch.contains(email)) .where((email) => !emailList.contains(email))
.toList(); .toList();
emailListSearch.addAll(resultEmailSearchList); emailList.addAll(resultEmailSearchList);
} else { } else {
canSearchMore = false; canSearchMore = false;
} }
@@ -916,7 +912,6 @@ class ThreadController extends BaseController {
bool isSelectionEnabled() => mailboxDashBoardController.isSelectionEnabled(); bool isSelectionEnabled() => mailboxDashBoardController.isSelectionEnabled();
void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List<PresentationEmail> selectionEmail) { void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List<PresentationEmail> selectionEmail) {
log('ThreadController::pressEmailSelectionAction(): selectionEmail: ${selectionEmail.length}');
switch(actionType) { switch(actionType) {
case EmailActionType.markAsRead: case EmailActionType.markAsRead:
case EmailActionType.markAsUnread: case EmailActionType.markAsUnread:
+322 -222
View File
@@ -5,8 +5,13 @@ import 'package:get/get.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.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/email_action_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/email_receive_time_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/quick_search_filter.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/email_quick_search_item_tile_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
@@ -16,11 +21,10 @@ import 'package:tmail_ui_user/features/thread/presentation/widgets/bottom_bar_th
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart' import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart'
if (dart.library.html) 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_web_builder.dart'; if (dart.library.html) 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_web_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/filter_message_cupertino_action_sheet_action_builder.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/filter_message_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/suggestion_box_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin { class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
FilterEmailPopupMenuMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>(); final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>(); final _imagePaths = Get.find<ImagePaths>();
@@ -46,50 +50,74 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Obx(() => !controller.isSearchActive() if ((!_responsiveUtils.isDesktop(context) && BuildUtils.isWeb) || !BuildUtils.isWeb)
&& ((!_responsiveUtils.isDesktop(context) && BuildUtils.isWeb) || !BuildUtils.isWeb) ... [
? _buildAppBarNormal(context) _buildAppBarNormal(context),
: const SizedBox.shrink()), Obx(() {
_buildSearchInputFormForMobile(context), return Stack(children: [
Container( if (!controller.isSearchActive())
color: BuildUtils.isWeb ? AppColor.colorBgDesktop : Colors.white, Container(
padding: EdgeInsets.zero, color: Colors.white,
child: _buildSearchButtonViewForMobile(context)), padding: EdgeInsets.symmetric(
Obx(() => controller.isMailboxTrash && controller.emailList.isNotEmpty && !controller.isSearchActive() horizontal: 16,
? _buildEmptyTrashButton(context) vertical: BuildUtils.isWeb && _responsiveUtils.isTabletLarge(context) ? 8 : 0),
: const SizedBox.shrink()), margin: const EdgeInsets.only(
Obx(() => controller.isSearchActive() && _responsiveUtils.isDesktop(context) && BuildUtils.isWeb bottom: !BuildUtils.isWeb ? 16 : 0),
? _buildListButtonQuickSearchFilter(context) child: _buildSearchFormInActive(context))
: const SizedBox.shrink()), else
Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: BuildUtils.isWeb && _responsiveUtils.isTabletLarge(context) ? 8 : 0),
margin: const EdgeInsets.only(
bottom: !BuildUtils.isWeb ? 16 : 0),
child: _buildSearchFormActive(context))
]);
})
]
else
const SizedBox.shrink(),
Obx(() {
if (controller.isMailboxTrash && controller.emailList.isNotEmpty
&& !controller.isSearchActive()) {
return _buildEmptyTrashButton(context);
} else {
return const SizedBox.shrink();
}
}),
Obx(() {
if (controller.isSearchActive()
&& controller.searchIsActive.isTrue
&& _responsiveUtils.isDesktop(context)
&& BuildUtils.isWeb) {
return _buildListButtonQuickSearchFilter(context);
} else {
return const SizedBox.shrink();
}
}),
Expanded(child: Container( Expanded(child: Container(
color: BuildUtils.isWeb ? AppColor.colorBgDesktop : Colors.white, alignment: Alignment.center,
padding: BuildUtils.isWeb && _responsiveUtils.isDesktop(context) margin: BuildUtils.isWeb && _responsiveUtils.isDesktop(context)
? const EdgeInsets.only(left: 32, right: 24, top: 16, bottom: 24) ? const EdgeInsets.only(left: 32, right: 24, top: 16, bottom: 24)
: EdgeInsets.zero, : EdgeInsets.zero,
child: Stack(children: [ decoration: BoxDecoration(
Container( borderRadius: BuildUtils.isWeb && _responsiveUtils.isDesktop(context)
alignment: Alignment.center, ? BorderRadius.circular(20)
decoration: BoxDecoration( : null,
borderRadius: BuildUtils.isWeb && _responsiveUtils.isDesktop(context) border: BuildUtils.isWeb && _responsiveUtils.isDesktop(context)
? BorderRadius.circular(20) ? Border.all(color: AppColor.colorBorderBodyThread, width: 1)
: null, : null,
border: BuildUtils.isWeb && _responsiveUtils.isDesktop(context) color: Colors.white),
? Border.all(color: AppColor.colorBorderBodyThread, width: 1) child: Column(
: null, crossAxisAlignment: CrossAxisAlignment.start,
color: Colors.white), children: [
child: Column( _buildLoadingView(),
crossAxisAlignment: CrossAxisAlignment.start, Expanded(child: _buildListEmail(context)),
children: [ _buildLoadingViewLoadMore(),
if (_responsiveUtils.isMobile(context)) ]
_buildStatusResultSearch(context), )
_buildLoadingView(), )),
Expanded(child: _buildListEmail(context)),
_buildLoadingViewLoadMore(),
]
)
),
_buildSuggestionBox(context)
]))),
_buildListButtonSelectionForMobile(context), _buildListButtonSelectionForMobile(context),
] ]
) )
@@ -125,62 +153,189 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
}); });
} }
Widget _buildSearchButtonViewForMobile(BuildContext context) { Widget _buildSearchFormInActive(BuildContext context) {
return Obx(() { return (SearchBarView(_imagePaths)
if (!controller.isSearchActive() && ..hintTextSearch(AppLocalizations.of(context).search_emails)
((!_responsiveUtils.isDesktop(context) && BuildUtils.isWeb) || !BuildUtils.isWeb)) { ..addOnOpenSearchViewAction(() => controller.enableSearch(context)))
return Container( .build();
color: Colors.white,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 10),
child: (SearchBarView(_imagePaths)
..hintTextSearch(BuildUtils.isWeb ? AppLocalizations.of(context).search_emails : AppLocalizations.of(context).hint_search_emails)
..addOnOpenSearchViewAction(() => controller.enableSearch(context)))
.build());
} else {
return const SizedBox.shrink();
}
});
} }
Widget _buildSearchInputFormForMobile(BuildContext context) { Widget _buildSearchFormActive(BuildContext context) {
return Obx(() { return Row(
if (controller.isSearchActive() && children: [
((!_responsiveUtils.isDesktop(context) && BuildUtils.isWeb) || !BuildUtils.isWeb)) { buildIconWeb(
return Column(children: [ icon: SvgPicture.asset(
_buildSearchForm(context), _imagePaths.icBack,
const Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2), color: AppColor.colorTextButton,
]); fit: BoxFit.fill),
} else { onTap: () => controller.closeSearchEmailAction()),
return const SizedBox.shrink(); Expanded(child: Container(
} decoration: const BoxDecoration(
}); borderRadius: BorderRadius.all(Radius.circular(10)),
} color: AppColor.colorBgSearchBar),
height: 45,
Widget _buildSearchForm(BuildContext context) { child: QuickSearchInputForm<PresentationEmail, RecentSearch>(
return (SearchAppBarWidget( textFieldConfiguration: QuickSearchTextFieldConfiguration(
context, controller: controller.searchController,
_imagePaths, autofocus: true,
_responsiveUtils, focusNode: controller.mailboxDashBoardController.searchFocus,
controller.searchQuery, textInputAction: TextInputAction.done,
controller.mailboxDashBoardController.searchFocus, onSubmitted: (keyword) {
controller.mailboxDashBoardController.searchInputController, if (keyword.trim().isNotEmpty) {
suggestionSearch: controller.mailboxDashBoardController.suggestionSearch,) controller.mailboxDashBoardController
..addDecoration(const BoxDecoration(color: Colors.white)) .saveRecentSearch(RecentSearch.now(keyword));
..setMargin(const EdgeInsets.only(right: 10)) }
..setHintText(AppLocalizations.of(context).search_mail) controller.mailboxDashBoardController.searchEmail(context, keyword);
..addOnCancelSearchPressed(() => controller.disableSearch()) },
..addOnClearTextSearchAction(() => controller.mailboxDashBoardController.clearSearchText()) decoration: InputDecoration(
..addOnTextChangeSearchAction((query) => controller.mailboxDashBoardController.addSuggestionSearch(query)) border: InputBorder.none,
..addOnSearchTextAction((query) => controller.mailboxDashBoardController.searchEmail(context, query))) focusedBorder: InputBorder.none,
.build(); enabledBorder: InputBorder.none,
contentPadding: EdgeInsets.zero,
hintText: AppLocalizations.of(context).search_mail,
hintStyle: const TextStyle(
color: AppColor.colorHintSearchBar,
fontSize: 17.0),
labelStyle: const TextStyle(
color: AppColor.colorHintSearchBar,
fontSize: 17.0)
),
leftButton: buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icSearchBar,
width: 16,
height: 16,
fit: BoxFit.fill),
onTap: () {
final keyword = controller.currentTextSearch;
if (keyword.trim().isNotEmpty) {
controller.mailboxDashBoardController
.saveRecentSearch(RecentSearch.now(keyword));
}
controller.mailboxDashBoardController.searchEmail(context, keyword);
}),
clearTextButton: buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icClearTextSearch,
width: 16,
height: 16,
fit: BoxFit.fill),
onTap: () {
controller.clearTextSearch();
})
),
suggestionsBoxDecoration: const QuickSearchSuggestionsBoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(16)),
),
debounceDuration: const Duration(milliseconds: 500),
hideSuggestionsBox: _responsiveUtils.isScreenWithShortestSide(context),
listActionButton: const [
QuickSearchFilter.hasAttachment,
QuickSearchFilter.last7Days,
QuickSearchFilter.fromMe,
],
actionButtonBuilder: (context, filterAction) {
if (filterAction is QuickSearchFilter) {
return _buildQuickSearchFilterButtonSuggestionBox(
context,
filterAction);
}
return const SizedBox.shrink();
},
buttonActionCallback: (filterAction) {
if (filterAction is QuickSearchFilter) {
controller.mailboxDashBoardController
.selectQuickSearchFilter(filterAction, fromSuggestionBox: true);
}
},
listActionPadding: const EdgeInsets.only(
left: 24,
top: 24,
right: 24,
bottom: 16),
titleHeaderRecent: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: Text(AppLocalizations.of(context).recent,
style: const TextStyle(fontSize: 13.0,
color: AppColor.colorTextButtonHeaderThread,
fontWeight: FontWeight.w500)
)
),
buttonShowAllResult: (context, keyword) {
if (keyword is String) {
return InkWell(
onTap: () {
if (keyword.trim().isNotEmpty) {
controller.mailboxDashBoardController
.saveRecentSearch(RecentSearch.now(keyword));
}
controller.mailboxDashBoardController.searchEmail(context, keyword);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
child: Row(children: [
Text(AppLocalizations.of(context).showingResultsFor,
style: const TextStyle(fontSize: 13.0,
color: AppColor.colorTextButtonHeaderThread,
fontWeight: FontWeight.w500)
),
const SizedBox(width: 4),
Expanded(child: Text('"$keyword"',
style: const TextStyle(
fontSize: 13.0,
color: Colors.black,
fontWeight: FontWeight.w500)))
])
),
);
} else {
return const SizedBox.shrink();
}
},
loadingBuilder: (context) => Padding(
padding: const EdgeInsets.only(bottom: 16),
child: loadingWidget,
),
fetchRecentActionCallback: (pattern) async {
return controller.mailboxDashBoardController
.getAllRecentSearchAction(pattern);
},
itemRecentBuilder: (context, recent) {
return RecentSearchItemTileWidget(recent);
},
onRecentSelected: (recent) {
controller.mailboxDashBoardController
.updateTextSearch(recent.value);
controller.mailboxDashBoardController
.searchEmail(context, recent.value);
},
suggestionsCallback: (pattern) async {
return controller.mailboxDashBoardController
.quickSearchEmailsAction(pattern);
},
itemBuilder: (context, email) {
return EmailQuickSearchItemTileWidget(
email,
controller.currentMailbox);
},
onSuggestionSelected: (presentationEmail) async {
controller.pressEmailAction(
context,
EmailActionType.preview,
presentationEmail);
}),
)),
const SizedBox(width: 16),
]
);
} }
Widget _buildAppBarNormal(BuildContext context) { Widget _buildAppBarNormal(BuildContext context) {
return (AppBarThreadWidgetBuilder( return Obx(() {
return (AppBarThreadWidgetBuilder(
context, context,
_imagePaths, controller.currentMailbox,
_responsiveUtils,
controller.mailboxDashBoardController.selectedMailbox.value,
controller.listEmailSelected, controller.listEmailSelected,
controller.mailboxDashBoardController.currentSelectMode.value, controller.mailboxDashBoardController.currentSelectMode.value,
controller.mailboxDashBoardController.filterMessageOption.value) controller.mailboxDashBoardController.filterMessageOption.value)
@@ -188,17 +343,24 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
..addOnEditThreadAction(() => controller.enableSelectionEmail()) ..addOnEditThreadAction(() => controller.enableSelectionEmail())
..addOnEmailSelectionAction((actionType, selectionEmail) => ..addOnEmailSelectionAction((actionType, selectionEmail) =>
controller.pressEmailSelectionAction(context, actionType, selectionEmail)) controller.pressEmailSelectionAction(context, actionType, selectionEmail))
..addOnFilterEmailAction((filterMessageOption, position) => ..addOnFilterEmailAction((filterMessageOption, position) {
_responsiveUtils.isScreenWithShortestSide(context) if (_responsiveUtils.isScreenWithShortestSide(context)) {
? controller.openContextMenuAction( controller.openContextMenuAction(
context, context,
_filterMessagesCupertinoActionTile(context, filterMessageOption)) _filterMessagesCupertinoActionTile(context, filterMessageOption));
: controller.openPopupMenuAction( } else {
context, controller.openPopupMenuAction(
position, context,
_popupMenuEmailActionTile(context, filterMessageOption))) position,
popupMenuFilterEmailActionTile(
context,
filterMessageOption,
(option) => controller.filterMessagesAction(context, option)));
}
})
..addOnCancelEditThread(() => controller.cancelSelectEmail())) ..addOnCancelEditThread(() => controller.cancelSelectEmail()))
.build(); .build();
});
} }
Widget _buildFloatingButtonCompose(BuildContext context) { Widget _buildFloatingButtonCompose(BuildContext context) {
@@ -232,75 +394,37 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
} }
List<Widget> _filterMessagesCupertinoActionTile(BuildContext context, FilterMessageOption optionCurrent) { List<Widget> _filterMessagesCupertinoActionTile(BuildContext context, FilterMessageOption optionCurrent) {
return <Widget>[ final listFilter = [
_filterMessageWithAttachmentsAction(context, optionCurrent), FilterMessageOption.attachments,
_filterMessagesUnreadAction(context, optionCurrent), FilterMessageOption.unread,
_filterMessageStarredAction(context, optionCurrent), FilterMessageOption.starred,
];
}
Widget _filterMessageWithAttachmentsAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
const Key('filter_attachment_action'),
SvgPicture.asset(_imagePaths.icAttachment, width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton),
AppLocalizations.of(context).with_attachments,
FilterMessageOption.attachments,
optionCurrent: optionCurrent,
iconLeftPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero,
actionSelected: SvgPicture.asset(_imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
Widget _filterMessagesUnreadAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
const Key('filter_unread_action'),
SvgPicture.asset(_imagePaths.icUnread, width: 28, height: 28, fit: BoxFit.fill),
AppLocalizations.of(context).unread,
FilterMessageOption.unread,
optionCurrent: optionCurrent,
iconLeftPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero,
actionSelected: SvgPicture.asset(_imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
Widget _filterMessageStarredAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
const Key('filter_starred_action'),
SvgPicture.asset(_imagePaths.icStar, width: 28, height: 28, fit: BoxFit.fill),
AppLocalizations.of(context).starred,
FilterMessageOption.starred,
optionCurrent: optionCurrent,
iconLeftPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero,
actionSelected: SvgPicture.asset(_imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
List<PopupMenuEntry> _popupMenuEmailActionTile(BuildContext context, FilterMessageOption option) {
return [
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: _filterMessageWithAttachmentsAction(context, option)),
const PopupMenuDivider(height: 0.5),
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: _filterMessagesUnreadAction(context, option)),
const PopupMenuDivider(height: 0.5),
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: _filterMessageStarredAction(context, option)),
]; ];
return listFilter.map((filter) => (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_email_${filter.name}'),
SvgPicture.asset(
filter.getIcon(_imagePaths),
width: 20,
height: 20,
fit: BoxFit.fill,
color: filter == FilterMessageOption.attachments
? AppColor.colorTextButton : null),
filter.getName(context),
filter,
optionCurrent: optionCurrent,
iconLeftPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: _responsiveUtils.isMobile(context)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero,
actionSelected: SvgPicture.asset(
_imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build()).toList();
} }
Widget _buildLoadingView() { Widget _buildLoadingView() {
@@ -344,25 +468,11 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
color: Colors.white, color: Colors.white,
child: Obx(() { child: Obx(() {
if (controller.isSearchActive()) { return _buildResultListEmail(context, controller.emailList);
if (controller.mailboxDashBoardController.suggestionSearch.isNotEmpty) {
return const SizedBox.shrink();
} else {
return _buildResultSearchEmails(context, controller.emailListSearch);
}
} else {
return _buildResultListEmail(context, controller.emailList);
}
}) })
); );
} }
Widget _buildResultSearchEmails(BuildContext context, List<PresentationEmail> listPresentationEmail) {
return listPresentationEmail.isNotEmpty
? _buildListEmailBody(context, listPresentationEmail)
: _buildEmptyEmail(context);
}
Widget _buildResultListEmail(BuildContext context, List<PresentationEmail> listPresentationEmail) { Widget _buildResultListEmail(BuildContext context, List<PresentationEmail> listPresentationEmail) {
if (controller.mailboxDashBoardController.currentSelectMode.value == SelectMode.INACTIVE) { if (controller.mailboxDashBoardController.currentSelectMode.value == SelectMode.INACTIVE) {
return listPresentationEmail.isNotEmpty return listPresentationEmail.isNotEmpty
@@ -433,42 +543,6 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
); );
} }
Widget _buildSuggestionBox(BuildContext context) {
return Obx(() => controller.mailboxDashBoardController.suggestionSearch.isNotEmpty
? (SuggestionBoxWidget(
context,
_imagePaths,
controller.mailboxDashBoardController.suggestionSearch)
..addOnSelectedSuggestion((suggestion) =>
controller.mailboxDashBoardController.searchEmail(context, suggestion)))
.build()
: const SizedBox.shrink()
);
}
Widget _buildStatusResultSearch(BuildContext context) {
return Obx(() {
if (controller.isSearchActive()) {
return controller.emailListSearch.isNotEmpty
? Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
decoration: BoxDecoration(
borderRadius: BuildUtils.isWeb && _responsiveUtils.isDesktop(context)
? const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))
: null,
color: AppColor.bgStatusResultSearch),
child: Text(
AppLocalizations.of(context).results,
style: const TextStyle(color: AppColor.baseTextColor, fontSize: 14, fontWeight: FontWeight.w500),
))
: const SizedBox.shrink();
} else {
return const SizedBox.shrink();
}
});
}
Widget _buildEmptyTrashButton(BuildContext context) { Widget _buildEmptyTrashButton(BuildContext context) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -661,4 +735,30 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
) )
); );
} }
Widget _buildQuickSearchFilterButtonSuggestionBox(
BuildContext context, QuickSearchFilter filter) {
return Obx(() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: filter.getBackgroundColor(controller.mailboxDashBoardController.listFilterQuickSearch)),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SvgPicture.asset(
filter.getIcon(_imagePaths, controller.mailboxDashBoardController.listFilterQuickSearch),
width: 16,
height: 16,
fit: BoxFit.fill),
const SizedBox(width: 4),
Text(
filter.getTitle(context,
receiveTimeType: controller.mailboxDashBoardController.emailReceiveTimeType.value),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: filter.getTextStyle(controller.mailboxDashBoardController.listFilterQuickSearch),
)
]));
});
}
} }
@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnFilterEmailAction = void Function(FilterMessageOption, RelativeRect? position); typedef OnFilterEmailAction = void Function(FilterMessageOption, RelativeRect? position);
@@ -15,6 +15,9 @@ typedef OnCancelEditThread = void Function();
typedef OnEmailSelectionAction = void Function(EmailActionType actionType, List<PresentationEmail>); typedef OnEmailSelectionAction = void Function(EmailActionType actionType, List<PresentationEmail>);
class AppBarThreadWidgetBuilder { class AppBarThreadWidgetBuilder {
final _imagePaths = Get.find<ImagePaths>();
final _responsiveUtils = Get.find<ResponsiveUtils>();
OnFilterEmailAction? _onFilterEmailAction; OnFilterEmailAction? _onFilterEmailAction;
OnOpenMailboxMenuActionClick? _onOpenMailboxMenuActionClick; OnOpenMailboxMenuActionClick? _onOpenMailboxMenuActionClick;
OnEditThreadAction? _onEditThreadAction; OnEditThreadAction? _onEditThreadAction;
@@ -22,8 +25,6 @@ class AppBarThreadWidgetBuilder {
OnEmailSelectionAction? _onEmailSelectionAction; OnEmailSelectionAction? _onEmailSelectionAction;
final BuildContext _context; final BuildContext _context;
final ImagePaths _imagePaths;
final ResponsiveUtils _responsiveUtils;
final PresentationMailbox? _currentMailbox; final PresentationMailbox? _currentMailbox;
final List<PresentationEmail> _listSelectionEmail; final List<PresentationEmail> _listSelectionEmail;
final SelectMode _selectMode; final SelectMode _selectMode;
@@ -31,8 +32,6 @@ class AppBarThreadWidgetBuilder {
AppBarThreadWidgetBuilder( AppBarThreadWidgetBuilder(
this._context, this._context,
this._imagePaths,
this._responsiveUtils,
this._currentMailbox, this._currentMailbox,
this._listSelectionEmail, this._listSelectionEmail,
this._selectMode, this._selectMode,
@@ -65,8 +64,11 @@ class AppBarThreadWidgetBuilder {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
color: Colors.white, color: Colors.white,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
padding: EdgeInsets.only(left: 8, bottom: 8, right: 8, padding: EdgeInsets.only(
top: (!BuildUtils.isWeb && _responsiveUtils.isPortraitMobile(_context)) ? 0 : 16), left: 8,
bottom: !BuildUtils.isWeb ? 8 : 16,
right: 8,
top: !BuildUtils.isWeb && _responsiveUtils.isPortraitMobile(_context) ? 0 : 16),
child: MediaQuery( child: MediaQuery(
data: const MediaQueryData(padding: EdgeInsets.zero), data: const MediaQueryData(padding: EdgeInsets.zero),
child: kIsWeb child: kIsWeb
@@ -211,7 +213,8 @@ class AppBarThreadWidgetBuilder {
color: Colors.transparent, color: Colors.transparent,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 16, right: 16), padding: const EdgeInsets.only(left: 16, right: 16),
child: GestureDetector( child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(10)),
onTap: () { onTap: () {
if (_onFilterEmailAction != null && _responsiveUtils.isScreenWithShortestSide(_context)) { if (_onFilterEmailAction != null && _responsiveUtils.isScreenWithShortestSide(_context)) {
_onFilterEmailAction!.call(_filterMessageOption, null); _onFilterEmailAction!.call(_filterMessageOption, null);
@@ -3,9 +3,10 @@ import 'package:core/core.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:model/model.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class FilterMessageCupertinoActionSheetActionBuilder extends CupertinoActionSheetActionBuilder<FilterMessageOption> { class FilterMessageCupertinoActionSheetActionBuilder
extends CupertinoActionSheetActionBuilder<FilterMessageOption> {
final FilterMessageOption option; final FilterMessageOption option;
final FilterMessageOption? optionCurrent; final FilterMessageOption? optionCurrent;
@@ -1,88 +0,0 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnSelectedSuggestion = Function(String);
class SuggestionBoxWidget {
OnSelectedSuggestion? _onSelectedSuggestion;
final BuildContext _context;
final ImagePaths _imagePaths;
double? _suggestionHeight;
double? _elevation;
final List<String> _listData;
SuggestionBoxWidget(
this._context,
this._imagePaths,
this._listData,
);
void setSuggestionHeight(double suggestionHeight) {
_suggestionHeight = suggestionHeight;
}
void setElevation(double elevation) {
_elevation = elevation;
}
void addOnSelectedSuggestion(OnSelectedSuggestion onSelectedSuggestion) {
_onSelectedSuggestion = onSelectedSuggestion;
}
Widget build() {
return Material(
elevation: _elevation ?? 3,
color: Colors.white,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: _suggestionHeight ?? 60,
),
child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: _listData.length,
itemBuilder: (BuildContext context, int index) => ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
onTap: () {
if (_onSelectedSuggestion != null) {
_onSelectedSuggestion!(_listData[index]);
}},
leading: IconButton(
color: AppColor.baseTextColor,
icon: SvgPicture.asset(_imagePaths.icSearch, color: AppColor.baseTextColor, fit: BoxFit.fill),
onPressed: () {
if (_onSelectedSuggestion != null) {
_onSelectedSuggestion!(_listData[index]);
}
}),
title: Transform(
transform: Matrix4.translationValues(-12.0, 0.0, 0.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'${AppLocalizations.of(_context).prefix_suggestion_search} ',
style: const TextStyle(fontSize: 15, color: AppColor.baseTextColor),
),
Expanded(child: Text(
'"${_listData[index]}"',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 15, color: AppColor.colorNameEmail),
))
],
)
)
),
),
),
);
}
}
@@ -1,40 +0,0 @@
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/email_extension.dart';
enum FilterMessageOption {
all,
unread,
attachments,
starred,
}
extension FilterMessageOptionExtension on FilterMessageOption {
bool filterPresentationEmail(PresentationEmail email) {
switch(this) {
case FilterMessageOption.all:
return true;
case FilterMessageOption.unread:
return !email.hasRead;
case FilterMessageOption.attachments:
return email.withAttachments;
case FilterMessageOption.starred:
return email.hasStarred;
}
}
bool filterEmail(Email email) {
switch(this) {
case FilterMessageOption.all:
return true;
case FilterMessageOption.unread:
return !email.hasRead;
case FilterMessageOption.attachments:
return email.withAttachments;
case FilterMessageOption.starred:
return email.hasStarred;
}
}
}
-2
View File
@@ -27,9 +27,7 @@ export 'email/read_actions.dart';
export 'email/attachment.dart'; export 'email/attachment.dart';
export 'email/mark_star_action.dart'; export 'email/mark_star_action.dart';
export 'email/email_property.dart'; export 'email/email_property.dart';
export 'email/email_filter.dart';
export 'email/email_content_type.dart'; export 'email/email_content_type.dart';
export 'email/filter_message_option.dart';
// Extensions // Extensions
export 'extensions/email_address_extension.dart'; export 'extensions/email_address_extension.dart';
@@ -11,6 +11,7 @@ import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
@@ -38,7 +39,7 @@ void main() {
when(threadRepository.getAllEmail( when(threadRepository.getAllEmail(
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
limit: UnsignedInt(20), limit: UnsignedInt(20),
sort: Set()..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
emailFilter: EmailFilter( emailFilter: EmailFilter(
filter: EmailFilterCondition(inMailbox: MailboxFixtures.inboxMailbox.id), filter: EmailFilterCondition(inMailbox: MailboxFixtures.inboxMailbox.id),
mailboxId: MailboxFixtures.inboxMailbox.id, mailboxId: MailboxFixtures.inboxMailbox.id,
@@ -66,7 +67,7 @@ void main() {
final streamStates = getEmailsInMailboxInteractor.execute( final streamStates = getEmailsInMailboxInteractor.execute(
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
limit: UnsignedInt(20), limit: UnsignedInt(20),
sort: Set()..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
emailFilter: EmailFilter( emailFilter: EmailFilter(
filter: EmailFilterCondition(inMailbox: MailboxFixtures.inboxMailbox.id), filter: EmailFilterCondition(inMailbox: MailboxFixtures.inboxMailbox.id),
mailboxId: MailboxFixtures.inboxMailbox.id, mailboxId: MailboxFixtures.inboxMailbox.id,
@@ -5,19 +5,22 @@
import 'dart:async' as _i3; import 'dart:async' as _i3;
import 'package:jmap_dart_client/jmap/account_id.dart' as _i5; import 'package:jmap_dart_client/jmap/account_id.dart' as _i5;
import 'package:jmap_dart_client/jmap/core/filter/filter.dart' as _i14; import 'package:jmap_dart_client/jmap/core/filter/filter.dart' as _i15;
import 'package:jmap_dart_client/jmap/core/properties/properties.dart' as _i9; import 'package:jmap_dart_client/jmap/core/properties/properties.dart' as _i9;
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart' as _i7; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart' as _i7;
import 'package:jmap_dart_client/jmap/core/state.dart' as _i10; import 'package:jmap_dart_client/jmap/core/state.dart' as _i10;
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart' as _i6; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart' as _i6;
import 'package:jmap_dart_client/jmap/mail/email/email.dart' as _i13; import 'package:jmap_dart_client/jmap/mail/email/email.dart' as _i14;
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart' as _i11; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart' as _i11;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:model/model.dart' as _i8; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart'
as _i8;
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart' import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'
as _i4; as _i4;
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart' import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'
as _i12; as _i12;
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart'
as _i13;
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart' import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'
as _i2; as _i2;
@@ -64,7 +67,7 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
_i9.Properties? propertiesCreated, _i9.Properties? propertiesCreated,
_i9.Properties? propertiesUpdated, _i9.Properties? propertiesUpdated,
_i11.MailboxId? inMailboxId, _i11.MailboxId? inMailboxId,
_i8.FilterMessageOption? filterOption}) => _i12.FilterMessageOption? filterOption}) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method(#refreshChanges, [ Invocation.method(#refreshChanges, [
accountId, accountId,
@@ -80,15 +83,15 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
as _i3.Stream<_i4.EmailsResponse>); as _i3.Stream<_i4.EmailsResponse>);
@override @override
_i3.Stream<_i4.EmailsResponse> loadMoreEmails( _i3.Stream<_i4.EmailsResponse> loadMoreEmails(
_i12.GetEmailRequest? emailRequest) => _i13.GetEmailRequest? emailRequest) =>
(super.noSuchMethod(Invocation.method(#loadMoreEmails, [emailRequest]), (super.noSuchMethod(Invocation.method(#loadMoreEmails, [emailRequest]),
returnValue: Stream<_i4.EmailsResponse>.empty()) returnValue: Stream<_i4.EmailsResponse>.empty())
as _i3.Stream<_i4.EmailsResponse>); as _i3.Stream<_i4.EmailsResponse>);
@override @override
_i3.Future<List<_i13.Email>> searchEmails(_i5.AccountId? accountId, _i3.Future<List<_i14.Email>> searchEmails(_i5.AccountId? accountId,
{_i6.UnsignedInt? limit, {_i6.UnsignedInt? limit,
Set<_i7.Comparator>? sort, Set<_i7.Comparator>? sort,
_i14.Filter? filter, _i15.Filter? filter,
_i9.Properties? properties}) => _i9.Properties? properties}) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method(#searchEmails, [ Invocation.method(#searchEmails, [
@@ -99,8 +102,8 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
#filter: filter, #filter: filter,
#properties: properties #properties: properties
}), }),
returnValue: Future<List<_i13.Email>>.value(<_i13.Email>[])) returnValue: Future<List<_i14.Email>>.value(<_i14.Email>[]))
as _i3.Future<List<_i13.Email>>); as _i3.Future<List<_i14.Email>>);
@override @override
_i3.Future<bool> emptyTrashFolder( _i3.Future<bool> emptyTrashFolder(
_i5.AccountId? accountId, _i11.MailboxId? trashMailboxId) => _i5.AccountId? accountId, _i11.MailboxId? trashMailboxId) =>
@@ -5,19 +5,22 @@
import 'dart:async' as _i3; import 'dart:async' as _i3;
import 'package:jmap_dart_client/jmap/account_id.dart' as _i5; import 'package:jmap_dart_client/jmap/account_id.dart' as _i5;
import 'package:jmap_dart_client/jmap/core/filter/filter.dart' as _i14; import 'package:jmap_dart_client/jmap/core/filter/filter.dart' as _i15;
import 'package:jmap_dart_client/jmap/core/properties/properties.dart' as _i9; import 'package:jmap_dart_client/jmap/core/properties/properties.dart' as _i9;
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart' as _i7; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart' as _i7;
import 'package:jmap_dart_client/jmap/core/state.dart' as _i10; import 'package:jmap_dart_client/jmap/core/state.dart' as _i10;
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart' as _i6; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart' as _i6;
import 'package:jmap_dart_client/jmap/mail/email/email.dart' as _i13; import 'package:jmap_dart_client/jmap/mail/email/email.dart' as _i14;
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart' as _i11; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart' as _i11;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:model/model.dart' as _i8; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart'
as _i8;
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart' import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'
as _i4; as _i4;
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart' import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'
as _i12; as _i12;
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart'
as _i13;
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart' import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'
as _i2; as _i2;
@@ -64,7 +67,7 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
_i9.Properties? propertiesCreated, _i9.Properties? propertiesCreated,
_i9.Properties? propertiesUpdated, _i9.Properties? propertiesUpdated,
_i11.MailboxId? inMailboxId, _i11.MailboxId? inMailboxId,
_i8.FilterMessageOption? filterOption}) => _i12.FilterMessageOption? filterOption}) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method(#refreshChanges, [ Invocation.method(#refreshChanges, [
accountId, accountId,
@@ -80,15 +83,15 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
as _i3.Stream<_i4.EmailsResponse>); as _i3.Stream<_i4.EmailsResponse>);
@override @override
_i3.Stream<_i4.EmailsResponse> loadMoreEmails( _i3.Stream<_i4.EmailsResponse> loadMoreEmails(
_i12.GetEmailRequest? emailRequest) => _i13.GetEmailRequest? emailRequest) =>
(super.noSuchMethod(Invocation.method(#loadMoreEmails, [emailRequest]), (super.noSuchMethod(Invocation.method(#loadMoreEmails, [emailRequest]),
returnValue: Stream<_i4.EmailsResponse>.empty()) returnValue: Stream<_i4.EmailsResponse>.empty())
as _i3.Stream<_i4.EmailsResponse>); as _i3.Stream<_i4.EmailsResponse>);
@override @override
_i3.Future<List<_i13.Email>> searchEmails(_i5.AccountId? accountId, _i3.Future<List<_i14.Email>> searchEmails(_i5.AccountId? accountId,
{_i6.UnsignedInt? limit, {_i6.UnsignedInt? limit,
Set<_i7.Comparator>? sort, Set<_i7.Comparator>? sort,
_i14.Filter? filter, _i15.Filter? filter,
_i9.Properties? properties}) => _i9.Properties? properties}) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method(#searchEmails, [ Invocation.method(#searchEmails, [
@@ -99,8 +102,8 @@ class MockThreadRepository extends _i1.Mock implements _i2.ThreadRepository {
#filter: filter, #filter: filter,
#properties: properties #properties: properties
}), }),
returnValue: Future<List<_i13.Email>>.value(<_i13.Email>[])) returnValue: Future<List<_i14.Email>>.value(<_i14.Email>[]))
as _i3.Future<List<_i13.Email>>); as _i3.Future<List<_i14.Email>>);
@override @override
_i3.Future<bool> emptyTrashFolder( _i3.Future<bool> emptyTrashFolder(
_i5.AccountId? accountId, _i11.MailboxId? trashMailboxId) => _i5.AccountId? accountId, _i11.MailboxId? trashMailboxId) =>