TF-4301 Add "Create a new label" button in Label As menus and wire up tagging in email view

This commit is contained in:
dab246
2026-02-04 13:53:01 +07:00
committed by Dat H. Pham
parent 061793846e
commit 190ccc7bc3
29 changed files with 600 additions and 247 deletions
@@ -1,6 +1,4 @@
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:labels/extensions/label_extension.dart';
@@ -8,112 +6,79 @@ import 'package:labels/extensions/list_label_extension.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/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/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/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/widgets/create_new_label_modal.dart';
import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.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/route_navigation.dart';
extension HandleLabelActionTypeExtension on LabelController {
void handleLabelActionType({
required BuildContext context,
required LabelActionType actionType,
required AccountId? accountId,
Label? label,
OnLabelActionCallback? onLabelActionCallback,
}) {
switch (actionType) {
case LabelActionType.create:
openCreateNewLabelModal(accountId);
onCreateALabelAction(
accountId: accountId,
onLabelActionCallback: onLabelActionCallback,
);
break;
case LabelActionType.edit:
if (label == null) return;
openEditLabelModal(accountId: accountId, label: label);
onEditLabelAction(accountId: accountId, label: label);
break;
case LabelActionType.delete:
if (label == null) return;
_openDeleteLabelModal(
context: context,
accountId: accountId,
label: label,
);
_openDeleteLabelModal(accountId: accountId, label: label);
break;
}
}
Future<void> openEditLabelModal({
Future<void> onEditLabelAction({
required AccountId? accountId,
required Label label,
}) async {
if (accountId == null) {
consumeState(
Stream.value(Left(EditLabelFailure(NotFoundAccountIdException()))),
);
if (createNewLabelInteractor == null || editLabelInteractor == null) {
_handleEditLabelFailure(EditLabelFailure(const InteractorNotInitialized()));
return;
}
final verifyNameInteractor = getBinding<VerifyNameInteractor>();
if (verifyNameInteractor == null) {
_handleEditLabelFailure(EditLabelFailure(const InteractorNotInitialized()));
return;
}
await DialogRouter().openDialogModal(
child: CreateNewLabelModal(
key: const Key('edit_label_modal'),
labels: labels,
selectedLabel: label,
actionType: LabelActionType.edit,
onLabelActionCallback: (newLabel) =>
editLabel(
accountId: accountId,
selectedLabel: label,
newLabel: newLabel,
),
),
dialogLabel: 'edit-label-modal',
);
}
void editLabel({
required AccountId? accountId,
required Label selectedLabel,
required Label newLabel,
}) {
log('LabelController::editLabel:selectedLabel: $selectedLabel, newLabel: $newLabel');
if (accountId == null) {
consumeState(
Stream.value(Left(EditLabelFailure(NotFoundAccountIdException()))),
);
} else if (editLabelInteractor == null) {
consumeState(
Stream.value(Left(EditLabelFailure(const InteractorNotInitialized()))),
);
} else {
final labelId = selectedLabel.id;
_handleEditLabelFailure(EditLabelFailure(NotFoundAccountIdException()));
return;
}
if (labelId == null) {
consumeState(
Stream.value(Left(EditLabelFailure(const LabelIdIsNull()))),
);
return;
}
final resultState = await openEditLabelModal(
selectedLabel: label,
accountId: accountId,
verifyNameInteractor: verifyNameInteractor,
);
final labelRequest = EditLabelRequest(
labelId: labelId,
labelKeyword: selectedLabel.keyword,
newLabel: newLabel,
);
consumeState(editLabelInteractor!.execute(accountId, labelRequest));
if (resultState is EditLabelSuccess) {
_handleEditLabelSuccess(resultState);
} else if (resultState is EditLabelFailure) {
_handleEditLabelFailure(resultState);
}
}
void handleEditLabelSuccess(EditLabelSuccess success) {
void _handleEditLabelSuccess(EditLabelSuccess success) {
toastManager.showMessageSuccess(success);
syncListLabels(success.newLabel);
}
void handleEditLabelFailure(EditLabelFailure failure) {
void _handleEditLabelFailure(EditLabelFailure failure) {
toastManager.showMessageFailure(failure);
}
@@ -124,10 +89,12 @@ extension HandleLabelActionTypeExtension on LabelController {
}
Future<void> _openDeleteLabelModal({
required BuildContext context,
required AccountId? accountId,
required Label label,
}) async {
final context = currentContext;
if (context == null) return;
final appLocalizations = AppLocalizations.of(context);
MessageDialogActionManager().showConfirmDialogAction(