TF-934 Implement search by query when open new tab

This commit is contained in:
dab246
2022-11-11 00:11:48 +07:00
committed by Dat H. Pham
parent 6050ee5386
commit 71abe0cf37
22 changed files with 224 additions and 120 deletions
@@ -20,6 +20,7 @@ class EmailSupervisorController extends BaseController {
int currentIndexPageView = -1;
final canGetNewerEmail = true.obs;
final canGetOlderEmail = true.obs;
final supportedPageView = RxBool(true);
Rxn<PresentationEmail> get selectedEmail => mailboxDashBoardController.selectedEmail;
Session? get sessionCurrent => mailboxDashBoardController.sessionCurrent;
@@ -33,8 +34,6 @@ class EmailSupervisorController extends BaseController {
}
}
bool get supportedPageView => listEmail.isNotEmpty;
@override
void onClose() {
pageController?.dispose();
@@ -181,10 +181,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
if (presentationEmail is PresentationEmail) {
if (_currentEmailId != presentationEmail.id) {
_currentEmailId = presentationEmail.id;
if (emailSupervisorController.supportedPageView) {
if (emailSupervisorController.listEmail.isNotEmpty) {
emailSupervisorController.supportedPageView.value = true;
emailSupervisorController.setCurrentPositionEmailInListEmail(_currentEmailId);
_getEmailDeBouncer.value = emailSupervisorController.currentIndexPageView;
} else {
emailSupervisorController.supportedPageView.value = false;
_getEmailContentAction(presentationEmail.id);
}
_resetToOriginalValue();
@@ -364,9 +366,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
PresentationMailbox? getMailboxContain(PresentationEmail email) {
return mailboxDashBoardController.searchController.isSearchEmailRunning
if (mailboxDashBoardController.selectedMailbox.value == null) {
return email.findMailboxContain(mailboxDashBoardController.mapMailboxById);
} else {
return mailboxDashBoardController.searchController.isSearchEmailRunning
? email.findMailboxContain(mailboxDashBoardController.mapMailboxById)
: mailboxDashBoardController.selectedMailbox.value;
}
}
void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions) async {
@@ -378,6 +384,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void _markAsEmailReadSuccess(Success success) {
log('SingleEmailController::_markAsEmailReadSuccess(): $success');
mailboxDashBoardController.dispatchState(Right(success));
if (success is MarkAsEmailReadSuccess
@@ -744,7 +751,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void _markAsEmailStarSuccess(Success success) {
if (success is MarkAsStarEmailSuccess) {
mailboxDashBoardController.setSelectedEmail(success.updatedEmail.toPresentationEmail(selectMode: SelectMode.ACTIVE));
final selectedEmail = mailboxDashBoardController.selectedEmail.value;
mailboxDashBoardController.setSelectedEmail(selectedEmail?.updateKeywords(success.updatedEmail.keywords));
}
mailboxDashBoardController.dispatchState(Right(success));
}
@@ -992,7 +1000,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void closeEmailView(BuildContext context) {
log('SingleEmailController::closeEmailView(): ');
if (emailSupervisorController.supportedPageView) {
if (emailSupervisorController.supportedPageView.isTrue) {
emailSupervisorController.presentationEmailsLoaded.removeWhere((e) => e.emailCurrent?.id == currentEmail?.id);
emailSupervisorController.currentIndexPageView = -1;
_getEmailDeBouncer.value = null;
@@ -1015,10 +1023,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
}
bool get isOpenEmailNotMailboxFromRoute => !emailSupervisorController.supportedPageView
bool get isOpenEmailNotMailboxFromRoute => emailSupervisorController.supportedPageView.isFalse
&& mailboxDashBoardController.selectedMailbox.value == null;
void _updateRouteOnBrowser() {
log('SingleEmailController::_updateRouteOnBrowser(): isSearchEmailRunning: ${mailboxDashBoardController.searchController.isSearchEmailRunning}');
if (BuildUtils.isWeb) {
final selectedMailboxId = mailboxDashBoardController.selectedMailbox.value?.id;
final route = RouteUtils.generateRouteBrowser(
@@ -88,9 +88,11 @@ class EmailView extends GetWidget<SingleEmailController> {
_buildAppBar(context, email),
_buildVacationNotificationMessage(context),
const Divider(color: AppColor.colorDividerHorizontal, height: 1),
Expanded(child: controller.emailSupervisorController.supportedPageView
? _buildMultipleEmailView(controller.emailSupervisorController.listEmail)
: _buildSingleEmailView(context, email),
Expanded(child: Obx(() {
return controller.emailSupervisorController.supportedPageView.isTrue
? _buildMultipleEmailView(controller.emailSupervisorController.listEmail)
: _buildSingleEmailView(context, email);
}),
),
const Divider(color: AppColor.colorDividerHorizontal, height: 1),
_buildBottomBar(context, email),
@@ -98,6 +100,7 @@ class EmailView extends GetWidget<SingleEmailController> {
}
Widget _buildMultipleEmailView(List<PresentationEmail> listEmails) {
log('EmailView::_buildMultipleEmailView(): ');
return PageView.builder(
physics: BuildUtils.isWeb ? const NeverScrollableScrollPhysics() : null,
itemCount: listEmails.length,
@@ -108,6 +111,7 @@ class EmailView extends GetWidget<SingleEmailController> {
}
Widget _buildSingleEmailView(BuildContext context, PresentationEmail email) {
log('EmailView::_buildSingleEmailView(): ');
return _buildEmailBody(context, email);
}
@@ -144,7 +148,7 @@ class EmailView extends GetWidget<SingleEmailController> {
Widget _buildAppBar(BuildContext context, PresentationEmail presentationEmail) {
return Obx(() => AppBarMailWidgetBuilder(
presentationEmail,
currentMailbox: controller.mailboxDashBoardController.selectedMailbox.value,
mailboxContain: _getMailboxContain(presentationEmail),
isSearchIsRunning: controller.mailboxDashBoardController.searchController.isSearchEmailRunning,
onBackActionClick: () => controller.closeEmailView(context),
onEmailActionClick: (email, action) =>
@@ -161,12 +165,16 @@ class EmailView extends GetWidget<SingleEmailController> {
_popupMenuEmailActionTile(context, email));
}
},
optionsWidget: BuildUtils.isWeb && controller.emailSupervisorController.supportedPageView
optionsWidget: BuildUtils.isWeb && controller.emailSupervisorController.supportedPageView.isTrue
? _buildNavigatorPageViewWidgets(context)
: null,
));
}
PresentationMailbox? _getMailboxContain(PresentationEmail currentEmail) {
return currentEmail.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById);
}
List<Widget> _buildNavigatorPageViewWidgets(BuildContext context) {
return [
buildIconWeb(
@@ -16,7 +16,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget {
final PresentationEmail _presentationEmail;
final List<Widget>? optionsWidget;
final PresentationMailbox? currentMailbox;
final PresentationMailbox? mailboxContain;
final bool isSearchIsRunning;
final OnBackActionClick? onBackActionClick;
final OnEmailActionClick? onEmailActionClick;
@@ -26,7 +26,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget {
this._presentationEmail,
{
Key? key,
this.currentMailbox,
this.mailboxContain,
this.onBackActionClick,
this.onEmailActionClick,
this.onMoreActionClick,
@@ -70,7 +70,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget {
constraints: BoxConstraints(
maxWidth: _responsiveUtils.getSizeScreenWidth(context) - 250),
child: Text(
currentMailbox?.name?.name.capitalizeFirstEach ?? '',
mailboxContain?.name?.name.capitalizeFirstEach ?? '',
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
@@ -134,17 +134,17 @@ class AppBarMailWidgetBuilder extends StatelessWidget {
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icDeleteComposer,
color: currentMailbox?.role != PresentationMailbox.roleTrash
color: mailboxContain?.isTrash == false
? AppColor.colorTextButton
: AppColor.colorDeletePermanentlyButton,
width: BuildUtils.isWeb ? 18 : 20,
height: BuildUtils.isWeb ? 18 : 20,
fit: BoxFit.fill),
tooltip: currentMailbox?.role != PresentationMailbox.roleTrash
tooltip: mailboxContain?.isTrash == false
? AppLocalizations.of(context).move_to_trash
: AppLocalizations.of(context).delete_permanently,
onTap: () {
if (currentMailbox?.role != PresentationMailbox.roleTrash) {
if (mailboxContain?.isTrash == false) {
onEmailActionClick?.call(
_presentationEmail,
EmailActionType.moveToTrash);
@@ -194,7 +194,7 @@ class LoginController extends ReloadableController {
@override
void handleReloaded(Session session) {
pushAndPop(
RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()),
RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()),
arguments: session);
}
@@ -177,8 +177,10 @@ class MailboxController extends BaseMailboxController {
}
},
(success) async {
if (success is GetAllMailboxSuccess || success is RefreshChangesAllMailboxSuccess) {
if (success is GetAllMailboxSuccess) {
_initialMailboxVariableStorage();
} else if (success is RefreshChangesAllMailboxSuccess) {
_initialMailboxVariableStorage(isRefreshChange: true);
} else if (success is CreateNewMailboxSuccess) {
_createNewMailboxSuccess(success);
} else if (success is SearchMailboxSuccess) {
@@ -315,10 +317,10 @@ class MailboxController extends BaseMailboxController {
}
}
void _initialMailboxVariableStorage() {
void _initialMailboxVariableStorage({bool isRefreshChange = false}) {
_setMapMailbox();
_setOutboxMailbox();
_selectMailboxDefault();
_selectMailboxDefault(isRefreshChange: isRefreshChange);
}
void _setMapMailbox() {
@@ -352,7 +354,7 @@ class MailboxController extends BaseMailboxController {
}
}
void _selectMailboxDefault() {
void _selectMailboxDefault({bool isRefreshChange = false}) {
final mapDefaultMailbox = {
for (var mailboxNode in defaultMailboxTree.value.root.childrenItems ?? List<MailboxNode>.empty())
mailboxNode.item.role!: mailboxNode.item
@@ -385,24 +387,29 @@ class MailboxController extends BaseMailboxController {
}
}
if (isHasDataFromRoute) {
if (mailboxIdFromNavigationRouter != null) {
_selectMailboxFromRouter();
} else if (emailIdFromNavigationRouter != null) {
mailboxDashBoardController.dispatchAction(
SelectEmailByIdAction(
emailIdFromNavigationRouter!,
mailboxIdFromNavigationRouter,
navigationRouter!.dashboardType
)
);
if (isRefreshChange) {
mailboxDashBoardController.setSelectedMailbox(mailboxSelected);
} else {
if (isHasDataFromRoute) {
log('MailboxController::_selectMailboxDefault(): isHasDataFromRoute is true:navigationRouter: $navigationRouter');
if (mailboxIdFromNavigationRouter != null) {
_selectMailboxFromRouter();
} else if (emailIdFromNavigationRouter != null) {
mailboxDashBoardController.dispatchAction(SelectEmailByIdAction(navigationRouter!));
_clearNavigationRouter();
} else if (searchQueryFromNavigationRouter != null) {
mailboxDashBoardController.dispatchAction(SearchEmailByQueryAction(navigationRouter!));
_clearNavigationRouter();
} else {
_clearNavigationRouter();
mailboxDashBoardController.setSelectedMailbox(mailboxSelected);
_updateSelectedMailboxRouteOnBrowser();
}
} else {
log('MailboxController::_selectMailboxDefault(): isHasDataFromRoute is false');
mailboxDashBoardController.setSelectedMailbox(mailboxSelected);
_updateSelectedMailboxRouteOnBrowser();
}
} else {
mailboxDashBoardController.setSelectedMailbox(mailboxSelected);
_updateSelectedMailboxRouteOnBrowser();
}
}
@@ -414,6 +421,8 @@ class MailboxController extends BaseMailboxController {
EmailId? get emailIdFromNavigationRouter => navigationRouter?.emailId;
SearchQuery? get searchQueryFromNavigationRouter => navigationRouter?.searchQuery;
void _clearNavigationRouter() {
mailboxDashBoardController.navigationRouter = null;
}
@@ -423,13 +432,7 @@ class MailboxController extends BaseMailboxController {
if (matchedMailboxNode != null) {
mailboxDashBoardController.setSelectedMailbox(matchedMailboxNode.item);
if (emailIdFromNavigationRouter != null) {
mailboxDashBoardController.dispatchAction(
SelectEmailByIdAction(
emailIdFromNavigationRouter!,
mailboxIdFromNavigationRouter,
navigationRouter!.dashboardType
)
);
mailboxDashBoardController.dispatchAction(SelectEmailByIdAction(navigationRouter!));
} else {
_updateSelectedMailboxRouteOnBrowser();
}
@@ -443,6 +446,7 @@ class MailboxController extends BaseMailboxController {
BuildContext context,
PresentationMailbox presentationMailboxSelected
) {
log('MailboxController::_handleOpenMailbox(): ');
FocusScope.of(context).unfocus();
mailboxDashBoardController.clearSelectedEmail();
@@ -584,6 +588,7 @@ class MailboxController extends BaseMailboxController {
}
void _searchMailboxAction(List<PresentationMailbox> allMailboxes, SearchQuery searchQuery) {
log('MailboxController::_searchMailboxAction():');
if (searchQuery.value.isNotEmpty) {
consumeState(_searchMailboxInteractor.execute(allMailboxes, searchQuery));
} else {
@@ -1112,7 +1117,12 @@ class MailboxController extends BaseMailboxController {
AppRoutes.dashboard,
NavigationRouter(
mailboxId: selectedMailboxId,
dashboardType: DashboardType.normal
searchQuery: mailboxDashBoardController.searchController.isSearchEmailRunning
? mailboxDashBoardController.searchController.searchQuery
: null,
dashboardType: mailboxDashBoardController.searchController.isSearchEmailRunning
? DashboardType.search
: DashboardType.normal
)
);
RouteUtils.updateRouteOnBrowser('Mailbox-${selectedMailboxId?.id.value}', route);
@@ -1,7 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
@@ -116,12 +114,20 @@ class SelectMailboxDefaultAction extends DashBoardAction {
class SelectEmailByIdAction extends DashBoardAction {
final EmailId emailId;
final MailboxId? mailboxId;
final DashboardType dashboardType;
final NavigationRouter navigationRouter;
SelectEmailByIdAction(this.emailId, this.mailboxId, this.dashboardType);
SelectEmailByIdAction(this.navigationRouter);
@override
List<Object?> get props => [emailId, mailboxId, dashboardType];
List<Object?> get props => [navigationRouter];
}
class SearchEmailByQueryAction extends DashBoardAction {
final NavigationRouter navigationRouter;
SearchEmailByQueryAction(this.navigationRouter);
@override
List<Object?> get props => [navigationRouter];
}
@@ -391,6 +391,7 @@ class MailboxDashBoardController extends ReloadableController {
}
void setSelectedEmail(PresentationEmail? newPresentationEmail) {
log('MailboxDashBoardController::setSelectedEmail(): $newPresentationEmail');
selectedEmail.value = newPresentationEmail;
}
@@ -440,6 +441,7 @@ class MailboxDashBoardController extends ReloadableController {
}
void _closeEmailDetailedView() {
log('MailboxDashBoardController::_closeEmailDetailedView(): ');
dispatchRoute(DashboardRoutes.thread);
clearSelectedEmail();
}
@@ -1012,6 +1014,7 @@ class MailboxDashBoardController extends ReloadableController {
}
void dispatchRoute(DashboardRoutes route) {
log('MailboxDashBoardController::dispatchRoute(): $route');
dashboardRoute.value = route;
if (dashboardRoute.value == DashboardRoutes.searchEmail) {
@@ -40,6 +40,7 @@ class SearchController extends BaseController {
final emailReceiveTimeType = Rxn<EmailReceiveTimeType>();
final simpleSearchIsActivated = RxBool(false);
final advancedSearchIsActivated = RxBool(false);
final autoFocus = RxBool(true);
SearchQuery? get searchQuery => searchEmailFilter.value.text;
@@ -55,7 +55,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin {
suggestionsBoxVerticalOffset: 0.0,
textFieldConfiguration: QuickSearchTextFieldConfiguration(
controller: controller.searchInputController,
autofocus: true,
autofocus: controller.autoFocus.value,
enabled: controller.isAdvancedSearchViewOpen.isFalse,
focusNode: controller.searchFocus,
textInputAction: TextInputAction.done,
@@ -227,7 +227,7 @@ class ManageAccountDashBoardController extends ReloadableController {
} else {
log('ManageAccountDashBoardController::backToMailboxDashBoard(): canBack: FALSE');
pushAndPopAll(
RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()),
RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()),
arguments: sessionCurrent);
}
}
@@ -584,6 +584,7 @@ class SearchEmailController extends BaseController
}
void closeSearchView(BuildContext context) {
log('SearchEmailController::closeSearchView(): ');
clearAllTextInputSearchForm();
clearAllResultSearch();
FocusScope.of(context).unfocus();
@@ -623,17 +624,17 @@ class SearchEmailController extends BaseController
markAsStarEmail(selectedEmail, MarkStarAction.unMarkStar);
break;
case EmailActionType.moveToMailbox:
moveToMailbox(context, selectedEmail);
moveToMailbox(context, selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.moveToTrash:
moveToTrash(selectedEmail);
moveToTrash(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.deletePermanently:
deleteEmailPermanently(context, selectedEmail);
break;
case EmailActionType.moveToSpam:
popBack();
moveToSpam(selectedEmail);
moveToSpam(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.unSpam:
popBack();
@@ -735,6 +736,7 @@ class SearchEmailController extends BaseController
AppRoutes.dashboard,
NavigationRouter(
emailId: currentEmail.id,
searchQuery: searchQuery,
dashboardType: DashboardType.search
)
);
@@ -58,7 +58,7 @@ class SessionController extends ReloadableController {
@override
void handleReloaded(Session session) {
pushAndPop(
RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()),
RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()),
arguments: session);
}
@@ -108,7 +108,7 @@ class SessionController extends ReloadableController {
if (apiUrl.isNotEmpty) {
_dynamicUrlInterceptors.changeBaseUrl(apiUrl);
pushAndPop(
RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()),
RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()),
arguments: success.session);
} else {
_goToLogin();
@@ -1,20 +1,16 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
class GetEmailByIdLoading extends LoadingState {}
class GetEmailByIdSuccess extends UIState {
final PresentationEmail email;
final MailboxId? mailboxId;
final DashboardType dashboardType;
GetEmailByIdSuccess(this.email, this.mailboxId, this.dashboardType);
GetEmailByIdSuccess(this.email);
@override
List<Object?> get props => [email, mailboxId, dashboardType];
List<Object?> get props => [email];
}
class GetEmailByIdFailure extends FeatureFailure {
@@ -4,10 +4,8 @@ import 'package:dartz/dartz.dart';
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/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart';
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
class GetEmailByIdInteractor {
final ThreadRepository _threadRepository;
@@ -18,15 +16,13 @@ class GetEmailByIdInteractor {
AccountId accountId,
EmailId emailId,
{
MailboxId? mailboxId,
DashboardType dashboardType = DashboardType.normal,
Properties? properties,
}
) async* {
try {
yield Right<Failure, Success>(GetEmailByIdLoading());
final email = await _threadRepository.getEmailById(accountId, emailId, properties: properties);
yield Right<Failure, Success>(GetEmailByIdSuccess(email, mailboxId, dashboardType));
yield Right<Failure, Success>(GetEmailByIdSuccess(email));
} catch (e) {
yield Left<Failure, Success>(GetEmailByIdFailure(e));
}
@@ -4,6 +4,7 @@ import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart';
import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/build_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -46,6 +47,7 @@ mixin EmailActionController on ViewAsDialogActionMixin {
}
void previewEmail(BuildContext context, PresentationEmail presentationEmail) {
log('EmailActionController::previewEmail():presentationEmailId: ${presentationEmail.id}');
mailboxDashBoardController.setSelectedEmail(presentationEmail);
mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed);
if (BuildUtils.isWeb && presentationEmail.routeWeb != null) {
@@ -55,14 +57,13 @@ mixin EmailActionController on ViewAsDialogActionMixin {
}
}
void moveToTrash(PresentationEmail email) async {
final currentMailbox = mailboxDashBoardController.selectedMailbox.value;
void moveToTrash(PresentationEmail email, {PresentationMailbox? mailboxContain}) async {
final accountId = mailboxDashBoardController.accountId.value;
final trashMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleTrash];
if (currentMailbox != null && accountId != null && trashMailboxId != null) {
if (mailboxContain != null && accountId != null && trashMailboxId != null) {
_moveToTrashAction(accountId, MoveToMailboxRequest(
{currentMailbox.id: [email.id]},
{mailboxContain.id: [email.id]},
trashMailboxId,
MoveAction.moving,
mailboxDashBoardController.sessionCurrent!,
@@ -75,14 +76,13 @@ mixin EmailActionController on ViewAsDialogActionMixin {
mailboxDashBoardController.moveToMailbox(accountId, moveRequest);
}
void moveToSpam(PresentationEmail email) async {
final currentMailbox = mailboxDashBoardController.selectedMailbox.value;
void moveToSpam(PresentationEmail email, {PresentationMailbox? mailboxContain}) async {
final accountId = mailboxDashBoardController.accountId.value;
final spamMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleSpam);
if (currentMailbox != null && accountId != null && spamMailboxId != null) {
if (mailboxContain != null && accountId != null && spamMailboxId != null) {
moveToSpamAction(accountId, MoveToMailboxRequest(
{currentMailbox.id: [email.id]},
{mailboxContain.id: [email.id]},
spamMailboxId,
MoveAction.moving,
mailboxDashBoardController.sessionCurrent!,
@@ -111,11 +111,14 @@ mixin EmailActionController on ViewAsDialogActionMixin {
mailboxDashBoardController.moveToMailbox(accountId, moveRequest);
}
void moveToMailbox(BuildContext context, PresentationEmail email) async {
final currentMailbox = mailboxDashBoardController.selectedMailbox.value;
void moveToMailbox(
BuildContext context,
PresentationEmail email,
{PresentationMailbox? mailboxContain}
) async {
final accountId = mailboxDashBoardController.accountId.value;
if (currentMailbox != null && accountId != null) {
if (mailboxContain != null && accountId != null) {
final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail);
if (BuildUtils.isWeb) {
@@ -129,7 +132,7 @@ mixin EmailActionController on ViewAsDialogActionMixin {
accountId,
mailboxDashBoardController.sessionCurrent!,
email,
currentMailbox,
mailboxContain,
destinationMailbox);
}
});
@@ -146,7 +149,7 @@ mixin EmailActionController on ViewAsDialogActionMixin {
accountId,
mailboxDashBoardController.sessionCurrent!,
email,
currentMailbox,
mailboxContain,
destinationMailbox);
}
}
@@ -90,9 +90,9 @@ class ThreadController extends BaseController with EmailActionController {
bool canLoadMore = true;
bool canSearchMore = true;
bool _isLoadingMore = false;
get isLoadingMore => _isLoadingMore;
MailboxId? _currentMailboxId;
jmap.State? _currentEmailState;
NavigationRouter? _navigationRouter;
final ScrollController listEmailController = ScrollController();
final FocusNode focusNodeKeyBoard = FocusNode();
final latestEmailSelectedOrUnselected = Rxn<PresentationEmail>();
@@ -102,6 +102,8 @@ class ThreadController extends BaseController with EmailActionController {
..add(EmailComparator(EmailComparatorProperty.receivedAt)
..setIsAscending(false));
bool get isLoadingMore => _isLoadingMore;
AccountId? get _accountId => mailboxDashBoardController.accountId.value;
PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value;
@@ -157,6 +159,7 @@ class ThreadController extends BaseController with EmailActionController {
_isLoadingMore = false;
} else if (failure is GetEmailByIdFailure) {
openingEmail.value = false;
_navigationRouter = null;
}
},
(success) {
@@ -176,7 +179,7 @@ class ThreadController extends BaseController with EmailActionController {
openingEmail.value = true;
} else if (success is GetEmailByIdSuccess) {
openingEmail.value = false;
_openEmailDetailView(success.email, success.mailboxId, success.dashboardType);
_openEmailDetailView(success.email);
}
}
);
@@ -246,13 +249,22 @@ class ThreadController extends BaseController with EmailActionController {
mailboxDashBoardController.clearDashBoardAction();
} else if (action is StartSearchEmailAction) {
cancelSelectEmail();
_updateSearchRouteOnBrowser();
_searchEmail();
mailboxDashBoardController.clearDashBoardAction();
} else if (action is EmptyTrashAction) {
deleteSelectionEmailsPermanently(action.context, DeleteActionType.all);
mailboxDashBoardController.clearDashBoardAction();
} else if (action is SelectEmailByIdAction) {
_getEmailByIdAction(action.emailId, action.mailboxId, action.dashboardType);
_navigationRouter = action.navigationRouter;
if (_navigationRouter!.searchQuery != null) {
_activateSearchFromRouter();
}
_getEmailByIdAction(_navigationRouter!.emailId!);
mailboxDashBoardController.clearDashBoardAction();
} else if (action is SearchEmailByQueryAction) {
_navigationRouter = action.navigationRouter;
_activateSearchFromRouter();
mailboxDashBoardController.clearDashBoardAction();
}
});
@@ -312,6 +324,18 @@ class ThreadController extends BaseController with EmailActionController {
viewStateWorker.dispose();
}
void _activateSearchFromRouter() {
searchController.autoFocus.value = false;
searchController.enableSearch();
searchController.updateTextSearch(_navigationRouter!.searchQuery!.value);
searchController.updateFilterEmail(text: _navigationRouter!.searchQuery!);
if (currentContext != null) {
FocusScope.of(currentContext!).unfocus();
}
searchController.searchFocus.unfocus();
_searchEmail();
}
void _handleErrorGetAllOrRefreshChangesEmail(dynamic error) async {
logError('ThreadController::_handleErrorGetAllOrRefreshChangesEmail():Error: $error');
if (error is CannotCalculateChangesMethodResponseException) {
@@ -334,7 +358,6 @@ class ThreadController extends BaseController with EmailActionController {
canLoadMore = true;
_isLoadingMore = false;
cancelSelectEmail();
mailboxDashBoardController.dispatchRoute(DashboardRoutes.thread);
}
void _getAllEmailSuccess(GetAllEmailSuccess success) {
@@ -613,6 +636,18 @@ class ThreadController extends BaseController with EmailActionController {
}
}
void _updateSearchRouteOnBrowser() {
if (BuildUtils.isWeb) {
final route = RouteUtils.generateRouteBrowser(
AppRoutes.dashboard,
NavigationRouter(
searchQuery: searchQuery,
dashboardType: DashboardType.search)
);
RouteUtils.updateRouteOnBrowser('SearchEmail', route);
}
}
void _searchEmailsSuccess(SearchEmailSuccess success) {
final resultEmailSearchList = success.emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
@@ -622,6 +657,7 @@ class ThreadController extends BaseController with EmailActionController {
final emailsSearchAfterChanges = resultEmailSearchList;
final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges);
emailList.value = newListEmailSearch;
searchController.autoFocus.value = true;
}
void searchMoreEmails() {
@@ -750,17 +786,17 @@ class ThreadController extends BaseController with EmailActionController {
markAsStarEmail(selectedEmail, MarkStarAction.unMarkStar);
break;
case EmailActionType.moveToMailbox:
moveToMailbox(context, selectedEmail);
moveToMailbox(context, selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.moveToTrash:
moveToTrash(selectedEmail);
moveToTrash(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.deletePermanently:
deleteEmailPermanently(context, selectedEmail);
break;
case EmailActionType.moveToSpam:
popBack();
moveToSpam(selectedEmail);
moveToSpam(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.unSpam:
popBack();
@@ -815,6 +851,9 @@ class ThreadController extends BaseController with EmailActionController {
NavigationRouter(
emailId: currentEmail.id,
mailboxId: currentMailbox?.id,
searchQuery: searchController.isSearchEmailRunning
? searchQuery
: null,
dashboardType: searchController.isSearchEmailRunning
? DashboardType.search
: DashboardType.normal
@@ -827,30 +866,29 @@ class ThreadController extends BaseController with EmailActionController {
}
}
void _getEmailByIdAction(EmailId emailId, MailboxId? mailboxId, DashboardType dashboardType) {
PresentationMailbox? getMailboxContain(PresentationEmail currentEmail) {
return currentEmail.findMailboxContain(mailboxDashBoardController.mapMailboxById);
}
void _getEmailByIdAction(EmailId emailId) {
if (_accountId != null) {
consumeState(_getEmailByIdInteractor.execute(
_accountId!,
emailId,
mailboxId: mailboxId,
dashboardType: dashboardType,
properties: ThreadConstants.propertiesDefault));
}
}
void _openEmailDetailView(
PresentationEmail email,
MailboxId? mailboxId,
DashboardType dashboardType
) {
void _openEmailDetailView(PresentationEmail email) {
if (currentContext != null) {
final mailboxContain = email.findMailboxContain(mailboxDashBoardController.mapMailboxById);
final route = RouteUtils.generateRouteBrowser(
AppRoutes.dashboard,
NavigationRouter(
emailId: email.id,
mailboxId: mailboxId,
dashboardType: dashboardType
mailboxId: _navigationRouter?.mailboxId,
searchQuery: _navigationRouter?.searchQuery,
dashboardType: _navigationRouter?.dashboardType ?? DashboardType.normal
)
);
pressEmailAction(
@@ -860,5 +898,6 @@ class ThreadController extends BaseController with EmailActionController {
mailboxContain: mailboxContain
);
}
_navigationRouter = null;
}
}
@@ -335,7 +335,7 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
itemExtent: _getItemExtent(context),
itemCount: listPresentationEmail.length,
itemBuilder: (context, index) {
final mailboxContain = _getMailboxContain(listPresentationEmail[index]);
final mailboxContain = controller.getMailboxContain(listPresentationEmail[index]);
final newPresentationEmail = controller.generateEmailByPlatform(listPresentationEmail[index]);
return Obx(() => Draggable<List<PresentationEmail>>(
maxSimultaneousDrags: kIsWeb ? null : 0,
@@ -375,12 +375,6 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
);
}
PresentationMailbox? _getMailboxContain(PresentationEmail currentEmail) {
return controller.searchController.isSearchEmailRunning
? currentEmail.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById)
: controller.currentMailbox;
}
Widget _buildFeedBackWidget(BuildContext context) {
return SizedBox(
height: 60,
@@ -508,7 +502,7 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
}
Widget _markAsEmailSpamOrUnSpamAction(BuildContext context, PresentationEmail email) {
final mailboxContain = _getMailboxContain(email);
final mailboxContain = controller.getMailboxContain(email);
return (EmailActionCupertinoActionSheetActionBuilder(
const Key('mark_as_spam_or_un_spam_action'),
SvgPicture.asset(
@@ -421,7 +421,7 @@ class EmailTileBuilder with BaseEmailItemTile {
: EmailActionType.markAsRead,
_presentationEmail)),
const SizedBox(width: 5),
if (mailboxContain?.isDrafts == false)
if (mailboxContain != null && mailboxContain?.isDrafts == false)
... [
buildIconWeb(
minSize: 18,
+4 -1
View File
@@ -2,6 +2,7 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
enum DashboardType {
normal,
@@ -12,13 +13,15 @@ class NavigationRouter with EquatableMixin {
final EmailId? emailId;
final MailboxId? mailboxId;
final DashboardType dashboardType;
final SearchQuery? searchQuery;
NavigationRouter({
this.emailId,
this.mailboxId,
this.searchQuery,
this.dashboardType = DashboardType.normal
});
@override
List<Object?> get props => [emailId, mailboxId, dashboardType];
List<Object?> get props => [emailId, mailboxId, searchQuery, dashboardType];
}
+22 -10
View File
@@ -1,4 +1,5 @@
import 'package:core/core.dart';
import 'package:core/data/model/query/query_parameter.dart';
import 'package:core/data/network/config/service_path.dart';
import 'package:core/utils/app_logger.dart';
@@ -6,6 +7,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
import 'package:universal_html/html.dart' as html;
@@ -15,18 +17,23 @@ abstract class RouteUtils {
static String get baseUrl => Uri.base.path;
static String generateRouteMobile(String route, NavigationRouter router) {
static String generateNavigationRoute(String route, NavigationRouter router) {
ServicePath servicePath = ServicePath(route);
if (router.emailId != null) {
servicePath = servicePath.withPathParameter(router.emailId!.id.value);
if (BuildUtils.isWeb) {
if (router.emailId != null) {
servicePath = servicePath.withPathParameter(router.emailId!.id.value);
}
servicePath = servicePath.withQueryParameters([
StringQueryParameter('type', router.dashboardType.name),
if (router.mailboxId != null)
StringQueryParameter('context', router.mailboxId!.id.value),
if (router.searchQuery != null)
StringQueryParameter('q', router.searchQuery!.value),
]);
return servicePath.path;
} else {
return servicePath.path;
}
servicePath = servicePath.withQueryParameters([
StringQueryParameter('type', router.dashboardType.name),
if (router.mailboxId != null)
StringQueryParameter('context', router.mailboxId!.id.value),
]);
return servicePath.path;
}
static Uri generateRouteBrowser(String route, NavigationRouter router) {
@@ -39,6 +46,8 @@ abstract class RouteUtils {
StringQueryParameter('type', router.dashboardType.name),
if (router.mailboxId != null)
StringQueryParameter('context', router.mailboxId!.id.value),
if (router.searchQuery != null)
StringQueryParameter('q', router.searchQuery!.value),
]);
return Uri.parse(servicePath.path);
@@ -48,9 +57,11 @@ abstract class RouteUtils {
final idParam = parameters['id'];
final typeParam = parameters['type'];
final contextPram = parameters['context'];
final queryParam = parameters['q'];
final emailId = idParam != null ? EmailId(Id(idParam)) : null;
final mailboxId = contextPram != null ? MailboxId(Id(contextPram)) : null;
final searchQuery = queryParam != null ? SearchQuery(queryParam) : null;
final dashboardType = typeParam == DashboardType.search.name
? DashboardType.search
: DashboardType.normal;
@@ -58,6 +69,7 @@ abstract class RouteUtils {
return NavigationRouter(
emailId: emailId,
mailboxId: mailboxId,
searchQuery: searchQuery,
dashboardType: dashboardType,
);
}
@@ -5,6 +5,7 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
@@ -192,4 +193,26 @@ extension PresentationEmailExtension on PresentationEmail {
routeWeb: routeWeb
);
}
PresentationEmail updateKeywords(Map<KeyWordIdentifier, bool>? newKeywords) {
return PresentationEmail(
this.id,
keywords: newKeywords,
size: size,
receivedAt: receivedAt,
hasAttachment: hasAttachment,
preview: preview,
subject: subject,
sentAt: sentAt,
from: from,
to: to,
cc: cc,
bcc: bcc,
replyTo: replyTo,
mailboxIds: mailboxIds,
mailboxNames: mailboxNames,
selectMode: selectMode,
routeWeb: routeWeb
);
}
}