TF-4195 Fix comments of coderabbit
This commit is contained in:
@@ -206,7 +206,7 @@ void main() {
|
|||||||
expect(parsed.notFound, isEmpty);
|
expect(parsed.notFound, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should throw DioException when server returns 500', () async {
|
test('should throw DioError when server returns 500', () async {
|
||||||
// Arrange
|
// Arrange
|
||||||
final dio = createDio();
|
final dio = createDio();
|
||||||
final adapter = DioAdapter(dio: dio);
|
final adapter = DioAdapter(dio: dio);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void main() {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(parsed, isNotNull);
|
expect(parsed, isNotNull);
|
||||||
expect(parsed!.created![Id('4f29')]!.keyword, equals('important'));
|
expect(parsed!.created![Id('4f29')]!.keyword?.value, equals('important'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should process multiple created labels', () async {
|
test('should process multiple created labels', () async {
|
||||||
@@ -143,8 +143,8 @@ void main() {
|
|||||||
// Assert
|
// Assert
|
||||||
expect(parsed, isNotNull);
|
expect(parsed, isNotNull);
|
||||||
expect(parsed!.created!.length, equals(2));
|
expect(parsed!.created!.length, equals(2));
|
||||||
expect(parsed.created![Id('A')]!.keyword, equals('tagA'));
|
expect(parsed.created![Id('A')]!.keyword?.value, equals('tagA'));
|
||||||
expect(parsed.created![Id('B')]!.keyword, equals('tagB'));
|
expect(parsed.created![Id('B')]!.keyword?.value, equals('tagB'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should throw DioException when backend returns 500', () async {
|
test('should throw DioException when backend returns 500', () async {
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
class HoverSubmenuController {
|
||||||
|
HoverSubmenuController({
|
||||||
|
this.exitDelay = const Duration(milliseconds: 120),
|
||||||
|
});
|
||||||
|
|
||||||
|
final Duration exitDelay;
|
||||||
|
|
||||||
|
final ValueNotifier<bool> isHovering = ValueNotifier(false);
|
||||||
|
|
||||||
|
int _hoverRefCount = 0;
|
||||||
|
Timer? _exitTimer;
|
||||||
|
|
||||||
|
void enter() {
|
||||||
|
_exitTimer?.cancel();
|
||||||
|
_hoverRefCount++;
|
||||||
|
if (!isHovering.value) {
|
||||||
|
isHovering.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit() {
|
||||||
|
_hoverRefCount = (_hoverRefCount - 1).clamp(0, 999);
|
||||||
|
|
||||||
|
if (_hoverRefCount == 0) {
|
||||||
|
_exitTimer?.cancel();
|
||||||
|
_exitTimer = Timer(exitDelay, () {
|
||||||
|
if (_hoverRefCount == 0) {
|
||||||
|
isHovering.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_exitTimer?.cancel();
|
||||||
|
isHovering.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
|||||||
child: PopupMenuItemActionWidget(
|
child: PopupMenuItemActionWidget(
|
||||||
menuAction: menuAction,
|
menuAction: menuAction,
|
||||||
menuActionClick: (menuAction) {
|
menuActionClick: (menuAction) {
|
||||||
|
submenuController?.hide();
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
onActionSelected(menuAction);
|
onActionSelected(menuAction);
|
||||||
},
|
},
|
||||||
@@ -60,7 +61,11 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return openPopupMenuAction(context, position, popupMenuItems);
|
try {
|
||||||
|
await openPopupMenuAction(context, position, popupMenuItems);
|
||||||
|
} finally {
|
||||||
|
submenuController?.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showPopupSubmenu({
|
void _showPopupSubmenu({
|
||||||
@@ -69,8 +74,9 @@ class PopupMenuActionGroupWidget with PopupContextMenuActionMixin {
|
|||||||
required PopupSubmenuController submenuController,
|
required PopupSubmenuController submenuController,
|
||||||
required Widget submenu,
|
required Widget submenu,
|
||||||
}) {
|
}) {
|
||||||
final renderBox = itemKey.currentContext?.findRenderObject() as RenderBox?;
|
final renderObject = itemKey.currentContext?.findRenderObject();
|
||||||
if (renderBox == null) return;
|
if (renderObject is! RenderBox) return;
|
||||||
|
final renderBox = renderObject;
|
||||||
|
|
||||||
final offset = renderBox.localToGlobal(Offset.zero);
|
final offset = renderBox.localToGlobal(Offset.zero);
|
||||||
final rect = offset & renderBox.size;
|
final rect = offset & renderBox.size;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:model/email/email_action_type.dart';
|
import 'package:model/email/email_action_type.dart';
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
import 'package:tmail_ui_user/features/base/model/popup_menu_item_action.dart';
|
import 'package:tmail_ui_user/features/base/model/popup_menu_item_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/popup_menu/hover_submenu_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
|
||||||
|
|
||||||
class PopupMenuItemActionWidget extends StatefulWidget {
|
class PopupMenuItemActionWidget extends StatefulWidget {
|
||||||
@@ -28,14 +29,15 @@ class PopupMenuItemActionWidget extends StatefulWidget {
|
|||||||
|
|
||||||
class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
||||||
GlobalKey? _itemKey;
|
GlobalKey? _itemKey;
|
||||||
ValueNotifier<bool>? _hoverItemNotifier;
|
HoverSubmenuController? _hoverController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (widget.menuAction is PopupMenuItemEmailAction) {
|
if (widget.menuAction is PopupMenuItemEmailAction &&
|
||||||
|
widget.menuAction.action == EmailActionType.labelAs) {
|
||||||
_itemKey = GlobalKey();
|
_itemKey = GlobalKey();
|
||||||
_hoverItemNotifier = ValueNotifier(false);
|
_hoverController = HoverSubmenuController();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +135,8 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
|||||||
return PointerInterceptor(
|
return PointerInterceptor(
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
onEnter: (_) {
|
onEnter: (_) {
|
||||||
if (_hoverItemNotifier != null) {
|
_hoverController?.enter();
|
||||||
_hoverItemNotifier?.value = true;
|
|
||||||
}
|
|
||||||
if (_itemKey != null) {
|
if (_itemKey != null) {
|
||||||
widget.onHoverShowSubmenu?.call(_itemKey!);
|
widget.onHoverShowSubmenu?.call(_itemKey!);
|
||||||
} else {
|
} else {
|
||||||
@@ -143,9 +144,7 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onExit: (_) {
|
onExit: (_) {
|
||||||
if (_hoverItemNotifier != null) {
|
_hoverController?.exit();
|
||||||
_hoverItemNotifier?.value = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: Material(
|
child: Material(
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
@@ -172,26 +171,23 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
|||||||
),
|
),
|
||||||
if (isSelected && selectedIconWidget != null)
|
if (isSelected && selectedIconWidget != null)
|
||||||
selectedIconWidget,
|
selectedIconWidget,
|
||||||
if (_hoverItemNotifier != null)
|
if (_hoverController != null)
|
||||||
ValueListenableBuilder(
|
ValueListenableBuilder(
|
||||||
valueListenable: _hoverItemNotifier!,
|
valueListenable: _hoverController!.isHovering,
|
||||||
builder: (_, value, __) {
|
builder: (_, isHovering, __) {
|
||||||
if (value) {
|
if (!isHovering) return const SizedBox.shrink();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsetsDirectional.only(start: 16),
|
const EdgeInsetsDirectional.only(start: 16),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
specificMenuAction.hoverIcon,
|
specificMenuAction.hoverIcon,
|
||||||
width: specificMenuAction.hoverIconSize,
|
width: specificMenuAction.hoverIconSize,
|
||||||
height: specificMenuAction.hoverIconSize,
|
height: specificMenuAction.hoverIconSize,
|
||||||
colorFilter: specificMenuAction.hoverIconColor
|
colorFilter: specificMenuAction.hoverIconColor
|
||||||
.asFilter(),
|
.asFilter(),
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -210,9 +206,7 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
|||||||
onTap: () => widget.menuAction.onClick(widget.menuActionClick),
|
onTap: () => widget.menuAction.onClick(widget.menuActionClick),
|
||||||
hoverColor: AppColor.popupMenuItemHovered,
|
hoverColor: AppColor.popupMenuItemHovered,
|
||||||
onHover: (_) {
|
onHover: (_) {
|
||||||
if (_hoverItemNotifier != null) {
|
_hoverController?.exit();
|
||||||
_hoverItemNotifier?.value = false;
|
|
||||||
}
|
|
||||||
widget.onHoverOtherItem?.call();
|
widget.onHoverOtherItem?.call();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -245,9 +239,9 @@ class _PopupMenuItemActionWidgetState extends State<PopupMenuItemActionWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_hoverItemNotifier != null) {
|
if (_hoverController != null) {
|
||||||
_hoverItemNotifier?.dispose();
|
_hoverController?.dispose();
|
||||||
_hoverItemNotifier = null;
|
_hoverController = null;
|
||||||
}
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
enum SubmenuDirection { left, right, auto }
|
enum SubmenuDirection { left, right, auto }
|
||||||
@@ -18,7 +20,12 @@ class PopupSubmenuController {
|
|||||||
}) {
|
}) {
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final overlayState = Overlay.maybeOf(context, rootOverlay: true);
|
||||||
|
if (overlayState == null) return;
|
||||||
|
|
||||||
|
final mediaSize = MediaQuery.sizeOf(context);
|
||||||
|
final screenWidth = mediaSize.width;
|
||||||
|
final screenHeight = mediaSize.height;
|
||||||
|
|
||||||
final rightPosition = anchor.right + offset;
|
final rightPosition = anchor.right + offset;
|
||||||
final leftPosition = anchor.left - submenuWidth - offset;
|
final leftPosition = anchor.left - submenuWidth - offset;
|
||||||
@@ -42,10 +49,16 @@ class PopupSubmenuController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final clampedLeft = finalLeft
|
||||||
|
.clamp(0.0, math.max(0.0, screenWidth - submenuWidth))
|
||||||
|
.toDouble();
|
||||||
|
final availableHeight = math.max(0.0, screenHeight - anchor.top);
|
||||||
|
final finalHeight = math.min(submenuMaxHeight, availableHeight);
|
||||||
|
|
||||||
_submenuEntry = OverlayEntry(
|
_submenuEntry = OverlayEntry(
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return PositionedDirectional(
|
return PositionedDirectional(
|
||||||
start: finalLeft,
|
start: clampedLeft,
|
||||||
top: anchor.top,
|
top: anchor.top,
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
onExit: (_) => hide(),
|
onExit: (_) => hide(),
|
||||||
@@ -57,7 +70,7 @@ class PopupSubmenuController {
|
|||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: submenuWidth,
|
width: submenuWidth,
|
||||||
height: submenuMaxHeight,
|
height: finalHeight,
|
||||||
child: submenu,
|
child: submenu,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -66,7 +79,7 @@ class PopupSubmenuController {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Overlay.maybeOf(context)?.insert(_submenuEntry!);
|
overlayState.insert(_submenuEntry!);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hide() {
|
void hide() {
|
||||||
|
|||||||
@@ -55,12 +55,14 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final iframeOverlay = Obx(() {
|
final iframeOverlay = Obx(() {
|
||||||
|
final dialogRouter = DialogRouter();
|
||||||
|
|
||||||
bool isOverlayEnabled = controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame ||
|
bool isOverlayEnabled = controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame ||
|
||||||
MessageDialogActionManager().isDialogOpened ||
|
MessageDialogActionManager().isDialogOpened ||
|
||||||
EmailActionReactor.isDialogOpened ||
|
EmailActionReactor.isDialogOpened ||
|
||||||
ColorDialogPicker().isOpened.isTrue ||
|
ColorDialogPicker().isOpened.isTrue ||
|
||||||
DialogRouter().isRuleFilterDialogOpened.isTrue ||
|
dialogRouter.isRuleFilterDialogOpened.isTrue ||
|
||||||
DialogRouter().isDialogOpened;
|
dialogRouter.isDialogOpened;
|
||||||
|
|
||||||
if (isOverlayEnabled) {
|
if (isOverlayEnabled) {
|
||||||
return Positioned.fill(
|
return Positioned.fill(
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ abstract class EmailDataSource {
|
|||||||
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
||||||
|
|
||||||
Future<void> addLabelToEmail(
|
Future<void> addLabelToEmail(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
|
|||||||
@@ -556,12 +556,18 @@ class EmailDataSourceImpl extends EmailDataSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addLabelToEmail(
|
Future<void> addLabelToEmail(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
) {
|
) {
|
||||||
return Future.sync(() async {
|
return Future.sync(() async {
|
||||||
return await emailAPI.addLabelToEmail(accountId, emailId, labelKeyword);
|
return await emailAPI.addLabelToEmail(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
labelKeyword,
|
||||||
|
);
|
||||||
}).catchError(_exceptionThrower.throwException);
|
}).catchError(_exceptionThrower.throwException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -577,7 +577,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addLabelToEmail(AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
Future<void> addLabelToEmail(Session session, AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,7 +353,7 @@ class EmailLocalStorageDataSourceImpl extends EmailDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addLabelToEmail(AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
Future<void> addLabelToEmail(Session session, AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ class EmailSessionStorageDatasourceImpl extends EmailDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addLabelToEmail(AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
Future<void> addLabelToEmail(Session session, AccountId accountId, EmailId emailId, KeyWordIdentifier labelKeyword) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -938,6 +938,7 @@ class EmailAPI with HandleSetErrorMixin, MailAPIMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addLabelToEmail(
|
Future<void> addLabelToEmail(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
@@ -948,8 +949,9 @@ class EmailAPI with HandleSetErrorMixin, MailAPIMixin {
|
|||||||
final builder = JmapRequestBuilder(_httpClient, ProcessingInvocation());
|
final builder = JmapRequestBuilder(_httpClient, ProcessingInvocation());
|
||||||
final invocation = builder.invocation(method);
|
final invocation = builder.invocation(method);
|
||||||
|
|
||||||
final result =
|
final capabilities = method.requiredCapabilities
|
||||||
await (builder..usings(method.requiredCapabilities)).build().execute();
|
.toCapabilitiesSupportTeamMailboxes(session, accountId);
|
||||||
|
final result = await (builder..usings(capabilities)).build().execute();
|
||||||
|
|
||||||
final response = result.parse<SetEmailResponse>(
|
final response = result.parse<SetEmailResponse>(
|
||||||
invocation.methodCallId,
|
invocation.methodCallId,
|
||||||
|
|||||||
@@ -483,11 +483,13 @@ class EmailRepositoryImpl extends EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addLabelToEmail(
|
Future<void> addLabelToEmail(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
) {
|
) {
|
||||||
return emailDataSource[DataSourceType.network]!.addLabelToEmail(
|
return emailDataSource[DataSourceType.network]!.addLabelToEmail(
|
||||||
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
emailId,
|
emailId,
|
||||||
labelKeyword,
|
labelKeyword,
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ abstract class EmailRepository {
|
|||||||
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
Future<String> generateEntireMessageAsDocument(ViewEntireMessageRequest entireMessageRequest);
|
||||||
|
|
||||||
Future<void> addLabelToEmail(
|
Future<void> addLabelToEmail(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
@@ -13,6 +14,7 @@ class AddALabelToAnEmailInteractor {
|
|||||||
AddALabelToAnEmailInteractor(this._emailRepository);
|
AddALabelToAnEmailInteractor(this._emailRepository);
|
||||||
|
|
||||||
Stream<Either<Failure, Success>> execute(
|
Stream<Either<Failure, Success>> execute(
|
||||||
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
KeyWordIdentifier labelKeyword,
|
KeyWordIdentifier labelKeyword,
|
||||||
@@ -21,6 +23,7 @@ class AddALabelToAnEmailInteractor {
|
|||||||
try {
|
try {
|
||||||
yield Right(AddingALabelToAnEmail());
|
yield Right(AddingALabelToAnEmail());
|
||||||
await _emailRepository.addLabelToEmail(
|
await _emailRepository.addLabelToEmail(
|
||||||
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
emailId,
|
emailId,
|
||||||
labelKeyword,
|
labelKeyword,
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class EmailInteractorBindings extends InteractorsBindings {
|
|||||||
Get.find<EmailRepository>(),
|
Get.find<EmailRepository>(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Get.lazyPut(
|
Get.lazyPut<AddALabelToAnEmailInteractor>(
|
||||||
() => AddALabelToAnEmailInteractor(Get.find<EmailRepository>()),
|
() => AddALabelToAnEmailInteractor(Get.find<EmailRepository>()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void handleSuccessViewState(Success success) {
|
void handleSuccessViewState(Success success) {
|
||||||
log('SingleEmailController::handleSuccessViewState(): $success');
|
|
||||||
if (success is GetEmailContentSuccess) {
|
if (success is GetEmailContentSuccess) {
|
||||||
_getEmailContentSuccess(success);
|
_getEmailContentSuccess(success);
|
||||||
} else if (success is GetEmailContentFromCacheSuccess) {
|
} else if (success is GetEmailContentFromCacheSuccess) {
|
||||||
@@ -255,7 +254,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void handleFailureViewState(Failure failure) {
|
void handleFailureViewState(Failure failure) {
|
||||||
logError('SingleEmailController::handleFailureViewState(): $failure');
|
|
||||||
if (failure is MarkAsEmailReadFailure) {
|
if (failure is MarkAsEmailReadFailure) {
|
||||||
_handleMarkAsEmailReadFailure(failure);
|
_handleMarkAsEmailReadFailure(failure);
|
||||||
} else if (failure is ParseCalendarEventFailure) {
|
} else if (failure is ParseCalendarEventFailure) {
|
||||||
@@ -899,6 +897,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
pressEmailAction(actionType, presentationEmail);
|
pressEmailAction(actionType, presentationEmail);
|
||||||
break;
|
break;
|
||||||
case EmailActionType.labelAs:
|
case EmailActionType.labelAs:
|
||||||
|
if (!isLabelFeatureEnabled) return;
|
||||||
openAddLabelToEmailDialogModal(presentationEmail);
|
openAddLabelToEmailDialogModal(presentationEmail);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -596,12 +596,13 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
|
final dialogRouter = DialogRouter();
|
||||||
bool isOverlayEnabled = controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame ||
|
bool isOverlayEnabled = controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame ||
|
||||||
MessageDialogActionManager().isDialogOpened ||
|
MessageDialogActionManager().isDialogOpened ||
|
||||||
EmailActionReactor.isDialogOpened ||
|
EmailActionReactor.isDialogOpened ||
|
||||||
ColorDialogPicker().isOpened.isTrue ||
|
ColorDialogPicker().isOpened.isTrue ||
|
||||||
DialogRouter().isRuleFilterDialogOpened.isTrue ||
|
dialogRouter.isRuleFilterDialogOpened.isTrue ||
|
||||||
DialogRouter().isDialogOpened;
|
dialogRouter.isDialogOpened;
|
||||||
|
|
||||||
if (isOverlayEnabled) {
|
if (isOverlayEnabled) {
|
||||||
return Positioned.fill(
|
return Positioned.fill(
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
|
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||||
import 'package:model/extensions/email_extension.dart';
|
import 'package:model/extensions/email_extension.dart';
|
||||||
import 'package:model/extensions/list_email_header_extension.dart';
|
import 'package:model/extensions/list_email_header_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/smime_signature_status.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/smime_signature_status.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/smime_signature_constant.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/smime_signature_constant.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread/data/extensions/map_keywords_extension.dart';
|
||||||
|
|
||||||
extension EmailExtension on Email {
|
extension EmailExtension on Email {
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ extension EmailExtension on Email {
|
|||||||
|
|
||||||
bool fromMe(String ownEmailAddress) {
|
bool fromMe(String ownEmailAddress) {
|
||||||
return from?.any(
|
return from?.any(
|
||||||
(emailAdress) => emailAdress.email == ownEmailAddress
|
(emailAddress) => emailAddress.email == ownEmailAddress
|
||||||
) == true;
|
) == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +52,15 @@ extension EmailExtension on Email {
|
|||||||
...bcc ?? {},
|
...bcc ?? {},
|
||||||
};
|
};
|
||||||
return recipients.any(
|
return recipients.any(
|
||||||
(emailAdress) => emailAdress.email == ownEmailAddress
|
(emailAddress) => emailAddress.email == ownEmailAddress
|
||||||
) == true;
|
) == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Email toggleKeyword(KeyWordIdentifier keyword, bool remove) {
|
||||||
|
return copyWith(
|
||||||
|
keywords: remove
|
||||||
|
? keywords.withoutKeyword(keyword)
|
||||||
|
: keywords.withKeyword(keyword),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,20 @@
|
|||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:model/extensions/email_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/email_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/data/extensions/map_keywords_extension.dart';
|
|
||||||
|
|
||||||
extension EmailLoadedExtension on EmailLoaded {
|
extension EmailLoadedExtension on EmailLoaded {
|
||||||
EmailLoaded addEmailKeyword({
|
EmailLoaded toggleEmailKeyword({
|
||||||
required EmailId emailId,
|
required EmailId emailId,
|
||||||
required KeyWordIdentifier keyword,
|
required KeyWordIdentifier keyword,
|
||||||
|
required bool remove,
|
||||||
}) {
|
}) {
|
||||||
if (emailCurrent == null || emailCurrent?.id != emailId) {
|
final current = emailCurrent;
|
||||||
|
if (current == null || current.id != emailId) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final newKeyword = emailCurrent?.keywords?.withKeyword(keyword);
|
return copyWith(
|
||||||
final updatedEmail = emailCurrent?.copyWith(keywords: newKeyword);
|
emailCurrent: current.toggleKeyword(keyword, remove),
|
||||||
return copyWith(emailCurrent: updatedEmail);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
EmailLoaded removeEmailKeyword({
|
|
||||||
required EmailId emailId,
|
|
||||||
required KeyWordIdentifier keyword,
|
|
||||||
}) {
|
|
||||||
if (emailCurrent == null || emailCurrent?.id != emailId) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
final newKeyword = emailCurrent?.keywords?.withoutKeyword(keyword);
|
|
||||||
final updatedEmail = emailCurrent?.copyWith(keywords: newKeyword);
|
|
||||||
return copyWith(emailCurrent: updatedEmail);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:core/utils/platform_info.dart';
|
|||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.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.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:labels/extensions/label_extension.dart';
|
import 'package:labels/extensions/label_extension.dart';
|
||||||
@@ -29,8 +30,10 @@ extension HandleLabelForEmailExtension on SingleEmailController {
|
|||||||
void toggleLabelToEmail(EmailId emailId, Label label, bool isSelected) {
|
void toggleLabelToEmail(EmailId emailId, Label label, bool isSelected) {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
final accountId = mailboxDashBoardController.accountId.value;
|
final accountId = mailboxDashBoardController.accountId.value;
|
||||||
|
final session = mailboxDashBoardController.sessionCurrent;
|
||||||
|
|
||||||
_addALabelToAnEmail(
|
_addALabelToAnEmail(
|
||||||
|
session: session,
|
||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
emailId: emailId,
|
emailId: emailId,
|
||||||
label: label,
|
label: label,
|
||||||
@@ -39,12 +42,25 @@ extension HandleLabelForEmailExtension on SingleEmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _addALabelToAnEmail({
|
void _addALabelToAnEmail({
|
||||||
|
required Session? session,
|
||||||
required AccountId? accountId,
|
required AccountId? accountId,
|
||||||
required Label label,
|
required Label label,
|
||||||
required EmailId emailId,
|
required EmailId emailId,
|
||||||
}) {
|
}) {
|
||||||
final labelDisplay = label.safeDisplayName;
|
final labelDisplay = label.safeDisplayName;
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
consumeState(
|
||||||
|
Stream.value(
|
||||||
|
Left(AddALabelToAnEmailFailure(
|
||||||
|
exception: NotFoundSessionException(),
|
||||||
|
labelDisplay: labelDisplay,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (accountId == null) {
|
if (accountId == null) {
|
||||||
consumeState(
|
consumeState(
|
||||||
Stream.value(
|
Stream.value(
|
||||||
@@ -71,6 +87,7 @@ extension HandleLabelForEmailExtension on SingleEmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
consumeState(addALabelToAnEmailInteractor.execute(
|
consumeState(addALabelToAnEmailInteractor.execute(
|
||||||
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
emailId,
|
emailId,
|
||||||
labelKeyword,
|
labelKeyword,
|
||||||
@@ -117,24 +134,27 @@ extension HandleLabelForEmailExtension on SingleEmailController {
|
|||||||
final controller = threadDetailController;
|
final controller = threadDetailController;
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
controller.emailIdsPresentation.value =
|
controller.emailIdsPresentation.value =
|
||||||
controller.emailIdsPresentation.addEmailKeywordById(
|
controller.emailIdsPresentation.toggleEmailKeywordById(
|
||||||
emailId: emailId,
|
emailId: emailId,
|
||||||
keyword: labelKeyword,
|
keyword: labelKeyword,
|
||||||
|
remove: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
controller.emailsInThreadDetailInfo.value =
|
controller.emailsInThreadDetailInfo.value =
|
||||||
controller.emailsInThreadDetailInfo.addEmailKeywordById(
|
controller.emailsInThreadDetailInfo.toggleEmailKeywordById(
|
||||||
emailId: emailId,
|
emailId: emailId,
|
||||||
keyword: labelKeyword,
|
keyword: labelKeyword,
|
||||||
|
remove: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final emailLoaded = currentEmailLoaded.value;
|
final emailLoaded = currentEmailLoaded.value;
|
||||||
if (emailLoaded != null && emailLoaded.emailCurrent?.id == emailId) {
|
if (emailLoaded != null && emailLoaded.emailCurrent?.id == emailId) {
|
||||||
currentEmailLoaded.value = emailLoaded.addEmailKeyword(
|
currentEmailLoaded.value = emailLoaded.toggleEmailKeyword(
|
||||||
emailId: emailId,
|
emailId: emailId,
|
||||||
keyword: labelKeyword,
|
keyword: labelKeyword,
|
||||||
|
remove: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +168,7 @@ extension HandleLabelForEmailExtension on SingleEmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> openAddLabelToEmailDialogModal(PresentationEmail email) async {
|
Future<void> openAddLabelToEmailDialogModal(PresentationEmail email) async {
|
||||||
|
if (!isLabelFeatureEnabled) return;
|
||||||
final labels = mailboxDashBoardController.labelController.labels;
|
final labels = mailboxDashBoardController.labelController.labels;
|
||||||
final emailLabels = email.getLabelList(labels);
|
final emailLabels = email.getLabelList(labels);
|
||||||
final emailId = email.id;
|
final emailId = email.id;
|
||||||
|
|||||||
@@ -170,15 +170,13 @@ extension PresentationEmailExtension on PresentationEmail {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
PresentationEmail addKeyword(KeyWordIdentifier keyword) {
|
PresentationEmail toggleKeyword(KeyWordIdentifier keyword, bool remove) {
|
||||||
return copyWith(
|
return copyWith(
|
||||||
keywords: keywords.withKeyword(keyword),
|
keywords: remove
|
||||||
);
|
? keywords.withoutKeyword(keyword)
|
||||||
}
|
: keywords.withKeyword(keyword),
|
||||||
|
)
|
||||||
PresentationEmail removeKeyword(KeyWordIdentifier keyword) {
|
..searchSnippetSubject = searchSnippetSubject
|
||||||
return copyWith(
|
..searchSnippetPreview = searchSnippetPreview;
|
||||||
keywords: keywords.withoutKeyword(keyword),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
class LabelKeywordIsNull implements Exception {}
|
class LabelKeywordIsNull implements Exception {
|
||||||
|
@override
|
||||||
|
String toString() => 'Label keyword is null';
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ class LabelController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> openCreateNewLabelModal(AccountId? accountId) async {
|
Future<void> openCreateNewLabelModal(AccountId? accountId) async {
|
||||||
|
if (accountId == null) {
|
||||||
|
consumeState(
|
||||||
|
Stream.value(Left(CreateNewLabelFailure(NotFoundAccountIdException()))),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await DialogRouter().openDialogModal(
|
await DialogRouter().openDialogModal(
|
||||||
child: CreateNewLabelModal(
|
child: CreateNewLabelModal(
|
||||||
labels: labels,
|
labels: labels,
|
||||||
@@ -80,13 +87,9 @@ class LabelController extends BaseController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _createNewLabel(AccountId? accountId, Label label) {
|
void _createNewLabel(AccountId accountId, Label label) {
|
||||||
log('LabelController::_createNewLabel:Label: $label');
|
log('LabelController::_createNewLabel:Label: $label');
|
||||||
if (accountId == null) {
|
if (_createNewLabelInteractor == null) {
|
||||||
consumeState(
|
|
||||||
Stream.value(Left(CreateNewLabelFailure(NotFoundAccountIdException()))),
|
|
||||||
);
|
|
||||||
} else if (_createNewLabelInteractor == null) {
|
|
||||||
consumeState(
|
consumeState(
|
||||||
Stream.value(Left(CreateNewLabelFailure(InteractorNotInitialized()))),
|
Stream.value(Left(CreateNewLabelFailure(InteractorNotInitialized()))),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import 'package:tmail_ui_user/features/labels/presentation/widgets/label_item_co
|
|||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
typedef OnAddLabelToEmailCallback = Function(
|
typedef OnAddLabelToEmailCallback = void Function(
|
||||||
EmailId emailId,
|
EmailId emailId,
|
||||||
Label label,
|
Label label,
|
||||||
bool isSelected,
|
bool isSelected,
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ class SignatureBuilder extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb) {
|
||||||
final iframeOverlay = Obx(() {
|
final iframeOverlay = Obx(() {
|
||||||
|
final dialogRouter = DialogRouter();
|
||||||
if (MessageDialogActionManager().isDialogOpened ||
|
if (MessageDialogActionManager().isDialogOpened ||
|
||||||
DialogRouter().isDialogOpened ||
|
dialogRouter.isDialogOpened ||
|
||||||
DialogRouter().isRuleFilterDialogOpened.isTrue) {
|
dialogRouter.isRuleFilterDialogOpened.isTrue) {
|
||||||
return Positioned.fill(
|
return Positioned.fill(
|
||||||
child: PointerInterceptor(
|
child: PointerInterceptor(
|
||||||
child: const SizedBox.expand(),
|
child: const SizedBox.expand(),
|
||||||
|
|||||||
@@ -4,27 +4,16 @@ import 'package:model/email/presentation_email.dart';
|
|||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart';
|
||||||
|
|
||||||
extension PresentationEmailMapExtension on Map<EmailId, PresentationEmail?> {
|
extension PresentationEmailMapExtension on Map<EmailId, PresentationEmail?> {
|
||||||
Map<EmailId, PresentationEmail?> addEmailKeywordById({
|
Map<EmailId, PresentationEmail?> toggleEmailKeywordById({
|
||||||
required EmailId emailId,
|
required EmailId emailId,
|
||||||
required KeyWordIdentifier keyword,
|
required KeyWordIdentifier keyword,
|
||||||
|
required bool remove,
|
||||||
}) {
|
}) {
|
||||||
return map((id, email) {
|
final newMap = Map<EmailId, PresentationEmail?>.from(this);
|
||||||
if (id != emailId || email == null) {
|
final email = newMap[emailId];
|
||||||
return MapEntry(id, email);
|
if (email != null) {
|
||||||
}
|
newMap[emailId] = email.toggleKeyword(keyword, remove);
|
||||||
return MapEntry(id, email.addKeyword(keyword));
|
}
|
||||||
});
|
return newMap;
|
||||||
}
|
|
||||||
|
|
||||||
Map<EmailId, PresentationEmail?> removeEmailKeywordById({
|
|
||||||
required EmailId emailId,
|
|
||||||
required KeyWordIdentifier keyword,
|
|
||||||
}) {
|
|
||||||
return map((id, email) {
|
|
||||||
if (id != emailId || email == null) {
|
|
||||||
return MapEntry(id, email);
|
|
||||||
}
|
|
||||||
return MapEntry(id, email.removeKeyword(keyword));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread/data/extensions/map_keywords_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
|
||||||
|
|
||||||
|
extension EmailInThreadDetailInfoExtension on EmailInThreadDetailInfo {
|
||||||
|
EmailInThreadDetailInfo toggleKeyword(
|
||||||
|
KeyWordIdentifier keyword,
|
||||||
|
bool remove,
|
||||||
|
) {
|
||||||
|
return copyWith(
|
||||||
|
keywords: remove
|
||||||
|
? keywords.withoutKeyword(keyword)
|
||||||
|
: keywords.withKeyword(keyword),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-20
@@ -1,6 +1,6 @@
|
|||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/data/extensions/map_keywords_extension.dart';
|
import 'package:tmail_ui_user/features/thread_detail/domain/extensions/email_in_thread_detail_info_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
|
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
|
||||||
|
|
||||||
extension ListEmailInThreadDetailInfoExtension on List<EmailInThreadDetailInfo> {
|
extension ListEmailInThreadDetailInfoExtension on List<EmailInThreadDetailInfo> {
|
||||||
@@ -10,29 +10,16 @@ extension ListEmailInThreadDetailInfoExtension on List<EmailInThreadDetailInfo>
|
|||||||
.map((email) => email.emailId)
|
.map((email) => email.emailId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
List<EmailInThreadDetailInfo> addEmailKeywordById({
|
List<EmailInThreadDetailInfo> toggleEmailKeywordById({
|
||||||
required EmailId emailId,
|
required EmailId emailId,
|
||||||
required KeyWordIdentifier keyword,
|
required KeyWordIdentifier keyword,
|
||||||
|
required bool remove,
|
||||||
}) {
|
}) {
|
||||||
return map((email) {
|
return map((emailInfo) {
|
||||||
if (email.emailId != emailId) {
|
if (emailInfo.emailId != emailId) {
|
||||||
return email;
|
return emailInfo;
|
||||||
}
|
}
|
||||||
final newKeywords = email.keywords.withKeyword(keyword);
|
return emailInfo.toggleKeyword(keyword, remove);
|
||||||
return email.copyWith(keywords: newKeywords);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<EmailInThreadDetailInfo> removeEmailKeywordById({
|
|
||||||
required EmailId emailId,
|
|
||||||
required KeyWordIdentifier keyword,
|
|
||||||
}) {
|
|
||||||
return map((email) {
|
|
||||||
if (email.emailId != emailId) {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
final newKeywords = email.keywords.withoutKeyword(keyword);
|
|
||||||
return email.copyWith(keywords: newKeywords);
|
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,9 @@ class DialogRouter {
|
|||||||
MailboxCreatorBindings().dependencies();
|
MailboxCreatorBindings().dependencies();
|
||||||
break;
|
break;
|
||||||
case AppRoutes.rulesFilterCreator:
|
case AppRoutes.rulesFilterCreator:
|
||||||
isRuleFilterDialogOpened.value = true;
|
if (PlatformInfo.isWeb) {
|
||||||
|
isRuleFilterDialogOpened.value = true;
|
||||||
|
}
|
||||||
RulesFilterCreatorBindings().dependencies();
|
RulesFilterCreatorBindings().dependencies();
|
||||||
break;
|
break;
|
||||||
case AppRoutes.identityCreator:
|
case AppRoutes.identityCreator:
|
||||||
@@ -107,7 +109,7 @@ class DialogRouter {
|
|||||||
|
|
||||||
await Get.generalDialog(
|
await Get.generalDialog(
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: dialogLabel,
|
barrierLabel: dialogLabel ?? 'dialog-modal',
|
||||||
pageBuilder: (_, __, ___) => child,
|
pageBuilder: (_, __, ___) => child,
|
||||||
).whenComplete(() {
|
).whenComplete(() {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb) {
|
||||||
|
|||||||
@@ -15,13 +15,11 @@ extension KeyWordIdentifierExtension on KeyWordIdentifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PatchObject generateReadActionPath(ReadActions action) {
|
PatchObject generateReadActionPath(ReadActions action) {
|
||||||
final isRead = action == ReadActions.markAsRead;
|
return _boolPatch(action == ReadActions.markAsRead ? true : null);
|
||||||
return _boolPatch(isRead ? true : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchObject generateMarkStarActionPath(MarkStarAction action) {
|
PatchObject generateMarkStarActionPath(MarkStarAction action) {
|
||||||
final isStar = action == MarkStarAction.markStar;
|
return _boolPatch(action == MarkStarAction.markStar ? true : null);
|
||||||
return _boolPatch(isStar ? true : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchObject generateAnsweredActionPath() => _boolPatch(true);
|
PatchObject generateAnsweredActionPath() => _boolPatch(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user