diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 47e11246c..41f735c8e 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -1,6 +1,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; 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'; abstract class EmailDataSource { @@ -9,4 +10,11 @@ abstract class EmailDataSource { Future sendEmail(AccountId accountId, EmailRequest emailRequest); Future markAsRead(AccountId accountId, EmailId emailId, ReadActions readActions); + + Future> downloadAttachments( + List attachments, + AccountId accountId, + String baseDownloadUrl, + AccountRequest accountRequest + ); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index 5f331fc14..a0bf60cc0 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -1,6 +1,9 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/email/read_actions.dart'; +import 'package:model/account/account_request.dart'; +import 'package:model/download/download_task_id.dart'; +import 'package:model/email/attachment.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'; @@ -37,4 +40,18 @@ class EmailDataSourceImpl extends EmailDataSource { throw error; }); } + + @override + Future> downloadAttachments( + List attachments, + AccountId accountId, + String baseDownloadUrl, + AccountRequest accountRequest + ) { + return Future.sync(() async { + return await emailAPI.downloadAttachments(attachments, accountId, baseDownloadUrl, accountRequest); + }).catchError((error) { + throw error; + }); + } } \ No newline at end of file diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index cdac1fc19..1c853fdea 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -1,5 +1,10 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:core/core.dart'; +import 'package:external_path/external_path.dart'; +import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.dart'; @@ -18,6 +23,7 @@ import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission.dar import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/envelope.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/set/set_email_submission_method.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:model/model.dart'; @@ -111,7 +117,7 @@ class EmailAPI { emailId.id: KeyWordIdentifier.emailSeen.generateReadActionPath(readAction) }); - final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation()); + final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); final setEmailInvocation = requestBuilder.invocation(setEmailMethod); @@ -131,4 +137,39 @@ class EmailAPI { throw error; }); } + + Future> downloadAttachments( + List attachments, + AccountId accountId, + String baseDownloadUrl, + AccountRequest accountRequest + ) async { + var externalStorageDirPath; + if (Platform.isAndroid) { + externalStorageDirPath = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS); + } else if (Platform.isIOS) { + externalStorageDirPath = (await getApplicationDocumentsDirectory()).absolute.path; + } else { + throw DeviceNotSupportedException(); + } + + final basicAuth = 'Basic ' + base64Encode(utf8.encode('${accountRequest.userName.userName}:${accountRequest.password.value}')); + + final taskIds = await Future.wait( + attachments.map((attachment) async => await FlutterDownloader.enqueue( + url: attachment.getDownloadUrl(baseDownloadUrl, accountId), + savedDir: externalStorageDirPath, + headers: { + HttpHeaders.authorizationHeader: basicAuth, + HttpHeaders.acceptHeader: DioClient.jmapHeader + }, + fileName: attachment.name, + showNotification: true, + openFileFromNotification: true))); + + return taskIds + .where((taskId) => taskId != null) + .map((taskId) => DownloadTaskId(taskId!)) + .toList(); + } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index 6405cdaf6..3afbed3a4 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -2,6 +2,9 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/email/read_actions.dart'; +import 'package:model/account/account_request.dart'; +import 'package:model/download/download_task_id.dart'; +import 'package:model/email/attachment.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/repository/email_repository.dart'; @@ -26,4 +29,14 @@ class EmailRepositoryImpl extends EmailRepository { Future markAsRead(AccountId accountId, EmailId emailId, ReadActions readAction) { return emailDataSource.markAsRead(accountId, emailId, readAction); } + + @override + Future> downloadAttachments( + List attachments, + AccountId accountId, + String baseDownloadUrl, + AccountRequest accountRequest + ) { + return emailDataSource.downloadAttachments(attachments, accountId, baseDownloadUrl, accountRequest); + } } \ No newline at end of file