TF-35 Implement search mailbox
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
|
||||
class SearchMailboxSuccess extends UIState {
|
||||
|
||||
final List<PresentationMailbox> mailboxesSearched;
|
||||
|
||||
SearchMailboxSuccess(this.mailboxesSearched);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [mailboxesSearched];
|
||||
}
|
||||
|
||||
class SearchMailboxFailure extends FeatureFailure {
|
||||
final exception;
|
||||
|
||||
SearchMailboxFailure(this.exception);
|
||||
|
||||
@override
|
||||
List<Object> get props => [exception];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/search_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
|
||||
class SearchMailboxInteractor {
|
||||
|
||||
Stream<Either<Failure, Success>> execute(List<PresentationMailbox> mailboxes, SearchQuery searchQuery) async* {
|
||||
try {
|
||||
final resultList = mailboxes
|
||||
.where((mailbox) => mailbox.name?.name.toLowerCase().contains(searchQuery.value.toLowerCase()) == true)
|
||||
.toList();
|
||||
|
||||
yield Right<Failure, Success>(SearchMailboxSuccess(resultList));
|
||||
} catch (exception) {
|
||||
yield Left<Failure, Success>(SearchMailboxFailure(exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_reposit
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
@@ -46,6 +47,7 @@ class MailboxBindings extends Bindings {
|
||||
Get.lazyPut(() => RefreshAllMailboxInteractor(Get.find<MailboxRepository>()));
|
||||
Get.lazyPut(() => TreeBuilder());
|
||||
Get.lazyPut(() => CreateNewMailboxInteractor(Get.find<MailboxRepository>()));
|
||||
Get.lazyPut(() => SearchMailboxInteractor());
|
||||
Get.lazyPut(() => Uuid());
|
||||
Get.lazyPut(() => TextEditingController());
|
||||
Get.lazyPut(() => FocusNode());
|
||||
@@ -54,13 +56,12 @@ class MailboxBindings extends Bindings {
|
||||
Get.find<DeleteCredentialInteractor>(),
|
||||
Get.find<RefreshAllMailboxInteractor>(),
|
||||
Get.find<CreateNewMailboxInteractor>(),
|
||||
Get.find<SearchMailboxInteractor>(),
|
||||
Get.find<TreeBuilder>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<AppToast>(),
|
||||
Get.find<ImagePaths>(),
|
||||
Get.find<ResponsiveUtils>(),
|
||||
Get.find<TextEditingController>(),
|
||||
Get.find<FocusNode>(),
|
||||
Get.find<CachingManager>()));
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,13 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_i
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/create_new_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/search_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart';
|
||||
@@ -45,22 +48,24 @@ class MailboxController extends BaseController {
|
||||
final DeleteCredentialInteractor _deleteCredentialInteractor;
|
||||
final RefreshAllMailboxInteractor _refreshAllMailboxInteractor;
|
||||
final CreateNewMailboxInteractor _createNewMailboxInteractor;
|
||||
final SearchMailboxInteractor _searchMailboxInteractor;
|
||||
final TreeBuilder _treeBuilder;
|
||||
final Uuid _uuid;
|
||||
final AppToast _appToast;
|
||||
final ImagePaths _imagePaths;
|
||||
final ResponsiveUtils responsiveUtils;
|
||||
final TextEditingController searchInputController;
|
||||
final FocusNode searchFocus;
|
||||
final CachingManager _cachingManager;
|
||||
|
||||
final defaultMailboxList = <PresentationMailbox>[].obs;
|
||||
final folderMailboxNodeList = <MailboxNode>[].obs;
|
||||
final listMailboxSearched = <PresentationMailbox>[].obs;
|
||||
final searchState = SearchState.initial().obs;
|
||||
final searchQuery = SearchQuery.initial().obs;
|
||||
|
||||
MailboxTree folderMailboxTree = MailboxTree(MailboxNode.root());
|
||||
List<PresentationMailbox> allMailboxes = <PresentationMailbox>[];
|
||||
List<PresentationMailbox> listMailboxSearched = <PresentationMailbox>[];
|
||||
TextEditingController searchInputController = TextEditingController();
|
||||
FocusNode searchFocus = FocusNode();
|
||||
|
||||
jmapState.State? currentMailboxState;
|
||||
|
||||
@@ -69,13 +74,12 @@ class MailboxController extends BaseController {
|
||||
this._deleteCredentialInteractor,
|
||||
this._refreshAllMailboxInteractor,
|
||||
this._createNewMailboxInteractor,
|
||||
this._searchMailboxInteractor,
|
||||
this._treeBuilder,
|
||||
this._uuid,
|
||||
this._appToast,
|
||||
this._imagePaths,
|
||||
this.responsiveUtils,
|
||||
this.searchInputController,
|
||||
this.searchFocus,
|
||||
this._cachingManager,
|
||||
);
|
||||
|
||||
@@ -111,6 +115,7 @@ class MailboxController extends BaseController {
|
||||
@override
|
||||
void onClose() {
|
||||
mailboxDashBoardController.accountId.close();
|
||||
searchInputController.dispose();
|
||||
searchFocus.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
@@ -135,11 +140,15 @@ class MailboxController extends BaseController {
|
||||
(failure) {
|
||||
if (failure is CreateNewMailboxFailure) {
|
||||
_createNewMailboxFailure(failure);
|
||||
} else if (failure is SearchMailboxFailure) {
|
||||
_searchMailboxFailure(failure);
|
||||
}
|
||||
},
|
||||
(success) {
|
||||
if (success is CreateNewMailboxSuccess) {
|
||||
_createNewMailboxSuccess(success);
|
||||
} else if (success is SearchMailboxSuccess) {
|
||||
_searchMailboxSuccess(success);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -158,6 +167,8 @@ class MailboxController extends BaseController {
|
||||
if (accountId != null) {
|
||||
consumeState(_getAllMailboxInteractor.execute(accountId));
|
||||
}
|
||||
} else {
|
||||
_searchMailboxAction(allMailboxes, searchQuery.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +180,8 @@ class MailboxController extends BaseController {
|
||||
}
|
||||
|
||||
void _buildTree(List<PresentationMailbox> folderMailboxList) async {
|
||||
final _folderMailboxTree = await _treeBuilder.generateMailboxTree(folderMailboxList);
|
||||
folderMailboxNodeList.value = _folderMailboxTree.root.childrenItems ?? [];
|
||||
folderMailboxTree = await _treeBuilder.generateMailboxTree(folderMailboxList);
|
||||
folderMailboxNodeList.value = folderMailboxTree.root.childrenItems ?? [];
|
||||
}
|
||||
|
||||
void toggleMailboxFolder(MailboxNode mailboxNode) {
|
||||
@@ -240,6 +251,8 @@ class MailboxController extends BaseController {
|
||||
BuildContext context,
|
||||
PresentationMailbox presentationMailboxSelected
|
||||
) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
mailboxDashBoardController.setSelectedMailbox(presentationMailboxSelected);
|
||||
mailboxDashBoardController.clearSelectedEmail();
|
||||
|
||||
@@ -315,10 +328,48 @@ class MailboxController extends BaseController {
|
||||
void clearSearchText() {
|
||||
searchQuery.value = SearchQuery.initial();
|
||||
searchFocus.requestFocus();
|
||||
listMailboxSearched.clear();
|
||||
}
|
||||
|
||||
void searchMailbox(String value) {
|
||||
searchQuery.value = SearchQuery(value);
|
||||
_searchMailboxAction(allMailboxes, searchQuery.value);
|
||||
}
|
||||
|
||||
void _searchMailboxAction(List<PresentationMailbox> allMailboxes, SearchQuery searchQuery) {
|
||||
if (searchQuery.value.isNotEmpty) {
|
||||
consumeState(_searchMailboxInteractor.execute(allMailboxes, searchQuery));
|
||||
} else {
|
||||
listMailboxSearched.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void _searchMailboxSuccess(SearchMailboxSuccess success) {
|
||||
final mailboxesSearchedWithPath = _findMailboxPath(success.mailboxesSearched);
|
||||
listMailboxSearched.value = mailboxesSearchedWithPath;
|
||||
}
|
||||
|
||||
List<PresentationMailbox> _findMailboxPath(List<PresentationMailbox> mailboxes) {
|
||||
return mailboxes.map((presentationMailbox) {
|
||||
if (!presentationMailbox.hasParentId()) {
|
||||
return presentationMailbox;
|
||||
} else {
|
||||
final mailboxNode = folderMailboxTree.findNode(presentationMailbox.id);
|
||||
if (mailboxNode != null) {
|
||||
String mailboxPath = mailboxNode.getPathMailboxNode(folderMailboxTree, defaultMailboxList);
|
||||
if (mailboxPath.contains('/')) {
|
||||
mailboxPath = mailboxPath.substring(0, mailboxPath.lastIndexOf('/')).replaceAll('/', ' / ');
|
||||
}
|
||||
return presentationMailbox.toPresentationMailboxWithMailboxPath(mailboxPath);
|
||||
} else {
|
||||
return presentationMailbox;
|
||||
}
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
void _searchMailboxFailure(SearchMailboxFailure failure) {
|
||||
listMailboxSearched.clear();
|
||||
}
|
||||
|
||||
void closeMailboxScreen(BuildContext context) {
|
||||
|
||||
@@ -35,15 +35,15 @@ class MailboxView extends GetWidget<MailboxController> {
|
||||
children: [
|
||||
_buildHeaderMailbox(context),
|
||||
Obx(() => controller.isSearchActive() ? _buildInputSearchFormWidget(context) : SizedBox.shrink()),
|
||||
Expanded(child: Container(
|
||||
Expanded(child: Obx(() => Container(
|
||||
color: controller.isSearchActive() ? Colors.white : AppColor.colorBgMailbox,
|
||||
child: RefreshIndicator(
|
||||
color: AppColor.primaryColor,
|
||||
onRefresh: () async => controller.refreshAllMailbox(),
|
||||
child: Obx(() => controller.isSearchActive()
|
||||
? _buildListMailboxSearched(context, controller.listMailboxSearched)
|
||||
: _buildListMailbox(context))),
|
||||
))
|
||||
child: controller.isSearchActive()
|
||||
? _buildListMailboxSearched(context, controller.listMailboxSearched)
|
||||
: _buildListMailbox(context)),
|
||||
)))
|
||||
]
|
||||
),
|
||||
)
|
||||
@@ -283,7 +283,7 @@ class MailboxView extends GetWidget<MailboxController> {
|
||||
|
||||
Widget _buildListMailboxSearched(BuildContext context, List<PresentationMailbox> listMailbox) {
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.all(8),
|
||||
padding: EdgeInsets.only(left: 16, right: 8, bottom: 30),
|
||||
key: Key('list_mailbox_searched'),
|
||||
itemCount: listMailbox.length,
|
||||
shrinkWrap: true,
|
||||
@@ -292,6 +292,7 @@ class MailboxView extends GetWidget<MailboxController> {
|
||||
Obx(() => (MailboxTileBuilder(
|
||||
imagePaths,
|
||||
listMailbox[index],
|
||||
isSearchActive: controller.isSearchActive(),
|
||||
isLastElement: index == listMailbox.length - 1)
|
||||
..onOpenMailboxAction((mailbox) => controller.selectMailbox(context, mailbox)))
|
||||
.build()));
|
||||
|
||||
@@ -14,6 +14,7 @@ class MailboxTileBuilder {
|
||||
final ImagePaths _imagePaths;
|
||||
final MailboxDisplayed mailboxDisplayed;
|
||||
final bool isLastElement;
|
||||
final bool isSearchActive;
|
||||
|
||||
OnOpenMailboxActionClick? _onOpenMailboxActionClick;
|
||||
|
||||
@@ -24,6 +25,7 @@ class MailboxTileBuilder {
|
||||
this.selectMode = SelectMode.INACTIVE,
|
||||
this.mailboxDisplayed = MailboxDisplayed.mailbox,
|
||||
this.isLastElement = false,
|
||||
this.isSearchActive = false,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -67,9 +69,9 @@ class MailboxTileBuilder {
|
||||
'${_presentationMailbox.name?.name ?? ''}',
|
||||
maxLines: 1,
|
||||
overflow:TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 15, color: AppColor.colorNameEmail),
|
||||
style: TextStyle(fontSize: isSearchActive ? 17 : 15, color: AppColor.colorNameEmail),
|
||||
)),
|
||||
if (mailboxDisplayed == MailboxDisplayed.mailbox)
|
||||
if (mailboxDisplayed == MailboxDisplayed.mailbox && !isSearchActive)
|
||||
Transform(
|
||||
transform: Matrix4.translationValues(40.0, 0.0, 0.0),
|
||||
child: Text(
|
||||
@@ -77,7 +79,18 @@ class MailboxTileBuilder {
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 13, color: AppColor.colorNameEmail)))
|
||||
])),
|
||||
trailing: (mailboxDisplayed == MailboxDisplayed.mailbox)
|
||||
subtitle: isSearchActive && _presentationMailbox.mailboxPath?.isNotEmpty == true
|
||||
? Transform(
|
||||
transform: Matrix4.translationValues(-10.0, 0.0, 0.0),
|
||||
child: Text(
|
||||
_presentationMailbox.mailboxPath ?? '',
|
||||
maxLines: 1,
|
||||
overflow:TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 13, color: AppColor.colorContentEmail),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
trailing: (mailboxDisplayed == MailboxDisplayed.mailbox && !isSearchActive)
|
||||
? Transform(
|
||||
transform: Matrix4.translationValues(8.0, 0.0, 0.0),
|
||||
child: IconButton(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
||||
|
||||
@@ -28,8 +28,6 @@ class MailboxDashBoardController extends BaseController {
|
||||
final AppToast _appToast;
|
||||
final ImagePaths _imagePaths;
|
||||
final RemoveEmailDraftsInteractor _removeEmailDraftsInteractor;
|
||||
final TextEditingController searchInputController;
|
||||
final FocusNode searchFocus;
|
||||
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final selectedMailbox = Rxn<PresentationMailbox>();
|
||||
@@ -43,13 +41,13 @@ class MailboxDashBoardController extends BaseController {
|
||||
Session? sessionCurrent;
|
||||
Map<Role, MailboxId> mapDefaultMailboxId = Map();
|
||||
Map<MailboxId, PresentationMailbox> mapMailbox = Map();
|
||||
TextEditingController searchInputController = TextEditingController();
|
||||
FocusNode searchFocus = FocusNode();
|
||||
|
||||
MailboxDashBoardController(
|
||||
this._getUserProfileInteractor,
|
||||
this._appToast,
|
||||
this._imagePaths,
|
||||
this.searchInputController,
|
||||
this.searchFocus,
|
||||
this._removeEmailDraftsInteractor,
|
||||
);
|
||||
|
||||
@@ -230,6 +228,7 @@ class MailboxDashBoardController extends BaseController {
|
||||
@override
|
||||
void onClose() {
|
||||
searchInputController.dispose();
|
||||
searchFocus.dispose();
|
||||
Get.delete<EmailController>();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -136,6 +136,7 @@ class ThreadController extends BaseController {
|
||||
mailboxDashBoardController.clearState();
|
||||
} else if (success is SearchEmailNewQuery){
|
||||
_searchEmail();
|
||||
mailboxDashBoardController.clearState();
|
||||
} else if (success is SaveEmailAsDraftsSuccess
|
||||
|| success is RemoveEmailDraftsSuccess
|
||||
|| success is SendEmailSuccess
|
||||
|
||||
Reference in New Issue
Block a user