TF-80 Move email to Mailbox in Email Detailed view
This commit is contained in:
@@ -63,7 +63,7 @@ class DestinationPickerController extends BaseController {
|
||||
}
|
||||
|
||||
void moveEmailToMailboxAction(PresentationMailbox destinationMailbox) {
|
||||
popBack();
|
||||
popBack(result: destinationMailbox);
|
||||
}
|
||||
|
||||
void closeDestinationPicker() {
|
||||
|
||||
+4
-4
@@ -2,15 +2,15 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
|
||||
class DestinationPickerArguments with EquatableMixin{
|
||||
final AccountId accountId;
|
||||
final List<EmailId> emailIds;
|
||||
final MailboxId currentMailboxId;
|
||||
final PresentationMailbox currentMailbox;
|
||||
|
||||
DestinationPickerArguments(this.accountId, this.emailIds, this.currentMailboxId);
|
||||
DestinationPickerArguments(this.accountId, this.emailIds, this.currentMailbox);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [accountId, emailIds, currentMailboxId];
|
||||
List<Object?> get props => [accountId, emailIds, currentMailbox];
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:model/email/read_actions.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
|
||||
abstract class EmailDataSource {
|
||||
Future<Email> getEmailContent(AccountId accountId, EmailId emailId);
|
||||
@@ -26,4 +27,6 @@ abstract class EmailDataSource {
|
||||
AccountRequest accountRequest,
|
||||
CancelToken cancelToken
|
||||
);
|
||||
|
||||
Future<bool> moveToMailbox(AccountId accountId, MoveRequest moveRequest);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
|
||||
class EmailDataSourceImpl extends EmailDataSource {
|
||||
|
||||
@@ -67,4 +68,13 @@ class EmailDataSourceImpl extends EmailDataSource {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> moveToMailbox(AccountId accountId, MoveRequest moveRequest) {
|
||||
return Future.sync(() async {
|
||||
return await emailAPI.moveToMailbox(accountId, moveRequest);
|
||||
}).catchError((error) {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import 'package:jmap_dart_client/jmap/mail/email/submission/set/set_email_submis
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
|
||||
class EmailAPI {
|
||||
|
||||
@@ -186,4 +187,32 @@ class EmailAPI {
|
||||
accountRequest.basicAuth,
|
||||
cancelToken: cancelToken);
|
||||
}
|
||||
|
||||
Future<bool> moveToMailbox(AccountId accountId, MoveRequest moveRequest) async {
|
||||
final setEmailMethod = SetEmailMethod(accountId)
|
||||
..addUpdates({
|
||||
moveRequest.emailId.id: moveRequest.currentMailboxId
|
||||
.generateMoveToMailboxActionPath(moveRequest.destinationMailboxId)
|
||||
});
|
||||
|
||||
final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation());
|
||||
|
||||
final setEmailInvocation = requestBuilder.invocation(setEmailMethod);
|
||||
|
||||
final response = await (requestBuilder
|
||||
..usings(setEmailMethod.requiredCapabilities))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
final setEmailResponse = response.parse<SetEmailResponse>(
|
||||
setEmailInvocation.methodCallId,
|
||||
SetEmailResponse.deserialize);
|
||||
|
||||
return Future.sync(() async {
|
||||
final emailUpdated = setEmailResponse!.updated![moveRequest.emailId.id];
|
||||
return emailUpdated == null;
|
||||
}).catchError((error) {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||
|
||||
class EmailRepositoryImpl extends EmailRepository {
|
||||
@@ -53,4 +54,9 @@ class EmailRepositoryImpl extends EmailRepository {
|
||||
accountRequest,
|
||||
cancelToken);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> moveToMailbox(AccountId accountId, MoveRequest moveRequest) {
|
||||
return emailDataSource.moveToMailbox(accountId, moveRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/model.dart';
|
||||
|
||||
class MoveRequest with EquatableMixin {
|
||||
|
||||
final EmailId emailId;
|
||||
final MailboxId currentMailboxId;
|
||||
final MailboxName currentMailboxName;
|
||||
final MailboxId destinationMailboxId;
|
||||
final MailboxName destinationMailboxName;
|
||||
final MoveAction moveAction;
|
||||
|
||||
MoveRequest(
|
||||
this.emailId,
|
||||
this.currentMailboxId,
|
||||
this.currentMailboxName,
|
||||
this.destinationMailboxId,
|
||||
this.destinationMailboxName,
|
||||
this.moveAction,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
emailId,
|
||||
currentMailboxId,
|
||||
currentMailboxName,
|
||||
destinationMailboxId,
|
||||
destinationMailboxName,
|
||||
moveAction
|
||||
];
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
|
||||
abstract class EmailRepository {
|
||||
Future<Email> getEmailContent(AccountId accountId, EmailId emailId);
|
||||
@@ -25,4 +26,6 @@ abstract class EmailRepository {
|
||||
AccountRequest accountRequest,
|
||||
CancelToken cancelToken
|
||||
);
|
||||
|
||||
Future<bool> moveToMailbox(AccountId accountId, MoveRequest moveRequest);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
|
||||
class MoveToMailboxSuccess extends UIState {
|
||||
final MoveRequest moveRequest;
|
||||
|
||||
MoveToMailboxSuccess(this.moveRequest);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [moveRequest];
|
||||
}
|
||||
|
||||
class MoveToMailboxFailure extends FeatureFailure {
|
||||
final exception;
|
||||
|
||||
MoveToMailboxFailure(this.exception);
|
||||
|
||||
@override
|
||||
List<Object> get props => [exception];
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart';
|
||||
|
||||
class MoveToMailboxInteractor {
|
||||
final EmailRepository emailRepository;
|
||||
|
||||
MoveToMailboxInteractor(this.emailRepository);
|
||||
|
||||
Stream<Either<Failure, Success>> execute(AccountId accountId, MoveRequest moveRequest) async* {
|
||||
try {
|
||||
final result = await emailRepository.moveToMailbox(accountId, moveRequest);
|
||||
yield result
|
||||
? Right(MoveToMailboxSuccess(moveRequest))
|
||||
: Left(MoveToMailboxFailure(null));
|
||||
} catch (e) {
|
||||
yield Left(MoveToMailboxFailure(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/email_controller.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/repository/credential_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||
@@ -33,12 +34,14 @@ class EmailBindings extends Bindings {
|
||||
Get.lazyPut(() => ExportAttachmentInteractor(
|
||||
Get.find<EmailRepository>(),
|
||||
Get.find<CredentialRepository>()));
|
||||
Get.lazyPut(() => MoveToMailboxInteractor(Get.find<EmailRepository>()));
|
||||
Get.put(EmailController(
|
||||
Get.find<GetEmailContentInteractor>(),
|
||||
Get.find<MarkAsEmailReadInteractor>(),
|
||||
Get.find<DownloadAttachmentsInteractor>(),
|
||||
Get.find<DeviceManager>(),
|
||||
Get.find<AppToast>(),
|
||||
Get.find<ExportAttachmentInteractor>()));
|
||||
Get.find<ExportAttachmentInteractor>(),
|
||||
Get.find<MoveToMailboxInteractor>()));
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,22 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/download_attachments_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachments_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
@@ -38,6 +42,7 @@ class EmailController extends BaseController {
|
||||
final DeviceManager _deviceManager;
|
||||
final AppToast _appToast;
|
||||
final ExportAttachmentInteractor _exportAttachmentInteractor;
|
||||
final MoveToMailboxInteractor _moveToMailboxInteractor;
|
||||
|
||||
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
|
||||
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
|
||||
@@ -50,6 +55,7 @@ class EmailController extends BaseController {
|
||||
this._deviceManager,
|
||||
this._appToast,
|
||||
this._exportAttachmentInteractor,
|
||||
this._moveToMailboxInteractor,
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -101,6 +107,8 @@ class EmailController extends BaseController {
|
||||
_markAsEmailReadSuccess(success);
|
||||
} else if (success is ExportAttachmentSuccess) {
|
||||
_exportAttachmentSuccessAction(success);
|
||||
} else if (success is MoveToMailboxSuccess) {
|
||||
_moveToMailboxSuccess(success);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -231,18 +239,36 @@ class EmailController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
void openDestinationPickerView(PresentationEmail email) {
|
||||
final currentMailboxId = mailboxDashBoardController.selectedMailbox.value?.id;
|
||||
void openDestinationPickerView(PresentationEmail email) async {
|
||||
final currentMailbox = mailboxDashBoardController.selectedMailbox.value;
|
||||
final accountId = mailboxDashBoardController.accountId.value;
|
||||
|
||||
if (currentMailboxId != null && accountId != null) {
|
||||
push(
|
||||
if (currentMailbox != null && accountId != null) {
|
||||
final mailboxDestination = await push(
|
||||
AppRoutes.DESTINATION_PICKER,
|
||||
arguments: DestinationPickerArguments(accountId, [email.id], currentMailboxId)
|
||||
arguments: DestinationPickerArguments(accountId, [email.id], currentMailbox)
|
||||
);
|
||||
|
||||
if (mailboxDestination != null && mailboxDestination is PresentationMailbox) {
|
||||
_moveToMailbox(accountId, MoveRequest(
|
||||
email.id,
|
||||
currentMailbox.id,
|
||||
currentMailbox.name ?? MailboxName(''),
|
||||
mailboxDestination.id,
|
||||
mailboxDestination.name ?? MailboxName(''),
|
||||
MoveAction.moveTo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _moveToMailbox(AccountId accountId, MoveRequest moveRequest) {
|
||||
consumeState(_moveToMailboxInteractor.execute(accountId, moveRequest));
|
||||
}
|
||||
|
||||
void _moveToMailboxSuccess(Success success) {
|
||||
mailboxDashBoardController.dispatchState(Right(success));
|
||||
}
|
||||
|
||||
bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null
|
||||
&& mailboxDashBoardController.userProfile.value != null
|
||||
&& mailboxDashBoardController.mapMailboxId.containsKey(PresentationMailbox.roleOutbox)
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/sender_and_rec
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
|
||||
class EmailView extends GetWidget {
|
||||
class EmailView extends GetView {
|
||||
|
||||
final emailController = Get.find<EmailController>();
|
||||
final responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
||||
@@ -77,16 +78,26 @@ class ThreadController extends BaseController {
|
||||
if (success is MarkAsEmailReadSuccess ||
|
||||
success is MarkAsMultipleEmailReadAllSuccess ||
|
||||
success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
|
||||
_refreshListEmailMarkAsRead();
|
||||
_refreshListEmail();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mailboxDashBoardController.viewState.listen((state) {
|
||||
state.map((success) {
|
||||
if (success is MoveToMailboxSuccess) {
|
||||
_refreshListEmail();
|
||||
mailboxDashBoardController.clearState();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
mailboxDashBoardController.selectedMailbox.close();
|
||||
mailboxDashBoardController.viewState.close();
|
||||
listEmailController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
@@ -233,7 +244,7 @@ class ThreadController extends BaseController {
|
||||
currentSelectMode.value = SelectMode.INACTIVE;
|
||||
}
|
||||
|
||||
void _refreshListEmailMarkAsRead() {
|
||||
void _refreshListEmail() {
|
||||
final newLimit = emailList.isNotEmpty ? UnsignedInt(emailList.length) : ThreadConstants.defaultLimit;
|
||||
loadMoreState.value = LoadMoreState.IDLE;
|
||||
emailList.clear();
|
||||
@@ -320,14 +331,15 @@ class ThreadController extends BaseController {
|
||||
}
|
||||
|
||||
void moveSelectedMultipleEmailToMailboxAction(List<PresentationEmail> listEmail) {
|
||||
final currentMailbox = mailboxDashBoardController.selectedMailbox.value;
|
||||
final accountId = mailboxDashBoardController.accountId.value;
|
||||
if (_currentMailboxId != null && accountId != null) {
|
||||
if (currentMailbox != null && accountId != null) {
|
||||
popBack();
|
||||
|
||||
final listEmailIds = listEmail.map((email) => email.id).toList();
|
||||
push(
|
||||
AppRoutes.DESTINATION_PICKER,
|
||||
arguments: DestinationPickerArguments(accountId, listEmailIds, _currentMailboxId!)
|
||||
arguments: DestinationPickerArguments(accountId, listEmailIds, currentMailbox)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,5 +393,20 @@ class AppLocalizations {
|
||||
name: 'browse',
|
||||
);
|
||||
}
|
||||
|
||||
String moved_to_mailbox(String destinationMailboxPath) {
|
||||
return Intl.message(
|
||||
'Moved to $destinationMailboxPath',
|
||||
name: 'moved_to_mailbox',
|
||||
args: [destinationMailboxPath]
|
||||
);
|
||||
}
|
||||
|
||||
String get undo_action {
|
||||
return Intl.message(
|
||||
'UNDO',
|
||||
name: 'undo_action'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
enum MoveAction {
|
||||
moveTo,
|
||||
undo
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:jmap_dart_client/jmap/core/patch_object.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
|
||||
extension MailboxIdExtension on MailboxId {
|
||||
String generatePath() {
|
||||
return '${PatchObject.mailboxIdsProperty}/${id.value}';
|
||||
}
|
||||
|
||||
PatchObject generateMoveToMailboxActionPath(MailboxId destinationMailboxId) {
|
||||
return PatchObject({
|
||||
generatePath(): null,
|
||||
destinationMailboxId.generatePath(): true
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export 'email/presentation_email_address.dart';
|
||||
export 'email/email_address_cache.dart';
|
||||
export 'email/read_actions.dart';
|
||||
export 'email/attachment.dart';
|
||||
export 'email/move_action.dart';
|
||||
|
||||
// Extensions
|
||||
export 'extensions/email_address_extension.dart';
|
||||
@@ -37,6 +38,7 @@ export 'extensions/keyword_identifier_extension.dart';
|
||||
export 'extensions/presentation_mailbox_extension.dart';
|
||||
export 'extensions/email_body_part_extension.dart';
|
||||
export 'extensions/attachment_extension.dart';
|
||||
export 'extensions/mailbox_id_extension.dart';
|
||||
|
||||
// Download
|
||||
export 'download/download_task_id.dart';
|
||||
|
||||
Reference in New Issue
Block a user