TF-4243 Implement delete a label in presentation layer

This commit is contained in:
dab246
2026-01-12 15:58:53 +07:00
committed by Dat H. Pham
parent 327d05d20b
commit 9760b6f077
11 changed files with 144 additions and 9 deletions
@@ -1,15 +1,16 @@
import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:labels/model/label.dart';
class DeletingALabel extends LoadingState {} class DeletingALabel extends LoadingState {}
class DeleteALabelSuccess extends UIState { class DeleteALabelSuccess extends UIState {
final String labelDisplayName; final Label deletedLabel;
DeleteALabelSuccess(this.labelDisplayName); DeleteALabelSuccess(this.deletedLabel);
@override @override
List<Object> get props => [labelDisplayName]; List<Object> get props => [deletedLabel];
} }
class DeleteALabelFailure extends FeatureFailure { class DeleteALabelFailure extends FeatureFailure {
@@ -2,7 +2,6 @@ import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/model/label.dart'; import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/labels/domain/repository/label_repository.dart'; import 'package:tmail_ui_user/features/labels/domain/repository/label_repository.dart';
import 'package:tmail_ui_user/features/labels/domain/state/delete_a_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/delete_a_label_state.dart';
@@ -18,8 +17,8 @@ class DeleteALabelInteractor {
) async* { ) async* {
try { try {
yield Right(DeletingALabel()); yield Right(DeletingALabel());
await _labelRepository.createNewLabel(accountId, label); await _labelRepository.deleteLabel(accountId, label);
yield Right(DeleteALabelSuccess(label.safeDisplayName)); yield Right(DeleteALabelSuccess(label));
} catch (e) { } catch (e) {
yield Left(DeleteALabelFailure(e)); yield Left(DeleteALabelFailure(e));
} }
@@ -1,21 +1,28 @@
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/extensions/list_label_extension.dart'; import 'package:labels/extensions/list_label_extension.dart';
import 'package:labels/model/label.dart'; import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
import 'package:tmail_ui_user/features/labels/domain/exceptions/label_exceptions.dart'; import 'package:tmail_ui_user/features/labels/domain/exceptions/label_exceptions.dart';
import 'package:tmail_ui_user/features/labels/domain/model/edit_label_request.dart'; import 'package:tmail_ui_user/features/labels/domain/model/edit_label_request.dart';
import 'package:tmail_ui_user/features/labels/domain/state/delete_a_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart';
import 'package:tmail_ui_user/features/labels/presentation/label_controller.dart'; import 'package:tmail_ui_user/features/labels/presentation/label_controller.dart';
import 'package:tmail_ui_user/features/labels/presentation/models/label_action_type.dart'; import 'package:tmail_ui_user/features/labels/presentation/models/label_action_type.dart';
import 'package:tmail_ui_user/features/labels/presentation/widgets/create_new_label_modal.dart'; import 'package:tmail_ui_user/features/labels/presentation/widgets/create_new_label_modal.dart';
import 'package:tmail_ui_user/main/exceptions/logic_exception.dart'; import 'package:tmail_ui_user/main/exceptions/logic_exception.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/dialog_router.dart'; import 'package:tmail_ui_user/main/routes/dialog_router.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleLabelActionTypeExtension on LabelController { extension HandleLabelActionTypeExtension on LabelController {
void handleLabelActionType({ void handleLabelActionType({
required BuildContext context,
required LabelActionType actionType, required LabelActionType actionType,
required AccountId? accountId, required AccountId? accountId,
Label? label, Label? label,
@@ -29,6 +36,12 @@ extension HandleLabelActionTypeExtension on LabelController {
openEditLabelModal(accountId: accountId, label: label); openEditLabelModal(accountId: accountId, label: label);
break; break;
case LabelActionType.delete: case LabelActionType.delete:
if (label == null) return;
_openDeleteLabelModal(
context: context,
accountId: accountId,
label: label,
);
break; break;
} }
} }
@@ -109,4 +122,61 @@ extension HandleLabelActionTypeExtension on LabelController {
labels.add(newLabel); labels.add(newLabel);
labels.sortByAlphabetically(); labels.sortByAlphabetically();
} }
Future<void> _openDeleteLabelModal({
required BuildContext context,
required AccountId? accountId,
required Label label,
}) async {
final appLocalizations = AppLocalizations.of(context);
MessageDialogActionManager().showConfirmDialogAction(
context,
appLocalizations.areYouSureYouWantToDeleteTheLabel(label.safeDisplayName),
appLocalizations.delete,
key: const Key('confirm_dialog_delete_label'),
title: appLocalizations.deleteLabel,
cancelTitle: appLocalizations.cancel,
onConfirmAction: () => _deleteLabel(accountId: accountId, label: label),
onCloseButtonAction: popBack,
alignCenter: true,
dialogMargin: MediaQuery.paddingOf(context).add(
const EdgeInsets.only(bottom: 12),
),
);
}
void _deleteLabel({
required AccountId? accountId,
required Label label,
}) {
log('LabelController::deleteLabel:label: $label');
if (accountId == null) {
emitFailure(
controller: this,
failure: DeleteALabelFailure(NotFoundAccountIdException()),
);
} else if (deleteALabelInteractor == null) {
emitFailure(
controller: this,
failure: DeleteALabelFailure(InteractorNotInitialized()),
);
} else {
consumeState(deleteALabelInteractor!.execute(accountId, label));
}
}
void handleDeleteLabelSuccess(DeleteALabelSuccess success) {
toastManager.showMessageSuccess(success);
syncListLabelsAfterDelete(success.deletedLabel);
}
void handleDeleteLabelFailure(DeleteALabelFailure failure) {
toastManager.showMessageFailure(failure);
}
void syncListLabelsAfterDelete(Label deletedLabel) {
labels.removeWhere((label) => label.id == deletedLabel.id);
labels.sortByAlphabetically();
}
} }
@@ -13,9 +13,11 @@ 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/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/create_new_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/delete_a_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/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/create_new_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart'; import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/delete_a_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_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/extensions/handle_label_action_type_extension.dart'; import 'package:tmail_ui_user/features/labels/presentation/extensions/handle_label_action_type_extension.dart';
import 'package:tmail_ui_user/features/labels/presentation/label_interactor_bindings.dart'; import 'package:tmail_ui_user/features/labels/presentation/label_interactor_bindings.dart';
@@ -37,6 +39,7 @@ class LabelController extends BaseController with LabelContextMenuMixin {
CreateNewLabelInteractor? _createNewLabelInteractor; CreateNewLabelInteractor? _createNewLabelInteractor;
GetLabelSettingStateInteractor? _getLabelSettingStateInteractor; GetLabelSettingStateInteractor? _getLabelSettingStateInteractor;
EditLabelInteractor? _editLabelInteractor; EditLabelInteractor? _editLabelInteractor;
DeleteALabelInteractor? _deleteALabelInteractor;
bool isLabelCapabilitySupported(Session session, AccountId accountId) { bool isLabelCapabilitySupported(Session session, AccountId accountId) {
return LabelsConstants.labelsCapability.isSupported(session, accountId); return LabelsConstants.labelsCapability.isSupported(session, accountId);
@@ -62,10 +65,13 @@ class LabelController extends BaseController with LabelContextMenuMixin {
_getAllLabelInteractor = getBinding<GetAllLabelInteractor>(); _getAllLabelInteractor = getBinding<GetAllLabelInteractor>();
_createNewLabelInteractor = getBinding<CreateNewLabelInteractor>(); _createNewLabelInteractor = getBinding<CreateNewLabelInteractor>();
_editLabelInteractor = getBinding<EditLabelInteractor>(); _editLabelInteractor = getBinding<EditLabelInteractor>();
_deleteALabelInteractor = getBinding<DeleteALabelInteractor>();
} }
EditLabelInteractor? get editLabelInteractor => _editLabelInteractor; EditLabelInteractor? get editLabelInteractor => _editLabelInteractor;
DeleteALabelInteractor? get deleteALabelInteractor => _deleteALabelInteractor;
void getAllLabels(AccountId accountId) { void getAllLabels(AccountId accountId) {
if (_getAllLabelInteractor == null) return; if (_getAllLabelInteractor == null) return;
@@ -139,6 +145,8 @@ class LabelController extends BaseController with LabelContextMenuMixin {
_handleGetLabelSettingStateSuccess(success.isEnabled, success.accountId); _handleGetLabelSettingStateSuccess(success.isEnabled, success.accountId);
} else if (success is EditLabelSuccess) { } else if (success is EditLabelSuccess) {
handleEditLabelSuccess(success); handleEditLabelSuccess(success);
} else if (success is DeleteALabelSuccess) {
handleDeleteLabelSuccess(success);
} else { } else {
super.handleSuccessViewState(success); super.handleSuccessViewState(success);
} }
@@ -155,6 +163,8 @@ class LabelController extends BaseController with LabelContextMenuMixin {
_clearLabelData(); _clearLabelData();
} else if (failure is EditLabelFailure) { } else if (failure is EditLabelFailure) {
handleEditLabelFailure(failure); handleEditLabelFailure(failure);
} else if (failure is DeleteALabelFailure) {
handleDeleteLabelFailure(failure);
} else { } else {
super.handleFailureViewState(failure); super.handleFailureViewState(failure);
} }
@@ -165,6 +175,7 @@ class LabelController extends BaseController with LabelContextMenuMixin {
_getAllLabelInteractor = null; _getAllLabelInteractor = null;
_createNewLabelInteractor = null; _createNewLabelInteractor = null;
_editLabelInteractor = null; _editLabelInteractor = null;
_deleteALabelInteractor = null;
_getLabelSettingStateInteractor = null; _getLabelSettingStateInteractor = null;
super.onClose(); super.onClose();
} }
@@ -8,6 +8,7 @@ import 'package:tmail_ui_user/features/labels/data/repository/label_repository_i
import 'package:tmail_ui_user/features/labels/domain/repository/label_repository.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/create_new_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart'; import 'package:tmail_ui_user/features/labels/domain/usecases/edit_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/delete_a_label_interactor.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/get_all_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/features/mailbox_creator/domain/usecases/verify_name_interactor.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
@@ -35,6 +36,7 @@ class LabelInteractorBindings extends InteractorsBindings {
Get.lazyPut(() => GetAllLabelInteractor(Get.find<LabelRepository>())); Get.lazyPut(() => GetAllLabelInteractor(Get.find<LabelRepository>()));
Get.lazyPut(() => CreateNewLabelInteractor(Get.find<LabelRepository>())); Get.lazyPut(() => CreateNewLabelInteractor(Get.find<LabelRepository>()));
Get.lazyPut(() => EditLabelInteractor(Get.find<LabelRepository>())); Get.lazyPut(() => EditLabelInteractor(Get.find<LabelRepository>()));
Get.lazyPut(() => DeleteALabelInteractor(Get.find<LabelRepository>()));
Get.lazyPut(() => VerifyNameInteractor()); Get.lazyPut(() => VerifyNameInteractor());
} }
@@ -380,6 +380,7 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
onToggleLabelListState: labelController.toggleLabelListState, onToggleLabelListState: labelController.toggleLabelListState,
onAddNewLabel: () => onAddNewLabel: () =>
labelController.handleLabelActionType( labelController.handleLabelActionType(
context: context,
actionType: LabelActionType.create, actionType: LabelActionType.create,
accountId: accountId, accountId: accountId,
), ),
@@ -22,7 +22,11 @@ extension HandleLabelActionTypeExtension on MailboxDashBoardController {
imagePaths, imagePaths,
label, label,
position: position, position: position,
_onPerformLabelActionType, (label, actionType) => _onPerformLabelActionType(
context: context,
label: label,
actionType: actionType,
),
); );
} finally { } finally {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
@@ -31,8 +35,13 @@ extension HandleLabelActionTypeExtension on MailboxDashBoardController {
} }
} }
void _onPerformLabelActionType(Label label, LabelActionType actionType) { void _onPerformLabelActionType({
required BuildContext context,
required Label label,
required LabelActionType actionType,
}) {
labelController.handleLabelActionType( labelController.handleLabelActionType(
context: context,
actionType: actionType, actionType: actionType,
accountId: accountId.value, accountId: accountId.value,
label: label, label: label,
@@ -48,7 +57,11 @@ extension HandleLabelActionTypeExtension on MailboxDashBoardController {
context, context,
imagePaths, imagePaths,
label, label,
_onPerformLabelActionType, (label, actionType) => _onPerformLabelActionType(
context: context,
label: label,
actionType: actionType,
),
); );
} }
} }
+16
View File
@@ -5437,5 +5437,21 @@
"placeholders": { "placeholders": {
"labelName": {} "labelName": {}
} }
},
"deleteLabelSuccessfullyMessage": "You successfully deleted the {labelName} label",
"@deleteLabelSuccessfullyMessage": {
"type": "text",
"placeholders_order": [
"labelName"
],
"placeholders": {
"labelName": {}
}
},
"deleteALabelFailure": "Delete a label failure",
"@deleteALabelFailure": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
} }
} }
@@ -5754,4 +5754,19 @@ class AppLocalizations {
args: [labelName], args: [labelName],
); );
} }
String deleteLabelSuccessfullyMessage(String labelName) {
return Intl.message(
'You successfully deleted the $labelName label',
name: 'deleteLabelSuccessfullyMessage',
args: [labelName],
);
}
String get deleteALabelFailure {
return Intl.message(
'Delete a label failure',
name: 'deleteALabelFailure',
);
}
} }
+7
View File
@@ -34,6 +34,7 @@ import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.d
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart'; import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/create_new_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/create_new_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart'; import 'package:tmail_ui_user/features/labels/domain/state/edit_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/state/delete_a_label_state.dart';
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart';
import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart';
@@ -224,6 +225,8 @@ class ToastManager {
appLocalizations.removeLabelFromThreadFailureMessage( appLocalizations.removeLabelFromThreadFailureMessage(
failure.labelDisplay, failure.labelDisplay,
); );
} else if (failure is DeleteALabelFailure) {
message = message ?? appLocalizations.deleteALabelFailure;
} }
log('ToastManager::showMessageFailure: Message: $message'); log('ToastManager::showMessageFailure: Message: $message');
if (message?.trim().isNotEmpty == true) { if (message?.trim().isNotEmpty == true) {
@@ -311,6 +314,10 @@ class ToastManager {
message = appLocalizations.removeLabelFromThreadSuccessfullyMessage( message = appLocalizations.removeLabelFromThreadSuccessfullyMessage(
success.labelDisplay, success.labelDisplay,
); );
} else if (success is DeleteALabelSuccess) {
message = appLocalizations.deleteLabelSuccessfullyMessage(
success.deletedLabel.safeDisplayName,
);
} }
log('ToastManager::showMessageSuccess: Message: $message'); log('ToastManager::showMessageSuccess: Message: $message');
if (message?.trim().isNotEmpty == true) { if (message?.trim().isNotEmpty == true) {