diff --git a/core/lib/presentation/views/dialog/modal_list_action_button_widget.dart b/core/lib/presentation/views/dialog/modal_list_action_button_widget.dart index 48eaed6d8..38e6cb49a 100644 --- a/core/lib/presentation/views/dialog/modal_list_action_button_widget.dart +++ b/core/lib/presentation/views/dialog/modal_list_action_button_widget.dart @@ -8,6 +8,7 @@ class ModalListActionButtonWidget extends StatelessWidget { final VoidCallback onNegativeAction; final VoidCallback onPositiveAction; final EdgeInsetsGeometry? padding; + final bool isPositiveActionEnabled; const ModalListActionButtonWidget({ super.key, @@ -15,6 +16,7 @@ class ModalListActionButtonWidget extends StatelessWidget { required this.negativeLabel, required this.onPositiveAction, required this.onNegativeAction, + this.isPositiveActionEnabled = true, this.padding, }); @@ -34,9 +36,13 @@ class ModalListActionButtonWidget extends StatelessWidget { height: 48, child: ConfirmDialogButton( label: positiveLabel, - backgroundColor: AppColor.primaryMain, - textColor: Colors.white, - onTapAction: onPositiveAction, + backgroundColor: isPositiveActionEnabled + ? AppColor.primaryMain + : AppColor.profileMenuDivider.withValues(alpha: 0.12), + textColor: isPositiveActionEnabled + ? Colors.white + : AppColor.m3SurfaceBackground.withValues(alpha: 0.38), + onTapAction: isPositiveActionEnabled ? onPositiveAction : null, ), ); diff --git a/lib/features/base/mixin/handle_error_mixin.dart b/lib/features/base/mixin/handle_error_mixin.dart index 242cfdd96..2d25a5a3b 100644 --- a/lib/features/base/mixin/handle_error_mixin.dart +++ b/lib/features/base/mixin/handle_error_mixin.dart @@ -79,9 +79,13 @@ mixin HandleSetErrorMixin { } parseErrorForSetResponse(SetResponse? response, Id requestId) { - final mapError = - response?.notCreated ?? response?.notUpdated ?? response?.notDestroyed; - if (mapError != null && mapError.containsKey(requestId)) { + final mapError = { + ...?response?.notCreated, + ...?response?.notUpdated, + ...?response?.notDestroyed, + }; + + if (mapError.containsKey(requestId)) { final setError = mapError[requestId]; log('HandleSetErrorMixin::parseErrorForSetResponse():setError: $setError'); if (setError?.type == ErrorMethodResponse.invalidArguments) { diff --git a/lib/features/labels/presentation/label_controller.dart b/lib/features/labels/presentation/label_controller.dart index 0dc17cd95..ae056f734 100644 --- a/lib/features/labels/presentation/label_controller.dart +++ b/lib/features/labels/presentation/label_controller.dart @@ -1,6 +1,8 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; +import 'package:dartz/dartz.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'; @@ -9,11 +11,15 @@ import 'package:labels/model/label.dart'; import 'package:labels/utils/labels_constants.dart'; import 'package:model/mailbox/expand_mode.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; +import 'package:tmail_ui_user/features/labels/domain/state/create_new_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/get_all_label_state.dart'; +import 'package:tmail_ui_user/features/labels/domain/usecases/create_new_label_interactor.dart'; import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_label_interactor.dart'; import 'package:tmail_ui_user/features/labels/presentation/label_interactor_bindings.dart'; import 'package:tmail_ui_user/features/labels/presentation/widgets/create_new_label_modal.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; +import 'package:tmail_ui_user/main/exceptions/logic_exception.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class LabelController extends BaseController { @@ -22,6 +28,7 @@ class LabelController extends BaseController { final isCreateNewLabelModalVisible = RxBool(false); GetAllLabelInteractor? _getAllLabelInteractor; + CreateNewLabelInteractor? _createNewLabelInteractor; bool isLabelCapabilitySupported(Session session, AccountId accountId) { return LabelsConstants.labelsCapability.isSupported(session, accountId); @@ -30,6 +37,7 @@ class LabelController extends BaseController { void injectLabelsBindings() { LabelInteractorBindings().dependencies(); _getAllLabelInteractor = getBinding(); + _createNewLabelInteractor = getBinding(); } void getAllLabels(AccountId accountId) { @@ -44,7 +52,7 @@ class LabelController extends BaseController { : ExpandMode.COLLAPSE; } - Future openCreateNewLabelModal() async { + Future openCreateNewLabelModal(AccountId? accountId) async { if (PlatformInfo.isWeb) { isCreateNewLabelModalVisible.value = true; } @@ -52,7 +60,10 @@ class LabelController extends BaseController { await Get.generalDialog( barrierDismissible: true, barrierLabel: 'create-new-label-modal', - pageBuilder: (_, __, ___) => CreateNewLabelModal(labels: labels), + pageBuilder: (_, __, ___) => CreateNewLabelModal( + labels: labels, + onCreateNewLabelCallback: (label) => _createNewLabel(accountId, label), + ), ).whenComplete(() { if (PlatformInfo.isWeb) { isCreateNewLabelModalVisible.value = false; @@ -60,10 +71,41 @@ class LabelController extends BaseController { }); } + void _createNewLabel(AccountId? accountId, Label label) { + log('LabelController::_createNewLabel:Label: $label'); + if (accountId == null) { + consumeState( + Stream.value(Left(CreateNewLabelFailure(NotFoundAccountIdException()))), + ); + } else if (_createNewLabelInteractor == null) { + consumeState( + Stream.value(Left(CreateNewLabelFailure(InteractorNotInitialized()))), + ); + } else { + consumeState(_createNewLabelInteractor!.execute(accountId, label)); + } + } + + void _handleCreateNewLabelSuccess(CreateNewLabelSuccess success) { + toastManager.showMessageSuccess(success); + _addLabelToList(success.newLabel); + } + + void _handleCreateNewLabelFailure(CreateNewLabelFailure failure) { + toastManager.showMessageFailure(failure); + } + + void _addLabelToList(Label newLabel) { + labels.add(newLabel); + labels.sortByAlphabetically(); + } + @override void handleSuccessViewState(Success success) { if (success is GetAllLabelSuccess) { labels.value = success.labels..sortByAlphabetically(); + } else if (success is CreateNewLabelSuccess) { + _handleCreateNewLabelSuccess(success); } else { super.handleSuccessViewState(success); } @@ -73,6 +115,8 @@ class LabelController extends BaseController { void handleFailureViewState(Failure failure) { if (failure is GetAllLabelFailure) { labels.value = []; + } else if (failure is CreateNewLabelFailure) { + _handleCreateNewLabelFailure(failure); } else { super.handleFailureViewState(failure); } @@ -81,6 +125,7 @@ class LabelController extends BaseController { @override void onClose() { _getAllLabelInteractor = null; + _createNewLabelInteractor = null; super.onClose(); } } diff --git a/lib/features/labels/presentation/label_interactor_bindings.dart b/lib/features/labels/presentation/label_interactor_bindings.dart index 1f1384cd1..ece44b616 100644 --- a/lib/features/labels/presentation/label_interactor_bindings.dart +++ b/lib/features/labels/presentation/label_interactor_bindings.dart @@ -6,6 +6,7 @@ import 'package:tmail_ui_user/features/labels/data/datasource_impl/label_datasou import 'package:tmail_ui_user/features/labels/data/network/label_api.dart'; import 'package:tmail_ui_user/features/labels/data/repository/label_repository_impl.dart'; import 'package:tmail_ui_user/features/labels/domain/repository/label_repository.dart'; +import 'package:tmail_ui_user/features/labels/domain/usecases/create_new_label_interactor.dart'; import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_label_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; @@ -31,6 +32,7 @@ class LabelInteractorBindings extends InteractorsBindings { @override void bindingsInteractor() { Get.lazyPut(() => GetAllLabelInteractor(Get.find())); + Get.lazyPut(() => CreateNewLabelInteractor(Get.find())); Get.lazyPut(() => VerifyNameInteractor()); } diff --git a/lib/features/labels/presentation/widgets/create_new_label_modal.dart b/lib/features/labels/presentation/widgets/create_new_label_modal.dart index cef725273..1b0b077b2 100644 --- a/lib/features/labels/presentation/widgets/create_new_label_modal.dart +++ b/lib/features/labels/presentation/widgets/create_new_label_modal.dart @@ -11,13 +11,11 @@ import 'package:core/presentation/views/dialog/modal_list_action_button_widget.d import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:labels/extensions/list_label_extension.dart'; -import 'package:labels/model/label.dart'; +import 'package:labels/labels.dart'; import 'package:tmail_ui_user/features/base/widget/label_input_field_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/duplicate_name_validator.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/empty_name_validator.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/name_with_space_only_validator.dart'; -import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/special_character_validator.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/validator.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/state/verify_name_view_state.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; @@ -25,10 +23,17 @@ import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/v import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +typedef OnCreateNewLabelCallback = Function(Label label); + class CreateNewLabelModal extends StatefulWidget { final List