TF-35 Implement search mailbox

This commit is contained in:
dab246
2022-02-23 18:45:34 +07:00
committed by Dat H. Pham
parent 9cca03fff3
commit ba453f71b2
9 changed files with 130 additions and 23 deletions
@@ -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