TF-1866 Implement delete sending email in Sending Queue

(cherry picked from commit 0b45b10231fd4ec4fd7936c71de6cdcda0e92d02)
This commit is contained in:
dab246
2023-06-05 09:15:28 +07:00
committed by Dat Vu
parent a1e9be48ee
commit 94cd15d237
10 changed files with 377 additions and 47 deletions
@@ -3,6 +3,7 @@ import 'package:model/extensions/email_extension.dart';
import 'package:model/extensions/email_id_extensions.dart';
import 'package:model/extensions/identity_id_extension.dart';
import 'package:model/extensions/mailbox_id_extension.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
import 'package:tmail_ui_user/features/composer/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/offline_mode/model/sending_email_hive_cache.dart';
@@ -33,4 +34,36 @@ extension SendingEmailExtension on SendingEmail {
identityId: identityId
);
}
SendingEmail toggleSelection() {
return SendingEmail(
sendingId: sendingId,
email: email,
emailActionType: emailActionType,
createTime: createTime,
sentMailboxId: sentMailboxId,
emailIdDestroyed: emailIdDestroyed,
emailIdAnsweredOrForwarded: emailIdAnsweredOrForwarded,
identityId: identityId,
mailboxNameRequest: mailboxNameRequest,
creationIdRequest: creationIdRequest,
selectMode: selectMode == SelectMode.INACTIVE ? SelectMode.ACTIVE : SelectMode.INACTIVE
);
}
SendingEmail unSelected() {
return SendingEmail(
sendingId: sendingId,
email: email,
emailActionType: emailActionType,
createTime: createTime,
sentMailboxId: sentMailboxId,
emailIdDestroyed: emailIdDestroyed,
emailIdAnsweredOrForwarded: emailIdAnsweredOrForwarded,
identityId: identityId,
mailboxNameRequest: mailboxNameRequest,
creationIdRequest: creationIdRequest,
selectMode: SelectMode.INACTIVE
);
}
}
@@ -77,7 +77,14 @@ class WorkSchedulerController {
Future<void> cancelByWorkType(WorkerType type) => Workmanager().cancelByTag(type.name);
Future<void> cancelByUniqueId(String uniqueId) => Workmanager().cancelByUniqueName(uniqueId);
Future<void> cancelByUniqueId(String uniqueId) {
try {
return Workmanager().cancelByUniqueName(uniqueId);
} catch (e) {
logError('WorkSchedulerController::cancelByUniqueId():EXCEPTION: $e');
return Future.value();
}
}
Future<void> cancelAll() => Workmanager().cancelAll();
}
@@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/sending_queue_controller.dart';
class SendingQueueBindings extends Bindings {
@@ -10,6 +11,6 @@ class SendingQueueBindings extends Bindings {
}
void _bindingsController() {
Get.put(SendingQueueController());
Get.put(SendingQueueController(Get.find<DeleteMultipleSendingEmailInteractor>()));
}
}
@@ -5,6 +5,8 @@ import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart';
import 'package:tmail_ui_user/features/sending_queue/data/repository/sending_queue_repository_impl.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/repository/sending_queue_repository.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_single_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart';
@@ -35,6 +37,8 @@ class SendingQueueInteractorBindings extends InteractorsBindings {
@override
void bindingsInteractor() {
Get.lazyPut(() => GetAllSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => DeleteSingleSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => DeleteMultipleSendingEmailInteractor(Get.find<DeleteSingleSendingEmailInteractor>()));
}
@override
@@ -1,24 +1,47 @@
import 'package:collection/collection.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter/cupertino.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/app_toast.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/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart';
import 'package:tmail_ui_user/features/composer/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/offline_mode/scheduler/worker_state.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/state/delete_multiple_sending_email_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/extensions/list_sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class SendingQueueController extends BaseController {
class SendingQueueController extends BaseController with MessageDialogActionMixin {
final DeleteMultipleSendingEmailInteractor _deleteMultipleSendingEmailInteractor;
final dashboardController = getBinding<MailboxDashBoardController>();
final sendingQueueIsolateManager = getBinding<SendingQueueIsolateManager>();
final _sendingQueueIsolateManager = getBinding<SendingQueueIsolateManager>();
final _imagePaths = getBinding<ImagePaths>();
final _appToast = getBinding<AppToast>();
final listSendingEmailController = ScrollController();
final selectionState = Rx<SelectMode>(SelectMode.INACTIVE);
SendingQueueController(this._deleteMultipleSendingEmailInteractor);
@override
void onInit() {
super.onInit();
sendingQueueIsolateManager?.initial(
_sendingQueueIsolateManager?.initial(
onData: _handleSendingQueueEvent,
onError: (error, stackTrace) {
logError('SendingQueueController::onInit():onError:error: $error | stackTrace: $stackTrace');
@@ -37,18 +60,140 @@ class SendingQueueController extends BaseController {
}
}
void handleOnLongPressAction(SendingEmail sendingEmail) {
final newListSendingEmail = dashboardController!.listSendingEmails.toggleSelection(sendingEmailSelected: sendingEmail);
dashboardController!.listSendingEmails.value = newListSendingEmail;
selectionState.value = newListSendingEmail.isAllUnSelected()
? SelectMode.INACTIVE
: SelectMode.ACTIVE;
}
void toggleSelectionSendingEmail(SendingEmail sendingEmail) {
final newListSendingEmail = dashboardController!.listSendingEmails.toggleSelection(sendingEmailSelected: sendingEmail);
dashboardController!.listSendingEmails.value = newListSendingEmail;
selectionState.value = newListSendingEmail.isAllUnSelected()
? SelectMode.INACTIVE
: SelectMode.ACTIVE;
}
bool get isAllUnSelected => dashboardController!.listSendingEmails.isAllUnSelected();
void _refreshSendingQueue({bool needToReopen = false}) {
dashboardController?.getAllSendingEmails(needToReopen: needToReopen);
dashboardController!.getAllSendingEmails(needToReopen: needToReopen);
}
void openMailboxMenu() {
dashboardController?.openMailboxMenuDrawer();
dashboardController!.openMailboxMenuDrawer();
}
void disableSelectionMode() {
final newListSendingEmail = dashboardController!.listSendingEmails.unAllSelected();
dashboardController!.listSendingEmails.value = newListSendingEmail;
selectionState.value = SelectMode.INACTIVE;
}
void handleSendingEmailActionType(
BuildContext context,
SendingEmailActionType actionType,
List<SendingEmail> listSendingEmails
) {
switch(actionType) {
case SendingEmailActionType.delete:
_deleteSendingEmailAction(context, listSendingEmails);
break;
}
}
void _deleteSendingEmailAction(BuildContext context, List<SendingEmail> listSendingEmails) {
showConfirmDialogAction(
context,
AppLocalizations.of(context).messageDialogDeleteSendingEmail,
AppLocalizations.of(currentContext!).delete,
title: AppLocalizations.of(currentContext!).deleteOfflineEmail,
icon: SvgPicture.asset(_imagePaths!.icDeleteDialogRecipients),
alignCenter: true,
messageStyle: const TextStyle(
color: AppColor.colorTitleSendingItem,
fontSize: 15,
fontWeight: FontWeight.normal
),
titleStyle: const TextStyle(
color: AppColor.colorDeletePermanentlyButton,
fontSize: 20,
fontWeight: FontWeight.bold
),
actionButtonColor: AppColor.colorDeletePermanentlyButton,
actionStyle: const TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.w500
),
cancelStyle: const TextStyle(
color: AppColor.colorDeletePermanentlyButton,
fontSize: 17,
fontWeight: FontWeight.w500
),
onConfirmAction: () => _handleDeleteSendingEmail(listSendingEmails),
);
}
void _handleDeleteSendingEmail(List<SendingEmail> listSendingEmails) async {
final accountId = dashboardController!.accountId.value;
final session = dashboardController!.sessionCurrent;
if (accountId != null && session != null) {
final sendingIds = listSendingEmails.map((sendingEmail) => sendingEmail.sendingId).toSet().toList();
await Future.wait(
sendingIds.map((sendingId) => WorkSchedulerController().cancelByUniqueId(sendingId)),
eagerError: true
);
consumeState(_deleteMultipleSendingEmailInteractor.execute(accountId, session.username, sendingIds));
}
}
void _handleDeleteSendingEmailSuccess() {
if (currentContext != null && currentOverlayContext != null) {
selectionState.value = SelectMode.INACTIVE;
_appToast!.showToastSuccessMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).deleteSomeOfflineEmailSuccessfully
);
_refreshSendingQueue();
}
}
void _handleDeleteSendingEmailFailure() {
selectionState.value = SelectMode.INACTIVE;
}
@override
void handleSuccessViewState(Success success) {
super.handleSuccessViewState(success);
if (success is DeleteMultipleSendingEmailAllSuccess ||
success is DeleteMultipleSendingEmailHasSomeSuccess) {
_handleDeleteSendingEmailSuccess();
}
}
@override
void handleFailureViewState(Failure failure) {
super.handleFailureViewState(failure);
if (failure is DeleteMultipleSendingEmailAllFailure ||
failure is DeleteMultipleSendingEmailFailure) {
_handleDeleteSendingEmailFailure();
}
}
@override
void onClose() {
listSendingEmailController.dispose();
sendingQueueIsolateManager?.release();
_sendingQueueIsolateManager?.release();
super.onClose();
}
}
@@ -8,6 +8,7 @@ import 'package:tmail_ui_user/features/sending_queue/presentation/sending_queue_
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/widgets/app_bar_sending_queue_widget.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/widgets/banner_message_sending_queue_widget.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/widgets/bottom_bar_sending_queue_widget.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/widgets/sending_email_tile_widget.dart';
class SendingQueueView extends GetWidget<SendingQueueController> with AppLoaderMixin {
@@ -18,23 +19,32 @@ class SendingQueueView extends GetWidget<SendingQueueController> with AppLoaderM
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: SafeArea(
child: Column(
children: [
AppBarSendingQueueWidget(onOpenMailboxMenu: controller.openMailboxMenu),
const Divider(color: AppColor.colorDividerComposer, height: 1),
const BannerMessageSendingQueueWidget(),
Expanded(child: _buildListSendingEmails(context))
]
),
body: SafeArea(
child: Column(
children: [
Obx(() => AppBarSendingQueueWidget(
listSendingEmails: controller.dashboardController!.listSendingEmails,
onOpenMailboxMenu: controller.openMailboxMenu,
onBackAction: controller.disableSelectionMode,
selectMode: controller.selectionState.value,
)),
const Divider(color: AppColor.colorDividerComposer, height: 1),
const BannerMessageSendingQueueWidget(),
Expanded(child: _buildListSendingEmails(context)),
Obx(() {
if (controller.isAllUnSelected) {
return const SizedBox.shrink();
} else {
return BottomBarSendingQueueWidget(
listSendingEmails: controller.dashboardController!.listSendingEmails,
onHandleSendingEmailActionType: (actionType, listSendingEmails) => controller.handleSendingEmailActionType(context, actionType, listSendingEmails),
);
}
}),
]
),
),
floatingActionButton: ComposeFloatingButton(
scrollController: controller.listSendingEmailController,
onTap: () => controller.dashboardController!.goToComposer(ComposerArguments())
),
floatingActionButton: _buildFloatingButtonCompose(),
);
}
@@ -45,13 +55,37 @@ class SendingQueueView extends GetWidget<SendingQueueController> with AppLoaderM
controller: controller.listSendingEmailController,
padding: EdgeInsets.zero,
itemCount: controller.dashboardController!.listSendingEmails.length,
itemBuilder: (context, index) => SendingEmailTileWidget(
sendingEmail: controller.dashboardController!.listSendingEmails[index]
)
itemBuilder: (context, index) {
return Obx(() => SendingEmailTileWidget(
sendingEmail: controller.dashboardController!.listSendingEmails[index],
selectMode: controller.selectionState.value,
onLongPressAction: controller.handleOnLongPressAction,
onSelectAction: controller.toggleSelectionSendingEmail,
));
}
);
} else {
return const SizedBox.shrink();
}
});
}
Widget _buildFloatingButtonCompose() {
return Obx(() {
if (controller.isAllUnSelected) {
return ComposeFloatingButton(
scrollController: controller.listSendingEmailController,
onTap: () => controller.dashboardController!.goToComposer(ComposerArguments())
);
} else {
return Container(
padding: const EdgeInsets.only(bottom: 70),
child: ComposeFloatingButton(
scrollController: controller.listSendingEmailController,
onTap: () => controller.dashboardController!.goToComposer(ComposerArguments())
),
);
}
});
}
}
@@ -7,6 +7,7 @@ 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/composer/domain/model/sending_email.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
@@ -15,12 +16,14 @@ class AppBarSendingQueueWidget extends StatelessWidget {
final VoidCallback? onBackAction;
final VoidCallback? onOpenMailboxMenu;
final SelectMode selectMode;
final List<SendingEmail> listSendingEmails;
const AppBarSendingQueueWidget({
super.key,
required this.listSendingEmails,
this.onBackAction,
this.onOpenMailboxMenu,
this.selectMode = SelectMode.INACTIVE,
this.selectMode = SelectMode.INACTIVE
});
@override
@@ -44,14 +47,40 @@ class AppBarSendingQueueWidget extends StatelessWidget {
onTap: onOpenMailboxMenu
)
else
buildIconWeb(
icon: SvgPicture.asset(
AppUtils.isDirectionRTL(context) ? imagePaths.icCollapseFolder : imagePaths.icBack,
colorFilter: AppColor.colorTextButton.asFilter(),
fit: BoxFit.fill
Padding(
padding: const EdgeInsets.only(left: 8),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(15),
child: InkWell(
onTap: onBackAction,
borderRadius: BorderRadius.circular(15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
AppUtils.isDirectionRTL(context) ? imagePaths.icCollapseFolder : imagePaths.icBack,
colorFilter: AppColor.colorTextButton.asFilter(),
fit: BoxFit.fill
),
const SizedBox(width: 8),
Text(
listSendingEmails.length.toString(),
maxLines: 1,
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontSize: 17,
color: AppColor.colorTextButton
)
)
]
),
),
),
),
tooltip: AppLocalizations.of(context).back,
onTap: onBackAction
),
Expanded(child: Text(
AppLocalizations.of(context).sendingQueue,
@@ -6,17 +6,26 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/extensions/presentation_email_extension.dart';
import 'package:model/model.dart';
import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/composer/domain/model/sending_email.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnLongPressSendingEmailItemAction = void Function(SendingEmail);
typedef OnSelectSendingEmailItemAction = void Function(SendingEmail);
class SendingEmailTileWidget extends StatelessWidget {
final SendingEmail sendingEmail;
final SelectMode selectMode;
final OnLongPressSendingEmailItemAction? onLongPressAction;
final OnSelectSendingEmailItemAction? onSelectAction;
const SendingEmailTileWidget({
super.key,
required this.sendingEmail
required this.sendingEmail,
required this.selectMode,
this.onLongPressAction,
this.onSelectAction
});
@override
@@ -27,6 +36,7 @@ class SendingEmailTileWidget extends StatelessWidget {
color: Colors.transparent,
child: InkWell(
onTap: () => {},
onLongPress: () => onLongPressAction?.call(sendingEmail),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -34,14 +44,36 @@ class SendingEmailTileWidget extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
SvgPicture.asset(
sendingEmail.presentationEmail.numberOfAllEmailAddress() == 1
? imagePath.icAvatarPersonal
: imagePath.icAvatarGroup,
fit: BoxFit.fill,
width: 60,
height: 60,
),
if (selectMode == SelectMode.ACTIVE)
GestureDetector(
child: Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(30))
),
alignment: Alignment.center,
child: SvgPicture.asset(
sendingEmail.isSelected
? imagePath.icSelected
: imagePath.icUnSelected,
fit: BoxFit.fill,
width: 24,
height: 24
),
),
onTap: () => onSelectAction?.call(sendingEmail),
)
else
SvgPicture.asset(
sendingEmail.presentationEmail.numberOfAllEmailAddress() == 1
? imagePath.icAvatarPersonal
: imagePath.icAvatarGroup,
fit: BoxFit.fill,
width: 60,
height: 60,
),
const SizedBox(width: 8),
Expanded(child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
+25 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2023-06-01T13:42:51.121212",
"@@last_modified": "2023-06-05T09:10:02.535366",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -2863,5 +2863,29 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"messageHasBeenSentSuccessfully": "Message has been sent successfully.",
"@messageHasBeenSentSuccessfully": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"deleteOfflineEmail": "Delete offline email",
"@deleteOfflineEmail": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"messageDialogDeleteSendingEmail": "Deleting an offline email will erase its content permanently. You won't be able to undo this action or recover the email from the Trash mailbox.",
"@messageDialogDeleteSendingEmail": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"deleteSomeOfflineEmailSuccessfully": "Delete some offline email successfully.",
"@deleteSomeOfflineEmailSuccessfully": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -2953,4 +2953,25 @@ class AppLocalizations {
name: 'messageHasBeenSentSuccessfully',
);
}
String get deleteOfflineEmail {
return Intl.message(
'Delete offline email',
name: 'deleteOfflineEmail'
);
}
String get messageDialogDeleteSendingEmail {
return Intl.message(
'Deleting an offline email will erase its content permanently. You won\'t be able to undo this action or recover the email from the Trash mailbox.',
name: 'messageDialogDeleteSendingEmail'
);
}
String get deleteSomeOfflineEmailSuccessfully {
return Intl.message(
'Delete some offline email successfully.',
name: 'deleteSomeOfflineEmailSuccessfully',
);
}
}