TF-832 Implement delete multiple recipient in forwarding

This commit is contained in:
dab246
2022-08-19 13:28:27 +07:00
committed by Dat H. Pham
parent 7da79592c8
commit 6acf70e61b
9 changed files with 377 additions and 61 deletions
@@ -0,0 +1,12 @@
import 'package:forward/forward/tmail_forward.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/recipient_forward.dart';
extension TMailForwardExtension on TMailForward {
List<RecipientForward> get listRecipientForward {
return forwards
.map((emailAddress) => RecipientForward(emailAddress))
.toList();
}
}
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:forward/forward/tmail_forward.dart';
import 'package:get/get.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/delete_recipient_in_forwarding_request.dart';
@@ -15,7 +16,9 @@ import 'package:tmail_ui_user/features/manage_account/domain/state/delete_recipi
import 'package:tmail_ui_user/features/manage_account/domain/state/get_forward_state.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_recipient_in_forwarding_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_forward_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/tmail_forward_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/recipient_forward.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -29,7 +32,10 @@ class ForwardController extends BaseController {
final _imagePaths = Get.find<ImagePaths>();
final _appToast = Get.find<AppToast>();
final currentForward = Rxn<TMailForward>();
final selectionMode = Rx<SelectMode>(SelectMode.INACTIVE);
final listRecipientForward = RxList<RecipientForward>();
TMailForward? currentForward;
ForwardController(
this._getForwardInteractor,
@@ -38,13 +44,20 @@ class ForwardController extends BaseController {
@override
void onDone() {
viewState.value.fold((failure) {}, (success) {
if (success is GetForwardSuccess) {
currentForward.value = success.forward;
} else if (success is DeleteRecipientInForwardingSuccess) {
_handleDeleteRecipientSuccess(success);
}
});
viewState.value.fold(
(failure) {
if (failure is DeleteRecipientInForwardingFailure) {
cancelSelectionMode();
}
},
(success) {
if (success is GetForwardSuccess) {
currentForward = success.forward;
listRecipientForward.value = currentForward!.listRecipientForward;
} else if (success is DeleteRecipientInForwardingSuccess) {
_handleDeleteRecipientSuccess(success);
}
});
}
@override
@@ -100,11 +113,11 @@ class ForwardController extends BaseController {
popBack();
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null && currentForward.value != null) {
if (accountId != null && currentForward != null) {
consumeState(_deleteRecipientInForwardingInteractor.execute(
accountId,
DeleteRecipientInForwardingRequest(
currentForward: currentForward.value!,
currentForward: currentForward!,
listRecipientDeleted: listRecipients)));
}
}
@@ -117,6 +130,75 @@ class ForwardController extends BaseController {
icon: _imagePaths.icSelected);
}
currentForward.value = success.forward;
currentForward = success.forward;
listRecipientForward.value = currentForward!.listRecipientForward;
selectionMode.value = SelectMode.INACTIVE;
}
List<RecipientForward> get listRecipientForwardSelected => listRecipientForward
.where((recipient) => recipient.selectMode == SelectMode.ACTIVE)
.toList();
bool get isAllUnSelected =>
listRecipientForward.every((recipient) => recipient.selectMode == SelectMode.INACTIVE);
void selectRecipientForward(RecipientForward recipientForward) {
if (selectionMode.value == SelectMode.INACTIVE) {
selectionMode.value = SelectMode.ACTIVE;
}
final matchRecipientForward = listRecipientForward.indexOf(recipientForward);
if (matchRecipientForward >= 0) {
final newRecipientForward = recipientForward.toggleSelection();
listRecipientForward[matchRecipientForward] = newRecipientForward;
listRecipientForward.refresh();
}
if (isAllUnSelected) {
selectionMode.value = SelectMode.INACTIVE;
}
}
void cancelSelectionMode() {
selectionMode.value = SelectMode.INACTIVE;
listRecipientForward.value = listRecipientForward
.map((recipient) => recipient.cancelSelection())
.toList();
}
void deleteMultipleRecipients(BuildContext context, Set<String> listEmailAddress) {
if (_responsiveUtils.isMobile(context)) {
(ConfirmationDialogActionSheetBuilder(context)
..messageText(AppLocalizations.of(context).messageConfirmationDialogDeleteAllRecipientForward)
..onCancelAction(AppLocalizations.of(context).cancel, () =>
popBack())
..onConfirmAction(AppLocalizations.of(context).delete, () {
_handleDeleteRecipientAction(listEmailAddress);
}))
.show();
} else {
showDialog(
context: context,
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
builder: (BuildContext context) =>
PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
..title(AppLocalizations.of(context).deleteRecipient)
..content(AppLocalizations.of(context).messageConfirmationDialogDeleteAllRecipientForward)
..addIcon(SvgPicture.asset(_imagePaths.icRemoveDialog,
fit: BoxFit.fill))
..marginIcon(EdgeInsets.zero)
..colorConfirmButton(AppColor.colorConfirmActionDialog)
..styleTextConfirmButton(const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: AppColor.colorActionDeleteConfirmDialog))
..onCloseButtonAction(() => popBack())
..onConfirmButtonAction(AppLocalizations.of(context).delete, () {
_handleDeleteRecipientAction(listEmailAddress);
})
..onCancelButtonAction(AppLocalizations.of(context).cancel, () =>
popBack()))
.build()));
}
}
}
@@ -22,9 +22,8 @@ class ForwardView extends GetWidget<ForwardController> with AppLoaderMixin {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: _responsiveUtils.isWebDesktop(context) ? 24 : 16),
_buildLoadingView(),
const Expanded(child: ListEmailForwardsWidget())
Expanded(child: ListEmailForwardsWidget())
],
),
),
@@ -2,46 +2,84 @@ import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/recipient_forward.dart';
class EmailForwardItemWidget extends StatelessWidget {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
final _emailForwardController = Get.find<ForwardController>();
final String emailAddress;
final RecipientForward recipientForward;
final SelectMode selectionMode;
EmailForwardItemWidget({
Key? key,
required this.emailAddress,
required this.recipientForward,
this.selectionMode = SelectMode.INACTIVE,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 15,
bottom: 15,
left: _responsiveUtils.isMobile(context) ? 16 : 24,
right: _responsiveUtils.isMobile(context) ? 8 : 24
return GestureDetector(
onLongPress: () => _emailForwardController.selectRecipientForward(recipientForward),
onTap: () {
if (selectionMode == SelectMode.ACTIVE) {
_emailForwardController.selectRecipientForward(recipientForward);
}
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
color: Colors.white,
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Container(
width: 32,
height: 32,
color: Colors.transparent,
alignment: Alignment.center,
child: _buildAvatarIcon()),
const SizedBox(width: 10),
Expanded(child: Text(recipientForward.emailAddress,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black))),
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icDeleteEmailForward,
fit: BoxFit.fill,
width: 18,
height: 18,
),
onTap: () =>
_emailForwardController.deleteRecipients(context, recipientForward.emailAddress)),
]),
),
color: Colors.white,
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Text(emailAddress,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black)),
const Spacer(),
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icDeleteEmailForward,
fit: BoxFit.fill,
),
onTap: () {
_emailForwardController.deleteRecipients(context, emailAddress);
}),
]),
);
}
Widget _buildAvatarIcon() {
if (selectionMode == SelectMode.ACTIVE) {
return Container(
alignment: Alignment.center,
child: SvgPicture.asset(
recipientForward.selectMode == SelectMode.ACTIVE
? _imagePaths.icSelected
: _imagePaths.icUnSelected,
width: 24,
height: 24));
} else {
return CircleAvatar(
backgroundColor: AppColor.colorTextButton,
radius: 16,
child: Text(recipientForward.emailAddress[0].toUpperCase(),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500)));
}
}
}
@@ -0,0 +1,97 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:html_editor_enhanced/utils/utils.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/recipient_forward.dart';
class EmailForwardItemWidget extends StatefulWidget {
final RecipientForward recipientForward;
final SelectMode selectionMode;
const EmailForwardItemWidget({
Key? key,
required this.recipientForward,
this.selectionMode = SelectMode.INACTIVE,
}) : super(key: key);
@override
State<EmailForwardItemWidget> createState() => _EmailForwardItemWidgetState();
}
class _EmailForwardItemWidgetState extends State<EmailForwardItemWidget> {
final _imagePaths = Get.find<ImagePaths>();
final _emailForwardController = Get.find<ForwardController>();
bool isHoverIcon = false;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
color: Colors.white,
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
InkWell(
onTap: () {
if (isHoverIcon) {
_emailForwardController.selectRecipientForward(widget.recipientForward);
}
},
onHover: (value) {
setState(mounted, this.setState, () {
isHoverIcon = value;
});
},
child: Container(
width: 32,
height: 32,
color: Colors.transparent,
alignment: Alignment.center,
child: _buildAvatarIcon())),
const SizedBox(width: 10),
Expanded(child: Text(widget.recipientForward.emailAddress,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black))),
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icDeleteEmailForward,
fit: BoxFit.fill,
width: 18,
height: 18,
),
onTap: () =>
_emailForwardController.deleteRecipients(context, widget.recipientForward.emailAddress)),
]),
);
}
Widget _buildAvatarIcon() {
if (isHoverIcon || widget.recipientForward.selectMode == SelectMode.ACTIVE) {
return Container(
alignment: Alignment.center,
child: SvgPicture.asset(
widget.recipientForward.selectMode == SelectMode.ACTIVE
? _imagePaths.icSelected
: _imagePaths.icUnSelected,
width: 24,
height: 24));
} else {
return CircleAvatar(
backgroundColor: AppColor.colorTextButton,
radius: 16,
child: Text(widget.recipientForward.emailAddress[0].toUpperCase(),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500)));
}
}
}
@@ -1,13 +1,19 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart'
if (dart.library.html) 'package:tmail_ui_user/features/manage_account/presentation/forward/widgets/email_forward_item_widget_for_web.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/recipient_forward.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ListEmailForwardsWidget extends GetWidget<ForwardController> {
const ListEmailForwardsWidget({Key? key}) : super(key: key);
final _imagePaths = Get.find<ImagePaths>();
ListEmailForwardsWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -25,7 +31,7 @@ class ListEmailForwardsWidget extends GetWidget<ForwardController> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
Obx(() => Container(
width: double.infinity,
decoration: const BoxDecoration(
color: AppColor.colorBackgroundHeaderListForwards,
@@ -33,16 +39,27 @@ class ListEmailForwardsWidget extends GetWidget<ForwardController> {
topLeft: Radius.circular(16),
topRight: Radius.circular(16)),
),
padding: const EdgeInsets.symmetric(
vertical: 28,
horizontal: 24,
),
child: Text(AppLocalizations.of(context).headerEmailsForward,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColor.colorTextButtonHeaderThread)),
),
padding: controller.selectionMode.value == SelectMode.INACTIVE
? const EdgeInsets.all(24)
: const EdgeInsets.symmetric(vertical: 13, horizontal: 24),
child: Row(children: [
Expanded(child: Text(
AppLocalizations.of(context).headerEmailsForward,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColor.colorTextButtonHeaderThread))),
Obx(() {
if (controller.selectionMode.value == SelectMode.ACTIVE) {
return _buildListButtonSelection(context);
} else {
return const SizedBox.shrink();
}
})
]),
)),
const Divider(
color: AppColor.lineItemListColor,
height: 1,
@@ -50,14 +67,14 @@ class ListEmailForwardsWidget extends GetWidget<ForwardController> {
),
Expanded(
child: Obx(() {
final listRecipients = controller.currentForward.value?.forwards.toList() ?? <String>[];
return ListView.separated(
shrinkWrap: true,
itemCount: listRecipients.length,
itemCount: controller.listRecipientForward.length,
itemBuilder: (context, index) {
final emailAddress = listRecipients[index];
log('ListEmailForwardsWidget::build(): $emailAddress');
return EmailForwardItemWidget(emailAddress: emailAddress);
final recipientForward = controller.listRecipientForward[index];
return EmailForwardItemWidget(
recipientForward: recipientForward,
selectionMode: controller.selectionMode.value);
},
separatorBuilder: (context, index) => const Divider(
color: AppColor.lineItemListColor,
@@ -71,4 +88,27 @@ class ListEmailForwardsWidget extends GetWidget<ForwardController> {
),
);
}
}
Widget _buildListButtonSelection(BuildContext context) {
return Row(mainAxisSize: MainAxisSize.min, children: [
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icCloseComposer,
color: AppColor.colorTextButton,
fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).cancel,
onTap: () => controller.cancelSelectionMode()),
const SizedBox(width: 5),
buildIconWeb(
icon: SvgPicture.asset(
_imagePaths.icDelete,
color: AppColor.colorActionDeleteConfirmDialog,
fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).delete_all,
onTap: () =>
controller.deleteMultipleRecipients(
context,
controller.listRecipientForwardSelected.listEmailAddress))
]);
}
}
@@ -0,0 +1,35 @@
import 'package:equatable/equatable.dart';
import 'package:model/mailbox/select_mode.dart';
class RecipientForward with EquatableMixin {
final String emailAddress;
final SelectMode selectMode;
RecipientForward(this.emailAddress, {this.selectMode = SelectMode.INACTIVE});
@override
List<Object?> get props => [emailAddress, selectMode];
}
extension RecipientForwardExtension on RecipientForward {
RecipientForward toggleSelection() {
return RecipientForward(
emailAddress,
selectMode: selectMode == SelectMode.ACTIVE
? SelectMode.INACTIVE
: SelectMode.ACTIVE
);
}
RecipientForward cancelSelection() {
return RecipientForward(emailAddress, selectMode: SelectMode.INACTIVE);
}
}
extension ListRecipientForwardExtension on List<RecipientForward> {
Set<String> get listEmailAddress =>
map((recipient) => recipient.emailAddress).toSet();
}
+7 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2022-08-19T11:57:02.557202",
"@@last_modified": "2022-08-19T13:28:03.023650",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -2059,5 +2059,11 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"messageConfirmationDialogDeleteAllRecipientForward": "Do you want to delete all email?",
"@messageConfirmationDialogDeleteAllRecipientForward": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -2126,4 +2126,11 @@ class AppLocalizations {
'The email has been removed from the recipient list.',
name: 'toastMessageDeleteRecipientSuccessfully');
}
String get messageConfirmationDialogDeleteAllRecipientForward {
return Intl.message(
'Do you want to delete all email?',
name: 'messageConfirmationDialogDeleteAllRecipientForward'
);
}
}