Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdds batch label-to-email functionality across the stack: new API/data-source/repository method addListLabelToListEmail, domain states for loading/success/partial-failure/failure, an interactor AddListLabelToListEmailsInteractor, presentation mixins/widgets (ChooseLabelModal, mailbox/dashboard/controller extensions and bindings), label UI updates (LabelListItem, TopBarThreadSelection), localization entries, toast handling, and a model extension to generate batch patch objects. Several datasource implementations remain unimplemented (throw UnimplementedError) and network/data-source wiring delegates to the new EmailAPI method. Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@lib/features/mailbox/presentation/widgets/labels/label_list_item.dart`:
- Around line 202-224: Rename the misspelled parameter/field onSelectAcion to
onSelectAction in the _SelectedIcon StatelessWidget: update the final field
declaration, the constructor parameter (and its required named parameter), and
the usage passed to TMailButtonWidget.fromIcon (onTapActionCallback) so all
references match the new onSelectAction name; ensure constructor callers (where
_SelectedIcon is instantiated) are updated to use the corrected named parameter
as well.
In `@lib/main/utils/toast_manager.dart`:
- Around line 325-327: The current toast branch treats
AddListLabelsToListEmailsHasSomeFailure the same as full
AddListLabelsToListEmailsSuccess, which shows a misleading full-success message;
in the toast assignment logic in toast_manager.dart update the conditional
handling for AddListLabelsToListEmailsHasSomeFailure so it uses a distinct
partial-failure localization key (e.g.
appLocalizations.addListLabelToListEmailPartiallyFailedMessage) or falls back to
the failure message (e.g.
appLocalizations.addListLabelToListEmailFailureMessage) instead of
appLocalizations.addListLabelToListEmailSuccessfullyMessage; adjust the branch
that checks success is AddListLabelsToListEmailsSuccess ||
AddListLabelsToListEmailsHasSomeFailure to differentiate the two cases and
ensure the appropriate message is selected.
In `@model/lib/extensions/list_email_id_extension.dart`:
- Around line 66-75: The function generateMapUpdateObjectListLabel currently
emits duplicate keys (emailId.id) for each KeyWordIdentifier so only the last
keyword survives; fix it by building a single PatchObject per email: iterate
over each emailId in this, create a combined map of keyword patch entries (use
the same key format you expect, e.g.
'${PatchObject.keywordsProperty}/${key.value}'), set each entry to remove ? null
: true, then assign result[emailId.id] = PatchObject(combinedMap) and return the
result map; update references to labelKeywords and the remove flag accordingly
so all keywords for an email are merged instead of overwritten.
🧹 Nitpick comments (4)
lib/features/email/domain/state/labels/add_list_label_to_list_email_state.dart (1)
23-30: Consider overridingpropsto distinguish from the parent state.
AddListLabelsToListEmailsHasSomeFailureinheritspropsfromAddListLabelsToListEmailsSuccess, so Equatable treats instances with the same data as equal regardless of type. If any downstream state deduplication (e.g.,distinct()on streams) is applied, a partial-failure event could be dropped after a full-success event with the same payload. Adding a discriminator topropswould make the distinction explicit.♻️ Proposed fix
class AddListLabelsToListEmailsHasSomeFailure extends AddListLabelsToListEmailsSuccess { AddListLabelsToListEmailsHasSomeFailure( super.emailIds, super.labelKeywords, super.labelDisplays, ); + + `@override` + List<Object> get props => [...super.props, 'hasSomeFailure']; }lib/features/mailbox/presentation/widgets/labels/label_list_item.dart (1)
104-115: Verify: extra space beforeAppColor.primaryMainon Line 109.Minor formatting inconsistency — there are two spaces before the
?ternary operator on Line 109. Not a functional issue.? AppColor.primaryMainvs the line above:
? widget.imagePaths.icCheckboxSelectedlib/features/labels/presentation/widgets/choose_label_modal.dart (1)
169-180: Consider using aSetfor selected labels to improve toggle performance and clarity.Using a
List<Label>and callingcontains+whereon every toggle is O(n). ASet<Label>(orSetkeyed by label id) would be more idiomatic for a selection model. This is minor for typical label list sizes.lib/features/labels/presentation/mixin/add_list_labels_to_list_emails_mixin.dart (1)
160-170: Misleading parameter namesuccessfor a partial-failure state.The parameter
AddListLabelsToListEmailsHasSomeFailure successreads oddly since the type represents a partial failure. Consider renaming topartialFailureorhasSomeFailurefor clarity.Suggested rename
void _handleAddListLabelsToListEmailsHasSomeFailure( - AddListLabelsToListEmailsHasSomeFailure success, + AddListLabelsToListEmailsHasSomeFailure hasSomeFailure, ) { - currentToastManager.showMessageSuccess(success); + currentToastManager.showMessageSuccess(hasSomeFailure); onSyncListLabelForListEmail?.call( - success.emailIds, - success.labelKeywords, + hasSomeFailure.emailIds, + hasSomeFailure.labelKeywords, shouldRemove: false, ); }
|
This PR has been deployed to https://linagora.github.io/tmail-flutter/4319. |
…between ‘Move’ and ‘Mark as spam’ action
a70e1ad to
08d2a8c
Compare
| bool value, | ||
| ) { | ||
| if (value) { | ||
| presentationEmail.keywords?[keyword] = true; |
There was a problem hiding this comment.
should check in case no keywords exist?
| void dependencies() { | ||
| Get.lazyPut(() => AddALabelToAnEmailInteractor(_emailRepository)); | ||
| Get.lazyPut(() => RemoveALabelFromAnEmailInteractor(_emailRepository)); | ||
| Get.put(AddListLabelToListEmailsInteractor(_emailRepository)); |
|
|
||
| String get addListLabelToListEmailSuccessfullyMessage { | ||
| return Intl.message( | ||
| 'Labels have been successfully added to these emails.', |
There was a problem hiding this comment.
message here and message at addListLabelToListEmailHasSomeFailureMessage are the same, maybe make user confused
chibenwa
left a comment
There was a problem hiding this comment.
I disagree with this change which denotes clear misdesign of the overall application
For the record... |
Split into 2:
A new approach is in #4431 |
|
Please @tddang-linagora explain this new approach and why it shall be prefered. Which difference with this work? Thanks by advance! |
Instead of creating a mixin but inject a lot of information into it making it tightly coupled, my approach is like extending the capability of an existing feature without modify the code inside it, typical open-closed. It is fully testable, minimal dependency, and single responsibility. You can add endless feature to a core functionality this way. |
Ok And part one is the refactoring? Part 2 the implem? |
yes exactly. |
|
@dab246 opinion on approach 2? If this is concensual then I have no problem to move forward with approach 2. |
IMO, approach 2 doesn't significantly reduce the amount of code and file changes for this issue. Approach 2 simply uses a controller instead of a mixin, but we still have to manage it, initialize it before use, and release it when not in use. Nevertheless, approach 2 is still worth considering, and we can continue with that approach. |




Issue
#4308
Resolved
Screen.Recording.2026-02-09.at.16.46.27.mov
Summary by CodeRabbit
New Features
UI/UX Improvements