create suggest box email
This commit is contained in:
@@ -120,6 +120,7 @@ extension AppColor on Color {
|
|||||||
static const colorBgMenuItemDropDownSelected = Color(0x80DEE2E7);
|
static const colorBgMenuItemDropDownSelected = Color(0x80DEE2E7);
|
||||||
static const colorButtonCancelDialog = Color(0x0D000000);
|
static const colorButtonCancelDialog = Color(0x0D000000);
|
||||||
static const colorShadowComposerButton = Color(0x99007AFF);
|
static const colorShadowComposerButton = Color(0x99007AFF);
|
||||||
|
static const colorBackgroundTagFilter = Color(0x6D7885);
|
||||||
|
|
||||||
static const mapGradientColor = [
|
static const mapGradientColor = [
|
||||||
[Color(0xFF21D4FD), Color(0xFFB721FF)],
|
[Color(0xFF21D4FD), Color(0xFFB721FF)],
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# 7. Fix show Dropdown can't not over overlayUI (#685)
|
||||||
|
|
||||||
|
Date: 2022-06-29
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
- Issue: DropDownButton menu shows behind Overlay
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
- Root cause: Add package flutter_portal to fix this issue
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
- When add Dropdown button to overlayUI, it can't lying above overlayUI.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- The app Navigator has a list of routes (_history) and each route has its list of OverlayEntry's.
|
||||||
|
When you push a new route using Navigator.push() you are inserting the route overlays above the overlays of the last route.
|
||||||
|
So, when you add an independent Overlay with just Overlay.of(context).insert(myOverlay);
|
||||||
|
it will always be above any route/overlay managed by the app Navigator (if what you receive from the of() method is the Navigator Overlay).
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import 'package:contact/contact_module.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/datasource/contact_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/datasource_impl/contact_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/repository/auto_complete_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/repository/auto_complete_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/session_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
import 'package:jmap_dart_client/http/http_client.dart' as jmap_http_client;
|
||||||
|
|
||||||
|
class AdvancedFilterBindings extends BaseBindings {
|
||||||
|
|
||||||
|
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||||
|
final Set<AutoCompleteDataSource> dataSources = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsDataSourceImpl() {
|
||||||
|
if (mailboxDashBoardController.sessionCurrent?.hasSupportAutoComplete == true) {
|
||||||
|
Get.lazyPut(() => ContactAPI(Get.find<jmap_http_client.HttpClient>()));
|
||||||
|
Get.lazyPut(() => TMailContactDataSourceImpl(Get.find<ContactAPI>()));
|
||||||
|
dataSources.add(Get.find<TMailContactDataSourceImpl>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Get.lazyPut(() => ContactDataSourceImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsDataSource() {
|
||||||
|
Get.lazyPut<ContactDataSource>(() => Get.find<ContactDataSourceImpl>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsRepositoryImpl() {
|
||||||
|
Get.lazyPut(() => AutoCompleteRepositoryImpl(dataSources));
|
||||||
|
Get.lazyPut(() => ContactRepositoryImpl(Get.find<ContactDataSource>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsRepository() {
|
||||||
|
Get.lazyPut<AutoCompleteRepository>(() => Get.find<AutoCompleteRepositoryImpl>());
|
||||||
|
Get.lazyPut<ContactRepository>(() => Get.find<ContactRepositoryImpl>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsInteractor() {
|
||||||
|
Get.lazyPut(() => GetAutoCompleteInteractor(Get.find<AutoCompleteRepository>()));
|
||||||
|
Get.lazyPut(() => GetDeviceContactSuggestionsInteractor(Get.find<ContactRepository>()));
|
||||||
|
Get.lazyPut(() => GetAutoCompleteWithDeviceContactInteractor(
|
||||||
|
Get.find<GetAutoCompleteInteractor>(),
|
||||||
|
Get.find<GetDeviceContactSuggestionsInteractor>()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void bindingsController() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -3,6 +3,13 @@ import 'package:get/get.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/recent_search_cache_client.dart';
|
import 'package:tmail_ui_user/features/caching/recent_search_cache_client.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
|
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/repository/auto_complete_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/repository/auto_complete_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
||||||
@@ -129,6 +136,12 @@ class MailboxDashBoardBindings extends BaseBindings {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void bindingsInteractor() {
|
void bindingsInteractor() {
|
||||||
|
Get.lazyPut(() => GetAutoCompleteInteractor(Get.find<AutoCompleteRepository>()));
|
||||||
|
Get.lazyPut(() => GetDeviceContactSuggestionsInteractor(Get.find<ContactRepository>()));
|
||||||
|
Get.lazyPut(() => GetAutoCompleteWithDeviceContactInteractor(
|
||||||
|
Get.find<GetAutoCompleteInteractor>(),
|
||||||
|
Get.find<GetDeviceContactSuggestionsInteractor>()
|
||||||
|
));
|
||||||
Get.lazyPut(() => GetUserProfileInteractor(Get.find<CredentialRepository>()));
|
Get.lazyPut(() => GetUserProfileInteractor(Get.find<CredentialRepository>()));
|
||||||
Get.lazyPut(() => RemoveEmailDraftsInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => RemoveEmailDraftsInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => MoveToMailboxInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MoveToMailboxInteractor(Get.find<EmailRepository>()));
|
||||||
@@ -156,6 +169,8 @@ class MailboxDashBoardBindings extends BaseBindings {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void bindingsRepository() {
|
void bindingsRepository() {
|
||||||
|
Get.lazyPut<AutoCompleteRepository>(() => Get.find<AutoCompleteRepositoryImpl>());
|
||||||
|
Get.lazyPut<ContactRepository>(() => Get.find<ContactRepositoryImpl>());
|
||||||
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
||||||
Get.lazyPut<SearchRepository>(() => Get.find<SearchRepositoryImpl>());
|
Get.lazyPut<SearchRepository>(() => Get.find<SearchRepositoryImpl>());
|
||||||
Get.lazyPut<ThreadRepository>(() => Get.find<ThreadRepositoryImpl>());
|
Get.lazyPut<ThreadRepository>(() => Get.find<ThreadRepositoryImpl>());
|
||||||
+133
-54
@@ -2,10 +2,16 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
import 'package:model/model.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/advanced_filter_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||||
@@ -13,33 +19,59 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/sear
|
|||||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
class AdvancedFilterController extends BaseController {
|
class AdvancedFilterController extends GetxController {
|
||||||
|
late GetAutoCompleteWithDeviceContactInteractor
|
||||||
|
_getAutoCompleteWithDeviceContactInteractor;
|
||||||
|
late GetAutoCompleteInteractor _getAutoCompleteInteractor;
|
||||||
|
|
||||||
final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs;
|
final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs;
|
||||||
final hasAttachment = false.obs;
|
final hasAttachment = false.obs;
|
||||||
|
final listEmailAddressInit = RxList<EmailAddress>();
|
||||||
|
final listTagFromSelected = RxList<String>();
|
||||||
|
final listTagToSelected = RxList<String>();
|
||||||
|
|
||||||
TextEditingController fromFilterInputController = TextEditingController();
|
|
||||||
TextEditingController toFilterInputController = TextEditingController();
|
|
||||||
TextEditingController subjectFilterInputController = TextEditingController();
|
TextEditingController subjectFilterInputController = TextEditingController();
|
||||||
TextEditingController hasKeyWordFilterInputController = TextEditingController();
|
TextEditingController hasKeyWordFilterInputController =
|
||||||
TextEditingController notKeyWordFilterInputController = TextEditingController();
|
TextEditingController();
|
||||||
|
TextEditingController notKeyWordFilterInputController =
|
||||||
|
TextEditingController();
|
||||||
TextEditingController dateFilterInputController = TextEditingController();
|
TextEditingController dateFilterInputController = TextEditingController();
|
||||||
TextEditingController mailBoxFilterInputController = TextEditingController();
|
TextEditingController mailBoxFilterInputController = TextEditingController();
|
||||||
|
ContactSuggestionSource _contactSuggestionSource =
|
||||||
|
ContactSuggestionSource.tMailContact;
|
||||||
|
|
||||||
final SearchController _searchController = Get.find<SearchController>();
|
final SearchController _searchController = Get.find<SearchController>();
|
||||||
final MailboxDashBoardController _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
final MailboxDashBoardController _mailboxDashBoardController =
|
||||||
|
Get.find<MailboxDashBoardController>();
|
||||||
|
|
||||||
SearchEmailFilter get _searchEmailFilter => _searchController.searchEmailFilter.value;
|
AdvancedFilterController() {
|
||||||
|
AdvancedFilterBindings().dependencies();
|
||||||
|
_getAutoCompleteWithDeviceContactInteractor =
|
||||||
|
Get.find<GetAutoCompleteWithDeviceContactInteractor>();
|
||||||
|
_getAutoCompleteInteractor = Get.find<GetAutoCompleteInteractor>();
|
||||||
|
}
|
||||||
|
|
||||||
selectOpenAdvanceSearch() {
|
SearchEmailFilter get searchEmailFilter =>
|
||||||
|
_searchController.searchEmailFilter.value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() async {
|
||||||
|
if (!BuildUtils.isWeb) {
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 500), () => _checkContactPermission());
|
||||||
|
}
|
||||||
|
super.onReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectOpenAdvanceSearch() {
|
||||||
_searchController.isAdvancedSearchViewOpen.toggle();
|
_searchController.isAdvancedSearchViewOpen.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanSearchFilter(BuildContext context) {
|
void cleanSearchFilter(BuildContext context) {
|
||||||
_searchController.cleanSearchFilter();
|
_searchController.cleanSearchFilter();
|
||||||
dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime;
|
dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime;
|
||||||
fromFilterInputController.text = '';
|
listTagFromSelected.clear();
|
||||||
toFilterInputController.text = '';
|
listTagToSelected.clear();
|
||||||
subjectFilterInputController.text = '';
|
subjectFilterInputController.text = '';
|
||||||
hasKeyWordFilterInputController.text = '';
|
hasKeyWordFilterInputController.text = '';
|
||||||
notKeyWordFilterInputController.text = '';
|
notKeyWordFilterInputController.text = '';
|
||||||
@@ -47,56 +79,102 @@ class AdvancedFilterController extends BaseController {
|
|||||||
hasAttachment.value = false;
|
hasAttachment.value = false;
|
||||||
_searchController.isAdvancedSearchHasApply.value = false;
|
_searchController.isAdvancedSearchHasApply.value = false;
|
||||||
_searchController.isAdvancedSearchViewOpen.toggle();
|
_searchController.isAdvancedSearchViewOpen.toggle();
|
||||||
_mailboxDashBoardController.searchEmail(context, StringConvert.writeNullToEmpty(_searchEmailFilter.text?.value));
|
_mailboxDashBoardController.searchEmail(
|
||||||
|
context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateFilterEmailFromAdvancedSearchView() {
|
void _updateFilterEmailFromAdvancedSearchView() {
|
||||||
if (fromFilterInputController.text.isNotEmpty) {
|
if (listTagFromSelected.isNotEmpty) {
|
||||||
_searchController.updateFilterEmail(from: fromFilterInputController.text.split(',').toSet());
|
_searchController.updateFilterEmail(
|
||||||
|
from: listTagFromSelected.toSet());
|
||||||
} else {
|
} else {
|
||||||
_searchController.updateFilterEmail(from: {});
|
_searchController.updateFilterEmail(from: {});
|
||||||
}
|
}
|
||||||
if (toFilterInputController.text.isNotEmpty) {
|
if (listTagToSelected.isNotEmpty) {
|
||||||
_searchController.updateFilterEmail(to: toFilterInputController.text.split(',').toSet());
|
_searchController.updateFilterEmail(
|
||||||
|
to: listTagToSelected.toSet());
|
||||||
} else {
|
} else {
|
||||||
_searchController.updateFilterEmail(to: {});
|
_searchController.updateFilterEmail(to: {});
|
||||||
}
|
}
|
||||||
if (hasKeyWordFilterInputController.text.isNotEmpty) {
|
if (hasKeyWordFilterInputController.text.isNotEmpty) {
|
||||||
_searchController.updateFilterEmail(hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet());
|
_searchController.updateFilterEmail(
|
||||||
|
hasKeyword: hasKeyWordFilterInputController.text.split(',').toSet());
|
||||||
} else {
|
} else {
|
||||||
_searchController.updateFilterEmail(hasKeyword: {});
|
_searchController.updateFilterEmail(hasKeyword: {});
|
||||||
}
|
}
|
||||||
if (notKeyWordFilterInputController.text.isNotEmpty) {
|
if (notKeyWordFilterInputController.text.isNotEmpty) {
|
||||||
_searchController.updateFilterEmail(notKeyword: notKeyWordFilterInputController.text.split(',').toSet());
|
_searchController.updateFilterEmail(
|
||||||
|
notKeyword: notKeyWordFilterInputController.text.split(',').toSet());
|
||||||
} else {
|
} else {
|
||||||
_searchController.updateFilterEmail(notKeyword: {});
|
_searchController.updateFilterEmail(notKeyword: {});
|
||||||
}
|
}
|
||||||
|
|
||||||
_searchController.updateFilterEmail(
|
_searchController.updateFilterEmail(
|
||||||
subject: StringConvert.writeEmptyToNull(subjectFilterInputController.text),
|
subject:
|
||||||
|
StringConvert.writeEmptyToNull(subjectFilterInputController.text),
|
||||||
emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value,
|
emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value,
|
||||||
hasAttachment: hasAttachment.value,
|
hasAttachment: hasAttachment.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selectedMailBox() async{
|
Future<void> selectedMailBox() async {
|
||||||
final PresentationMailbox destinationMailbox = await push(
|
final PresentationMailbox destinationMailbox = await push(
|
||||||
AppRoutes.DESTINATION_PICKER,
|
AppRoutes.DESTINATION_PICKER,
|
||||||
arguments: DestinationPickerArguments(_mailboxDashBoardController.accountId.value!, MailboxActions.moveEmail));
|
arguments: DestinationPickerArguments(
|
||||||
_searchController.updateFilterEmail(mailbox: destinationMailbox);
|
_mailboxDashBoardController.accountId.value!,
|
||||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(destinationMailbox.name?.name);
|
MailboxActions.moveEmail));
|
||||||
}
|
_searchController.updateFilterEmail(mailbox: destinationMailbox);
|
||||||
|
mailBoxFilterInputController.text =
|
||||||
applyAdvancedSearchFilter(BuildContext context){
|
StringConvert.writeNullToEmpty(destinationMailbox.name?.name);
|
||||||
_updateFilterEmailFromAdvancedSearchView();
|
|
||||||
_mailboxDashBoardController.searchEmail(context, StringConvert.writeNullToEmpty(_searchEmailFilter.text?.value));
|
|
||||||
_searchController.isAdvancedSearchViewOpen.toggle();
|
|
||||||
_searchController.isAdvancedSearchHasApply.value = _checkAdvancedSearchHasApply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _checkAdvancedSearchHasApply() {
|
void applyAdvancedSearchFilter(BuildContext context) {
|
||||||
return fromFilterInputController.text.isNotEmpty ||
|
_updateFilterEmailFromAdvancedSearchView();
|
||||||
toFilterInputController.text.isNotEmpty ||
|
_mailboxDashBoardController.searchEmail(
|
||||||
|
context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
|
||||||
|
_searchController.isAdvancedSearchViewOpen.toggle();
|
||||||
|
_searchController.isAdvancedSearchHasApply.value =
|
||||||
|
_checkAdvancedSearchHasApply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkContactPermission() async {
|
||||||
|
final permissionStatus = await Permission.contacts.status;
|
||||||
|
if (permissionStatus.isGranted) {
|
||||||
|
_contactSuggestionSource = ContactSuggestionSource.all;
|
||||||
|
} else if (!permissionStatus.isPermanentlyDenied) {
|
||||||
|
final requestedPermission = await Permission.contacts.request();
|
||||||
|
_contactSuggestionSource = requestedPermission == PermissionStatus.granted
|
||||||
|
? ContactSuggestionSource.all
|
||||||
|
: _contactSuggestionSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<EmailAddress>> getAutoCompleteSuggestion(
|
||||||
|
{required String word}) async {
|
||||||
|
if (_contactSuggestionSource == ContactSuggestionSource.all) {
|
||||||
|
return await _getAutoCompleteWithDeviceContactInteractor
|
||||||
|
.execute(AutoCompletePattern(
|
||||||
|
word: word,
|
||||||
|
accountId: _mailboxDashBoardController.accountId.value))
|
||||||
|
.then((value) => value.fold(
|
||||||
|
(failure) => <EmailAddress>[],
|
||||||
|
(success) => success is GetAutoCompleteSuccess
|
||||||
|
? success.listEmailAddress
|
||||||
|
: <EmailAddress>[]));
|
||||||
|
}
|
||||||
|
return await _getAutoCompleteInteractor
|
||||||
|
.execute(AutoCompletePattern(
|
||||||
|
word: word, accountId: _mailboxDashBoardController.accountId.value))
|
||||||
|
.then((value) => value.fold(
|
||||||
|
(failure) => <EmailAddress>[],
|
||||||
|
(success) => success is GetAutoCompleteSuccess
|
||||||
|
? success.listEmailAddress
|
||||||
|
: <EmailAddress>[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _checkAdvancedSearchHasApply() {
|
||||||
|
return listTagFromSelected.isNotEmpty ||
|
||||||
|
listTagToSelected.isNotEmpty ||
|
||||||
subjectFilterInputController.text.isNotEmpty ||
|
subjectFilterInputController.text.isNotEmpty ||
|
||||||
hasKeyWordFilterInputController.text.isNotEmpty ||
|
hasKeyWordFilterInputController.text.isNotEmpty ||
|
||||||
notKeyWordFilterInputController.text.isNotEmpty ||
|
notKeyWordFilterInputController.text.isNotEmpty ||
|
||||||
@@ -105,32 +183,33 @@ class AdvancedFilterController extends BaseController {
|
|||||||
hasAttachment.isTrue;
|
hasAttachment.isTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
initSearchFilterField(BuildContext context) {
|
void initSearchFilterField(BuildContext context) {
|
||||||
_searchController.updateFilterEmail(mailbox: _mailboxDashBoardController.selectedMailbox.value);
|
_searchController.updateFilterEmail(
|
||||||
fromFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.from.firstOrNull);
|
mailbox: _mailboxDashBoardController.selectedMailbox.value);
|
||||||
toFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.to.firstOrNull);
|
subjectFilterInputController.text =
|
||||||
subjectFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.subject);
|
StringConvert.writeNullToEmpty(searchEmailFilter.subject);
|
||||||
hasKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.hasKeyword.firstOrNull);
|
hasKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||||
notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.notKeyword.firstOrNull);
|
searchEmailFilter.hasKeyword.firstOrNull);
|
||||||
dateFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.emailReceiveTimeType.getTitle(context));
|
notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(_searchEmailFilter.mailbox?.name?.name);
|
searchEmailFilter.notKeyword.firstOrNull);
|
||||||
dateFilterSelectedFormAdvancedSearch.value = _searchEmailFilter.emailReceiveTimeType;
|
dateFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||||
hasAttachment.value = _searchEmailFilter.hasAttachment;
|
searchEmailFilter.emailReceiveTimeType.getTitle(context));
|
||||||
|
mailBoxFilterInputController.text =
|
||||||
|
StringConvert.writeNullToEmpty(searchEmailFilter.mailbox?.name?.name);
|
||||||
|
dateFilterSelectedFormAdvancedSearch.value =
|
||||||
|
searchEmailFilter.emailReceiveTimeType;
|
||||||
|
hasAttachment.value = searchEmailFilter.hasAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onDone() {
|
void onDone() {}
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onError(error) {
|
void onError(error) {}
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
fromFilterInputController.dispose();
|
|
||||||
subjectFilterInputController.dispose();
|
subjectFilterInputController.dispose();
|
||||||
toFilterInputController.dispose();
|
|
||||||
hasKeyWordFilterInputController.dispose();
|
hasKeyWordFilterInputController.dispose();
|
||||||
notKeyWordFilterInputController.dispose();
|
notKeyWordFilterInputController.dispose();
|
||||||
mailBoxFilterInputController.dispose();
|
mailBoxFilterInputController.dispose();
|
||||||
|
|||||||
-1
@@ -241,7 +241,6 @@ class MailboxDashBoardController extends ReloadableController {
|
|||||||
void setNewFirstSelectedMailbox(PresentationMailbox? newPresentationMailbox) {
|
void setNewFirstSelectedMailbox(PresentationMailbox? newPresentationMailbox) {
|
||||||
selectedMailbox.firstRebuild = true;
|
selectedMailbox.firstRebuild = true;
|
||||||
selectedMailbox.value = newPresentationMailbox;
|
selectedMailbox.value = newPresentationMailbox;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectedEmail(PresentationEmail? newPresentationEmail) {
|
void setSelectedEmail(PresentationEmail? newPresentationEmail) {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class SearchController extends BaseController {
|
|||||||
return;
|
return;
|
||||||
case QuickSearchFilter.fromMe:
|
case QuickSearchFilter.fromMe:
|
||||||
quickSearchFilterSelected
|
quickSearchFilterSelected
|
||||||
? searchEmailFilter.value.from.remove(userProfile.email)
|
? searchEmailFilter.value.from.removeWhere((e) => e == userProfile.email)
|
||||||
: searchEmailFilter.value.from.add(userProfile.email);
|
: searchEmailFilter.value.from.add(userProfile.email);
|
||||||
updateFilterEmail(from: searchEmailFilter.value.from);
|
updateFilterEmail(from: searchEmailFilter.value.from);
|
||||||
return;
|
return;
|
||||||
@@ -195,7 +195,7 @@ class SearchController extends BaseController {
|
|||||||
}
|
}
|
||||||
return searchEmailFilter.value.emailReceiveTimeType == EmailReceiveTimeType.last7Days;
|
return searchEmailFilter.value.emailReceiveTimeType == EmailReceiveTimeType.last7Days;
|
||||||
case QuickSearchFilter.fromMe:
|
case QuickSearchFilter.fromMe:
|
||||||
return searchEmailFilter.value.from.contains(userProfile.email) && searchEmailFilter.value.from.length == 1;
|
return searchEmailFilter.value.from.contains( userProfile.email) && searchEmailFilter.value.from.length == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
|||||||
tabletLarge: Row(
|
tabletLarge: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(child: MailboxView(), width: responsiveUtils.defaultSizeDrawer),
|
SizedBox(child: MailboxView(), width: responsiveUtils.defaultSizeMenu),
|
||||||
Expanded(child: _wrapContainerForThreadAndEmail(context))
|
Expanded(child: _wrapContainerForThreadAndEmail(context))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -423,8 +423,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
|||||||
target: Alignment.bottomLeft,
|
target: Alignment.bottomLeft,
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
backup: Aligned(
|
backup: Aligned(
|
||||||
follower: Alignment.bottomLeft,
|
follower: Alignment.topLeft,
|
||||||
target: Alignment.topLeft,
|
target: Alignment.bottomLeft,
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+79
-17
@@ -8,6 +8,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/sear
|
|||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/drop_down_button_filter_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart';
|
||||||
|
|
||||||
class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||||
with PopupContextMenuActionMixin {
|
with PopupContextMenuActionMixin {
|
||||||
@@ -24,15 +25,17 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildFilterField(
|
_buildSuggestionFilterField(
|
||||||
textEditingController: controller.fromFilterInputController,
|
listTagSelected: controller.listTagFromSelected,
|
||||||
context: context,
|
context: context,
|
||||||
advancedSearchFilterField: AdvancedSearchFilterField.form,
|
advancedSearchFilterField: AdvancedSearchFilterField.form,
|
||||||
|
listTagInitial: controller.searchEmailFilter.from.toList()
|
||||||
),
|
),
|
||||||
_buildFilterField(
|
_buildSuggestionFilterField(
|
||||||
textEditingController: controller.toFilterInputController,
|
listTagSelected: controller.listTagToSelected,
|
||||||
context: context,
|
context: context,
|
||||||
advancedSearchFilterField: AdvancedSearchFilterField.to,
|
advancedSearchFilterField: AdvancedSearchFilterField.to,
|
||||||
|
listTagInitial: controller.searchEmailFilter.to.toList()
|
||||||
),
|
),
|
||||||
_buildFilterField(
|
_buildFilterField(
|
||||||
textEditingController: controller.subjectFilterInputController,
|
textEditingController: controller.subjectFilterInputController,
|
||||||
@@ -50,14 +53,13 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
advancedSearchFilterField: AdvancedSearchFilterField.notKeyword,
|
advancedSearchFilterField: AdvancedSearchFilterField.notKeyword,
|
||||||
),
|
),
|
||||||
_buildFilterField(
|
_buildFilterField(
|
||||||
textEditingController: controller.mailBoxFilterInputController,
|
textEditingController: controller.mailBoxFilterInputController,
|
||||||
context: context,
|
context: context,
|
||||||
advancedSearchFilterField: AdvancedSearchFilterField.mailBox,
|
advancedSearchFilterField: AdvancedSearchFilterField.mailBox,
|
||||||
isSelectFormList: true,
|
isSelectFormList: true,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await controller.selectedMailBox();
|
await controller.selectedMailBox();
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
_buildFilterField(
|
_buildFilterField(
|
||||||
textEditingController: controller.dateFilterInputController,
|
textEditingController: controller.dateFilterInputController,
|
||||||
context: context,
|
context: context,
|
||||||
@@ -70,7 +72,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const AdvancedSearchFilterFormBottomView()
|
const AdvancedSearchFilterFormBottomView()
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -177,6 +179,57 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildSuggestionFilterField({
|
||||||
|
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||||
|
required BuildContext context,
|
||||||
|
required List<String> listTagSelected,
|
||||||
|
required List<String> listTagInitial,
|
||||||
|
}) {
|
||||||
|
final child = [
|
||||||
|
SizedBox(
|
||||||
|
width: _responsiveUtils.isMobile(context) ? null : 112,
|
||||||
|
child: Text(
|
||||||
|
advancedSearchFilterField.getTitle(context),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: AppColor.colorContentEmail,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Padding(padding: EdgeInsets.all(4)),
|
||||||
|
_responsiveUtils.isMobile(context)
|
||||||
|
? TextFieldAutoCompleteEmailAddress(
|
||||||
|
optionsBuilder: (word) async {
|
||||||
|
return controller.getAutoCompleteSuggestion(word: word);
|
||||||
|
},
|
||||||
|
advancedSearchFilterField: advancedSearchFilterField,
|
||||||
|
initialTags: listTagInitial,
|
||||||
|
listTagSelected: listTagSelected,
|
||||||
|
)
|
||||||
|
: Expanded(
|
||||||
|
child: TextFieldAutoCompleteEmailAddress(
|
||||||
|
optionsBuilder: (word) async {
|
||||||
|
return controller.getAutoCompleteSuggestion(word: word);
|
||||||
|
},
|
||||||
|
advancedSearchFilterField: advancedSearchFilterField,
|
||||||
|
initialTags: listTagInitial,
|
||||||
|
listTagSelected: listTagSelected,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
];
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: _responsiveUtils.isMobile(context)
|
||||||
|
? Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: child,
|
||||||
|
)
|
||||||
|
: SizedBox(height: 44, child: Row(children: child)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildTextField({
|
Widget _buildTextField({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||||
@@ -195,6 +248,15 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
|||||||
right: 8,
|
right: 8,
|
||||||
left: 12,
|
left: 12,
|
||||||
),
|
),
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10),
|
||||||
|
),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color: AppColor.colorInputBorderCreateMailbox,
|
||||||
|
),
|
||||||
|
),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(10),
|
Radius.circular(10),
|
||||||
|
|||||||
+4
-4
@@ -33,8 +33,8 @@ class AdvancedSearchFilterFormBottomView
|
|||||||
controller.cleanSearchFilter(context);
|
controller.cleanSearchFilter(context);
|
||||||
popBack();
|
popBack();
|
||||||
},
|
},
|
||||||
colorButton: AppColor.primaryColor.withOpacity(0.14),
|
colorButton: Colors.transparent,
|
||||||
colorText: AppColor.primaryColor,
|
colorText: AppColor.colorMessageConfirmDialog,
|
||||||
text: AppLocalizations.of(context).clearFilter,
|
text: AppLocalizations.of(context).clearFilter,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@@ -80,8 +80,8 @@ class AdvancedSearchFilterFormBottomView
|
|||||||
onAction.call();
|
onAction.call();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 154),
|
height: 44,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
constraints: const BoxConstraints(maxWidth: 144),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10), color: colorButton),
|
borderRadius: BorderRadius.circular(10), color: colorButton),
|
||||||
|
|||||||
+7
-2
@@ -11,7 +11,7 @@ class AdvancedSearchFilterOverlay extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(top: 8),
|
padding: const EdgeInsets.only(top: 8),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 660,
|
width: 660,
|
||||||
height: 558,
|
height: MediaQuery.of(context).size.height,
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@@ -22,7 +22,12 @@ class AdvancedSearchFilterOverlay extends StatelessWidget {
|
|||||||
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5)),
|
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5)),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
child: AdvancedSearchInputForm(),
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 12),
|
||||||
|
child: AdvancedSearchInputForm(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+286
@@ -0,0 +1,286 @@
|
|||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:core/core.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:model/extensions/email_address_extension.dart';
|
||||||
|
import 'package:textfield_tags/textfield_tags.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
|
class TextFieldAutoCompleteEmailAddress extends StatefulWidget {
|
||||||
|
const TextFieldAutoCompleteEmailAddress({
|
||||||
|
Key? key,
|
||||||
|
required this.advancedSearchFilterField,
|
||||||
|
required this.listTagSelected,
|
||||||
|
required this.initialTags,
|
||||||
|
required this.optionsBuilder,
|
||||||
|
}) : super(key: key);
|
||||||
|
final AdvancedSearchFilterField advancedSearchFilterField;
|
||||||
|
final List<String> listTagSelected;
|
||||||
|
final List<String> initialTags;
|
||||||
|
final Future<List<EmailAddress>> Function(String) optionsBuilder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TextFieldAutoCompleteEmailAddress> createState() =>
|
||||||
|
_TextFieldAutoCompleteEmailAddressState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TextFieldAutoCompleteEmailAddressState
|
||||||
|
extends State<TextFieldAutoCompleteEmailAddress> {
|
||||||
|
final double _distanceToField = 380;
|
||||||
|
final ImagePaths _imagePaths = Get.find<ImagePaths>();
|
||||||
|
late TextfieldTagsController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_controller = TextfieldTagsController();
|
||||||
|
_controller.addListener(() {
|
||||||
|
if(_controller.hasTags){
|
||||||
|
widget.listTagSelected.addAll(_controller.getTags!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Autocomplete<EmailAddress>(
|
||||||
|
optionsViewBuilder: (context, onSelected, options) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: Material(
|
||||||
|
elevation: 4.0,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints:
|
||||||
|
const BoxConstraints(maxHeight: 200, maxWidth: 200),
|
||||||
|
child: ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: options.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final dynamic option = options.elementAt(index);
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
onSelected(option);
|
||||||
|
},
|
||||||
|
child: _buildSuggestionItem(context, option),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||||
|
return widget.optionsBuilder.call(textEditingValue.text);
|
||||||
|
},
|
||||||
|
onSelected: (EmailAddress selectedTag) {
|
||||||
|
_controller.addTag = selectedTag.asString();
|
||||||
|
},
|
||||||
|
fieldViewBuilder: (context, ttec, tfn, onFieldSubmitted) {
|
||||||
|
return TextFieldTags(
|
||||||
|
initialTags: widget.initialTags,
|
||||||
|
textEditingController: ttec,
|
||||||
|
focusNode: tfn,
|
||||||
|
textfieldTagsController: _controller,
|
||||||
|
textSeparators: const [' ', ','],
|
||||||
|
letterCase: LetterCase.normal,
|
||||||
|
validator: (String tag) {
|
||||||
|
if (_controller.getTags!.contains(tag)) {
|
||||||
|
return AppLocalizations.of(context).messageDuplicateTagFilterMail;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
inputfieldBuilder: (context, tec, fn, error, onChanged, onSubmitted) {
|
||||||
|
return ((context, sc, tags, onTagDelete) {
|
||||||
|
return TextField(
|
||||||
|
controller: tec,
|
||||||
|
focusNode: fn,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
fillColor: AppColor.loginTextFieldBackgroundColor,
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
right: 8,
|
||||||
|
left: 12,
|
||||||
|
),
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10),
|
||||||
|
),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color: AppColor.colorInputBorderCreateMailbox,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
hintText:
|
||||||
|
widget.advancedSearchFilterField.getHintText(context),
|
||||||
|
hintStyle: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: AppColor.colorHintSearchBar,
|
||||||
|
),
|
||||||
|
prefixIconConstraints:
|
||||||
|
BoxConstraints(maxWidth: _distanceToField * 0.74),
|
||||||
|
prefixIcon: tags.isNotEmpty
|
||||||
|
? SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
controller: sc,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
children: tags.map((String tag) {
|
||||||
|
return _buildTagItem(context, tag, onTagDelete);
|
||||||
|
}).toList()),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
onChanged: onChanged,
|
||||||
|
onSubmitted: (tag){
|
||||||
|
onSubmitted?.call(tag);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSuggestionItem(
|
||||||
|
BuildContext context,
|
||||||
|
EmailAddress emailAddress,
|
||||||
|
) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: AppColor.avatarColor,
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColor.colorShadowBgContentEmail, width: 1.0)),
|
||||||
|
child: Text(
|
||||||
|
emailAddress.asString().isNotEmpty
|
||||||
|
? emailAddress.asString()[0].toUpperCase()
|
||||||
|
: '',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600))),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(emailAddress.asString(),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: kIsWeb ? null : TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.normal)),
|
||||||
|
if (emailAddress.displayName.isNotEmpty &&
|
||||||
|
emailAddress.emailAddress.isNotEmpty)
|
||||||
|
Text(emailAddress.emailAddress,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: kIsWeb ? null : TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColor.colorHintSearchBar,
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.normal))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTagItem(
|
||||||
|
BuildContext context,
|
||||||
|
String tag,
|
||||||
|
Function(String tag) onTagDelete,
|
||||||
|
) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(10),
|
||||||
|
),
|
||||||
|
color: AppColor.colorBackgroundTagFilter.withOpacity(0.08),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.only(right: 8),
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 4, 4, 4),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: AppColor.mapGradientColor[_generateIndex(tag)],
|
||||||
|
),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColor.colorShadowBgContentEmail, width: 0.21)),
|
||||||
|
child: Text(tag[0].toUpperCase(),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 8.57,
|
||||||
|
fontWeight: FontWeight.w600))),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(tag,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: kIsWeb ? null : TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.normal)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
onTagDelete.call(tag);
|
||||||
|
widget.listTagSelected.remove(tag);
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
_imagePaths.icClose,
|
||||||
|
width: 28,
|
||||||
|
height: 28,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _generateIndex(String tag) {
|
||||||
|
if (tag.isNotEmpty) {
|
||||||
|
final codeUnits = tag.codeUnits;
|
||||||
|
if (codeUnits.isNotEmpty) {
|
||||||
|
final sumCodeUnits = codeUnits.sum;
|
||||||
|
final index = sumCodeUnits % AppColor.mapGradientColor.length;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_controller.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -289,8 +289,8 @@ class ThreadController extends BaseController {
|
|||||||
if (viewState is Either) {
|
if (viewState is Either) {
|
||||||
viewState.map((success) {
|
viewState.map((success) {
|
||||||
if (success is SearchEmailNewQuery){
|
if (success is SearchEmailNewQuery){
|
||||||
_searchEmail();
|
|
||||||
mailboxDashBoardController.clearState();
|
mailboxDashBoardController.clearState();
|
||||||
|
_searchEmail();
|
||||||
} else if (success is MarkAsEmailReadSuccess
|
} else if (success is MarkAsEmailReadSuccess
|
||||||
|| success is MoveToMailboxSuccess
|
|| success is MoveToMailboxSuccess
|
||||||
|| success is MarkAsStarEmailSuccess
|
|| success is MarkAsStarEmailSuccess
|
||||||
|
|||||||
@@ -190,8 +190,8 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
|
|||||||
target: Alignment.bottomLeft,
|
target: Alignment.bottomLeft,
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
backup: Aligned(
|
backup: Aligned(
|
||||||
follower: Alignment.bottomLeft,
|
follower: Alignment.topLeft,
|
||||||
target: Alignment.topLeft,
|
target: Alignment.bottomLeft,
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"@@last_modified": "2022-06-24T14:16:53.170960",
|
"@@last_modified": "2022-06-29T12:21:47.830137",
|
||||||
"initializing_data": "Initializing data...",
|
"initializing_data": "Initializing data...",
|
||||||
"@initializing_data": {
|
"@initializing_data": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -1545,4 +1545,11 @@ class AppLocalizations {
|
|||||||
name: 'selectMailbox',
|
name: 'selectMailbox',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get messageDuplicateTagFilterMail {
|
||||||
|
return Intl.message(
|
||||||
|
'you already entered that',
|
||||||
|
name: 'selectMailbox',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ import 'package:tmail_ui_user/features/login/presentation/login_view.dart'
|
|||||||
if (dart.library.html) 'package:tmail_ui_user/features/login/presentation/login_view_web.dart' deferred as login;
|
if (dart.library.html) 'package:tmail_ui_user/features/login/presentation/login_view_web.dart' deferred as login;
|
||||||
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_bindings.dart';
|
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_view.dart' deferred as mailbox_creator;
|
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_view.dart' deferred as mailbox_creator;
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart'
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart'
|
||||||
if (dart.library.html) 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart' deferred as mailbox_dashboard;
|
if (dart.library.html) 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart' deferred as mailbox_dashboard;
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_bindings.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_bindings.dart';
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ dependencies:
|
|||||||
|
|
||||||
built_collection: 5.1.1
|
built_collection: 5.1.1
|
||||||
|
|
||||||
|
textfield_tags: ^2.0.1
|
||||||
|
|
||||||
# jmap_dart_client
|
# jmap_dart_client
|
||||||
jmap_dart_client:
|
jmap_dart_client:
|
||||||
git:
|
git:
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
// Mocks generated by Mockito 5.0.17 from annotations
|
// Mocks generated by Mockito 5.2.0 from annotations
|
||||||
// in tmail_ui_user/test/features/thread/domain/usecases/get_emails_in_mailbox_interactor_test.dart.
|
// in tmail_ui_user/test/features/thread/domain/usecases/get_emails_in_mailbox_interactor_test.dart.
|
||||||
// Do not manually edit this file.
|
// Do not manually edit this file.
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dar
|
|||||||
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;
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: avoid_redundant_argument_values
|
// ignore_for_file: avoid_redundant_argument_values
|
||||||
// ignore_for_file: avoid_setters_without_getters
|
// ignore_for_file: avoid_setters_without_getters
|
||||||
// ignore_for_file: comment_references
|
// ignore_for_file: comment_references
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
// Mocks generated by Mockito 5.0.17 from annotations
|
// Mocks generated by Mockito 5.2.0 from annotations
|
||||||
// in tmail_ui_user/test/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor_test.dart.
|
// in tmail_ui_user/test/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor_test.dart.
|
||||||
// Do not manually edit this file.
|
// Do not manually edit this file.
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dar
|
|||||||
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;
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: avoid_redundant_argument_values
|
// ignore_for_file: avoid_redundant_argument_values
|
||||||
// ignore_for_file: avoid_setters_without_getters
|
// ignore_for_file: avoid_setters_without_getters
|
||||||
// ignore_for_file: comment_references
|
// ignore_for_file: comment_references
|
||||||
|
|||||||
Reference in New Issue
Block a user