diff --git a/lib/features/email_recovery/presentation/email_recovery_controller.dart b/lib/features/email_recovery/presentation/email_recovery_controller.dart index e7c4f92c8..7a472508d 100644 --- a/lib/features/email_recovery/presentation/email_recovery_controller.dart +++ b/lib/features/email_recovery/presentation/email_recovery_controller.dart @@ -1,15 +1,33 @@ import 'package:core/presentation/utils/keyboard_utils.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:model/autocomplete/auto_complete_pattern.dart'; +import 'package:model/mailbox/expand_mode.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:super_tag_editor/tag_editor.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/date_range_picker_mixin.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/state/get_device_contact_suggestions_state.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_all_autocomplete_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/controller/input_field_focus_manager.dart'; +import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_arguments.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_field.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_time_type.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class EmailRecoveryController extends BaseController with DateRangePickerMixin { + GetAllAutoCompleteInteractor? _getAllAutoCompleteInteractor; + GetAutoCompleteInteractor? _getAutoCompleteInteractor; + GetDeviceContactSuggestionsInteractor? _getDeviceContactSuggestionsInteractor; final deletionDateFieldSelected = EmailRecoveryTimeType.last1Year.obs; final receptionDateFieldSelected = EmailRecoveryTimeType.allTime.obs; @@ -17,13 +35,106 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { final endDeletionDate = Rxn(); final startReceptionDate = Rxn(); final endReceptionDate = Rxn(); + final recipientsExpandMode = ExpandMode.EXPAND.obs; + final senderExpandMode = ExpandMode.EXPAND.obs; + final focusManager = InputFieldFocusManager.initial(); List listRecipients = []; List listSenders = []; + TextEditingController subjectFieldInputController = TextEditingController(); + TextEditingController recipientsFieldInputController = TextEditingController(); + TextEditingController senderFieldInputController = TextEditingController(); + ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact; + + final GlobalKey recipientsFieldKey = GlobalKey(); + final GlobalKey senderFieldKey = GlobalKey(); + + EmailRecoveryArguments? arguments; + AccountId? _accountId; + Session? _session; + EmailRecoveryController(); + @override + void onInit() { + _registerFocusListener(); + log('EmailRecoveryController::onInit():arguments: ${Get.arguments}'); + arguments = Get.arguments; + super.onInit(); + } + + @override + void onReady() { + log('EmailRecoveryController::onReady():'); + if (arguments != null) { + _accountId = arguments!.accountId; + _session = arguments!.session; + } + if (PlatformInfo.isMobile) { + Future.delayed( + const Duration(milliseconds: 500), + () => _checkContactPermission(), + ); + } + injectAutoCompleteBindings(_session, _accountId); + super.onReady(); + } + + 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; + } + } + + void _registerFocusListener() { + focusManager.subjectFieldFocusNode.addListener(_onSubjectFieldFocusChanged); + focusManager.recipientsFieldFocusNode.addListener(_onRecipientsFieldFocusChanged); + focusManager.senderFieldFocusNode.addListener(_onSenderFieldFocusChanged); + } + + void _onSubjectFieldFocusChanged() { + if (focusManager.subjectFieldFocusNode.hasFocus) { + senderExpandMode.value = ExpandMode.COLLAPSE; + recipientsExpandMode.value = ExpandMode.COLLAPSE; + _closeSuggestionBox(); + } + } + + void _onRecipientsFieldFocusChanged() { + if (focusManager.recipientsFieldFocusNode.hasFocus) { + recipientsExpandMode.value = ExpandMode.EXPAND; + senderExpandMode.value = ExpandMode.COLLAPSE; + _closeSuggestionBox(); + } + } + + void _onSenderFieldFocusChanged() { + if (focusManager.senderFieldFocusNode.hasFocus) { + senderExpandMode.value = ExpandMode.EXPAND; + recipientsExpandMode.value = ExpandMode.COLLAPSE; + _closeSuggestionBox(); + } + } + + void _closeSuggestionBox() { + if (recipientsFieldInputController.text.isNotEmpty) { + recipientsFieldKey.currentState?.closeSuggestionBox(); + } + + if (senderFieldInputController.text.isNotEmpty) { + senderFieldKey.currentState?.closeSuggestionBox(); + } + } + void onSelectDeletionDateRange(BuildContext context) { showMultipleViewDateRangePicker( context, @@ -99,8 +210,92 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { } } + Future> getAutoCompleteSuggestion(String word) async { + log('EmailRecoveryController::getAutoCompleteSuggestion(): $word | $_contactSuggestionSource'); + _getAllAutoCompleteInteractor = getBinding(); + _getAutoCompleteInteractor = getBinding(); + _getDeviceContactSuggestionsInteractor = getBinding(); + + if (_contactSuggestionSource == ContactSuggestionSource.all) { + if (_getAllAutoCompleteInteractor != null) { + return await _getAllAutoCompleteInteractor! + .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .then((value) => value.fold( + (failure) => [], + (success) => success is GetAutoCompleteSuccess + ? success.listEmailAddress + : [] + )); + } else if (_getDeviceContactSuggestionsInteractor != null) { + return await _getDeviceContactSuggestionsInteractor! + .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .then((value) => value.fold( + (failure) => [], + (success) => success is GetDeviceContactSuggestionsSuccess + ? success.listEmailAddress + : [] + )); + } else { + return []; + } + } else { + if (_getAutoCompleteInteractor == null) { + return []; + } else { + return await _getAutoCompleteInteractor! + .execute(AutoCompletePattern(word: word, accountId: _accountId)) + .then((value) => value.fold( + (failure) => [], + (success) => success is GetAutoCompleteSuccess + ? success.listEmailAddress + : [] + )); + } + } + } + + void showFullEmailAddress(EmailRecoveryField field) { + switch (field) { + case EmailRecoveryField.recipients: + recipientsExpandMode.value = ExpandMode.EXPAND; + break; + case EmailRecoveryField.sender: + senderExpandMode.value = ExpandMode.EXPAND; + break; + default: + break; + } + } + + void updateListEmailAddress( + EmailRecoveryField field, + List listEmailAddress, + ) { + switch (field) { + case EmailRecoveryField.recipients: + listRecipients = List.from(listEmailAddress); + log('EmailRecoveryController::updateListEmailAddress(): listRecipients: ${listRecipients.first}'); + break; + case EmailRecoveryField.sender: + listSenders = List.from(listEmailAddress); + log('EmailRecoveryController::updateListEmailAddress(): listSenders: ${listSenders.first}'); + break; + default: + break; + } + } + void closeView(BuildContext context) { KeyboardUtils.hideKeyboard(context); popBack(); } + + @override + void dispose() { + focusManager.subjectFieldFocusNode.removeListener(_onSubjectFieldFocusChanged); + focusManager.recipientsFieldFocusNode.removeListener(_onRecipientsFieldFocusChanged); + focusManager.senderFieldFocusNode.removeListener(_onSenderFieldFocusChanged); + focusManager.dispose(); + super.dispose(); + } } \ No newline at end of file