TF-1604: Add requiredCapabilities support TeamMailbox for GetEmailMethod

(cherry picked from commit 3922303e63a8e910511361019a54ea13801e3f92)
This commit is contained in:
HuyNguyen
2023-03-21 23:29:45 +07:00
committed by Dat Vu
parent 890ca4c8cd
commit 8a28225e05
41 changed files with 516 additions and 197 deletions
+1 -1
View File
@@ -232,7 +232,7 @@ abstract class BaseController extends GetxController
await LocalNotificationManager.instance.setUp(); await LocalNotificationManager.instance.setUp();
} }
FcmInteractorBindings().dependencies(); FcmInteractorBindings().dependencies();
FcmController.instance.initialize(accountId: accountId); FcmController.instance.initialize(session: session,accountId: accountId);
} else { } else {
throw NotSupportFCMException(); throw NotSupportFCMException();
} }
@@ -1095,11 +1095,13 @@ class ComposerController extends BaseController {
_emailContents = arguments.emailContents; _emailContents = arguments.emailContents;
emailContentsViewState.value = Right(GetEmailContentSuccess(_emailContents!, [], [], null)); emailContentsViewState.value = Right(GetEmailContentSuccess(_emailContents!, [], [], null));
} else { } else {
final session = mailboxDashBoardController.sessionCurrent;
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl); final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
final accountId = mailboxDashBoardController.sessionCurrent?.accounts.keys.first; final accountId = mailboxDashBoardController.sessionCurrent?.accounts.keys.first;
final emailId = arguments.presentationEmail?.id; final emailId = arguments.presentationEmail?.id;
if (emailId != null && baseDownloadUrl != null && accountId != null) { if (session != null && emailId != null && baseDownloadUrl != null && accountId != null) {
consumeState(_getEmailContentInteractor.execute( consumeState(_getEmailContentInteractor.execute(
session,
accountId, accountId,
emailId, emailId,
baseDownloadUrl, baseDownloadUrl,
@@ -5,6 +5,7 @@ import 'package:core/core.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.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:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
@@ -12,7 +13,7 @@ import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_reques
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
abstract class EmailDataSource { abstract class EmailDataSource {
Future<Email> getEmailContent(AccountId accountId, EmailId emailId); Future<Email> getEmailContent(Session session, AccountId accountId, EmailId emailId);
Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest}); Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest});
@@ -7,6 +7,7 @@ import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.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:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
@@ -24,9 +25,9 @@ class EmailDataSourceImpl extends EmailDataSource {
EmailDataSourceImpl(this.emailAPI, this._exceptionThrower); EmailDataSourceImpl(this.emailAPI, this._exceptionThrower);
@override @override
Future<Email> getEmailContent(AccountId accountId, EmailId emailId) { Future<Email> getEmailContent(Session session, AccountId accountId, EmailId emailId) {
return Future.sync(() async { return Future.sync(() async {
return await emailAPI.getEmailContent(accountId, emailId); return await emailAPI.getEmailContent(session, accountId, emailId);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
+20 -2
View File
@@ -17,6 +17,7 @@ import 'package:jmap_dart_client/jmap/core/patch_object.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/reference_id.dart'; import 'package:jmap_dart_client/jmap/core/reference_id.dart';
import 'package:jmap_dart_client/jmap/core/reference_prefix.dart'; import 'package:jmap_dart_client/jmap/core/reference_prefix.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/jmap_request.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/get/get_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/get/get_email_method.dart';
@@ -66,7 +67,24 @@ class EmailAPI with HandleSetErrorMixin {
EmailAPI(this._httpClient, this._downloadManager, this._dioClient, this._uuid); EmailAPI(this._httpClient, this._downloadManager, this._dioClient, this._uuid);
Future<Email> getEmailContent(AccountId accountId, EmailId emailId) async { Set<CapabilityIdentifier> _capabilitiesForEmailMethod(Session session, AccountId accountId) {
final getMailboxCreated = GetEmailMethod(accountId);
try {
requireCapability(
session,
accountId,
[CapabilityIdentifier.jmapTeamMailboxes]);
return {
CapabilityIdentifier.jmapCore,
CapabilityIdentifier.jmapMail,
CapabilityIdentifier.jmapTeamMailboxes
};
} catch (_) {
return getMailboxCreated.requiredCapabilities;
}
}
Future<Email> getEmailContent(Session session, AccountId accountId, EmailId emailId) async {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(_httpClient, processingInvocation); final jmapRequestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
@@ -86,7 +104,7 @@ class EmailAPI with HandleSetErrorMixin {
final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod); final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod);
final result = await (jmapRequestBuilder final result = await (jmapRequestBuilder
..usings(getEmailMethod.requiredCapabilities)) ..usings(_capabilitiesForEmailMethod(session, accountId)))
.build() .build()
.execute(); .execute();
@@ -6,6 +6,7 @@ import 'package:core/core.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.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/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
@@ -31,8 +32,8 @@ class EmailRepositoryImpl extends EmailRepository {
); );
@override @override
Future<Email> getEmailContent(AccountId accountId, EmailId emailId) { Future<Email> getEmailContent(Session session, AccountId accountId, EmailId emailId) {
return emailDataSource.getEmailContent(accountId, emailId); return emailDataSource.getEmailContent(session ,accountId, emailId);
} }
@override @override
@@ -5,6 +5,7 @@ import 'package:core/core.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.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/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/model.dart'; import 'package:model/model.dart';
@@ -13,7 +14,7 @@ import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_reques
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
abstract class EmailRepository { abstract class EmailRepository {
Future<Email> getEmailContent(AccountId accountId, EmailId emailId); Future<Email> getEmailContent(Session session, AccountId accountId, EmailId emailId);
Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest}); Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest});
@@ -4,6 +4,7 @@ import 'package:core/utils/app_logger.dart';
import 'package:core/utils/build_utils.dart'; import 'package:core/utils/build_utils.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:model/extensions/email_extension.dart'; import 'package:model/extensions/email_extension.dart';
import 'package:model/extensions/list_attachment_extension.dart'; import 'package:model/extensions/list_attachment_extension.dart';
@@ -16,6 +17,7 @@ class GetEmailContentInteractor {
GetEmailContentInteractor(this.emailRepository); GetEmailContentInteractor(this.emailRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
EmailId emailId, EmailId emailId,
String? baseDownloadUrl, String? baseDownloadUrl,
@@ -26,7 +28,7 @@ class GetEmailContentInteractor {
) async* { ) async* {
try { try {
yield Right<Failure, Success>(GetEmailContentLoading()); yield Right<Failure, Success>(GetEmailContentLoading());
final email = await emailRepository.getEmailContent(accountId, emailId); final email = await emailRepository.getEmailContent(session, accountId, emailId);
if (email.emailContentList.isNotEmpty) { if (email.emailContentList.isNotEmpty) {
final newEmailContents = await emailRepository.transformEmailContent( final newEmailContents = await emailRepository.transformEmailContent(
@@ -293,6 +293,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
} }
void _getEmailContentAction(EmailId emailId) async { void _getEmailContentAction(EmailId emailId) async {
final session = mailboxDashBoardController.sessionCurrent;
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl); final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
final emailLoaded = emailSupervisorController.getEmailInQueueByEmailId(emailId); final emailLoaded = emailSupervisorController.getEmailInQueueByEmailId(emailId);
@@ -305,8 +306,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
emailLoaded.emailContentsDisplayed, emailLoaded.emailContentsDisplayed,
emailLoaded.attachments, emailLoaded.attachments,
emailLoaded.emailCurrent)))); emailLoaded.emailCurrent))));
} else if (accountId != null && baseDownloadUrl != null) { } else if (session != null && accountId != null && baseDownloadUrl != null) {
consumeState(_getEmailContentInteractor.execute(accountId, emailId, baseDownloadUrl)); consumeState(_getEmailContentInteractor.execute(session, accountId, emailId, baseDownloadUrl));
} }
} }
@@ -1,23 +1,32 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.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/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart';
class MailboxMarkAsReadArguments with EquatableMixin { class MailboxMarkAsReadArguments with EquatableMixin {
final Session session;
final AccountId accountId; final AccountId accountId;
final MailboxId mailboxId; final MailboxId mailboxId;
final ThreadAPI threadAPI; final ThreadAPI threadAPI;
final EmailAPI emailAPI; final EmailAPI emailAPI;
MailboxMarkAsReadArguments( MailboxMarkAsReadArguments(
this.session,
this.threadAPI, this.threadAPI,
this.emailAPI, this.emailAPI,
this.accountId, this.accountId,
this.mailboxId); this.mailboxId);
@override @override
List<Object?> get props => [accountId, mailboxId]; List<Object?> get props => [
session,
accountId,
threadAPI,
emailAPI,
mailboxId
];
} }
@@ -43,25 +43,27 @@ class MailboxIsolateWorker {
) async { ) async {
if (BuildUtils.isWeb) { if (BuildUtils.isWeb) {
return _handleMarkAsMailboxReadActionOnWeb( return _handleMarkAsMailboxReadActionOnWeb(
accountId, session,
mailboxId, accountId,
totalEmailUnread, mailboxId,
onProgressController); totalEmailUnread,
onProgressController);
} else { } else {
final result = await _isolateExecutor.execute( final result = await _isolateExecutor.execute(
arg1: MailboxMarkAsReadArguments( arg1: MailboxMarkAsReadArguments(
_threadApi, session,
_emailApi, _threadApi,
accountId, _emailApi,
mailboxId), accountId,
mailboxId),
fun1: _handleMarkAsMailboxReadAction, fun1: _handleMarkAsMailboxReadAction,
notification: (value) { notification: (value) {
if (value is List<Email>) { if (value is List<Email>) {
log('MailboxIsolateWorker::markAsMailboxRead(): onUpdateProgress: PERCENT ${value.length / totalEmailUnread}'); log('MailboxIsolateWorker::markAsMailboxRead(): onUpdateProgress: PERCENT ${value.length / totalEmailUnread}');
onProgressController.add(Right(UpdatingMarkAsMailboxReadState( onProgressController.add(Right(UpdatingMarkAsMailboxReadState(
mailboxId: mailboxId, mailboxId: mailboxId,
totalUnread: totalEmailUnread, totalUnread: totalEmailUnread,
countRead: value.length))); countRead: value.length)));
} }
}); });
return result; return result;
@@ -80,16 +82,18 @@ class MailboxIsolateWorker {
while (mailboxHasEmails) { while (mailboxHasEmails) {
final emailResponse = await args.threadAPI final emailResponse = await args.threadAPI
.getAllEmail(args.accountId, .getAllEmail(
limit: UnsignedInt(30), args.session,
filter: EmailFilterCondition( args.accountId,
limit: UnsignedInt(30),
filter: EmailFilterCondition(
inMailbox: args.mailboxId, inMailbox: args.mailboxId,
notKeyword: KeyWordIdentifier.emailSeen.value, notKeyword: KeyWordIdentifier.emailSeen.value,
before: lastReceivedDate), before: lastReceivedDate),
sort: <Comparator>{}..add( sort: <Comparator>{}..add(
EmailComparator(EmailComparatorProperty.receivedAt) EmailComparator(EmailComparatorProperty.receivedAt)
..setIsAscending(false)), ..setIsAscending(false)),
properties: Properties({ properties: Properties({
EmailProperty.id, EmailProperty.id,
EmailProperty.keywords, EmailProperty.keywords,
EmailProperty.receivedAt, EmailProperty.receivedAt,
@@ -98,8 +102,8 @@ class MailboxIsolateWorker {
var listEmails = response.emailList; var listEmails = response.emailList;
if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) { if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) {
listEmails = listEmails listEmails = listEmails
.where((email) => email.id != lastEmailId) .where((email) => email.id != lastEmailId)
.toList(); .toList();
} }
return EmailsResponse(emailList: listEmails, state: response.state); return EmailsResponse(emailList: listEmails, state: response.state);
}); });
@@ -131,10 +135,11 @@ class MailboxIsolateWorker {
} }
Future<List<Email>> _handleMarkAsMailboxReadActionOnWeb( Future<List<Email>> _handleMarkAsMailboxReadActionOnWeb(
AccountId accountId, Session session,
MailboxId mailboxId, AccountId accountId,
int totalEmailUnread, MailboxId mailboxId,
StreamController<Either<Failure, Success>> onProgressController int totalEmailUnread,
StreamController<Either<Failure, Success>> onProgressController
) async { ) async {
List<Email> emailListCompleted = List.empty(growable: true); List<Email> emailListCompleted = List.empty(growable: true);
try { try {
@@ -144,28 +149,30 @@ class MailboxIsolateWorker {
while (mailboxHasEmails) { while (mailboxHasEmails) {
final emailResponse = await _threadApi final emailResponse = await _threadApi
.getAllEmail(accountId, .getAllEmail(
limit: UnsignedInt(30), session,
filter: EmailFilterCondition( accountId,
inMailbox: mailboxId, limit: UnsignedInt(30),
notKeyword: KeyWordIdentifier.emailSeen.value, filter: EmailFilterCondition(
before: lastReceivedDate), inMailbox: mailboxId,
sort: <Comparator>{}..add( notKeyword: KeyWordIdentifier.emailSeen.value,
before: lastReceivedDate),
sort: <Comparator>{}..add(
EmailComparator(EmailComparatorProperty.receivedAt) EmailComparator(EmailComparatorProperty.receivedAt)
..setIsAscending(false)), ..setIsAscending(false)),
properties: Properties({ properties: Properties({
EmailProperty.id, EmailProperty.id,
EmailProperty.keywords, EmailProperty.keywords,
EmailProperty.receivedAt, EmailProperty.receivedAt,
})) })
.then((response) { ).then((response) {
var listEmails = response.emailList; var listEmails = response.emailList;
if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) { if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) {
listEmails = listEmails listEmails = listEmails
.where((email) => email.id != lastEmailId) .where((email) => email.id != lastEmailId)
.toList(); .toList();
} }
return EmailsResponse(emailList: listEmails, state: response.state); return EmailsResponse(emailList: listEmails, state: response.state);
}); });
final listEmailUnread = emailResponse.emailList; final listEmailUnread = emailResponse.emailList;
@@ -1,5 +1,6 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/model.dart'; import 'package:model/model.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';
@@ -17,6 +18,7 @@ class QuickSearchEmailInteractor {
QuickSearchEmailInteractor(this.threadRepository); QuickSearchEmailInteractor(this.threadRepository);
Future<Either<Failure, Success>> execute( Future<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -27,6 +29,7 @@ class QuickSearchEmailInteractor {
) async { ) async {
try { try {
final emailList = await threadRepository.searchEmails( final emailList = await threadRepository.searchEmails(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -1074,8 +1074,8 @@ class MailboxDashBoardController extends ReloadableController {
onCancelSelectionEmail?.call(); onCancelSelectionEmail?.call();
final trashMailboxId = mapDefaultMailboxIdByRole[PresentationMailbox.roleTrash]; final trashMailboxId = mapDefaultMailboxIdByRole[PresentationMailbox.roleTrash];
if (accountId.value != null && trashMailboxId != null) { if (sessionCurrent != null && accountId.value != null && trashMailboxId != null) {
consumeState(_emptyTrashFolderInteractor.execute(accountId.value!, trashMailboxId)); consumeState(_emptyTrashFolderInteractor.execute(sessionCurrent!, accountId.value!, trashMailboxId));
} }
} }
@@ -1285,7 +1285,10 @@ class MailboxDashBoardController extends ReloadableController {
searchController.addFilterToSuggestionForm(filter); searchController.addFilterToSuggestionForm(filter);
} }
Future<List<PresentationEmail>> quickSearchEmails() => searchController.quickSearchEmails(accountId: accountId.value!); Future<List<PresentationEmail>> quickSearchEmails() => searchController.quickSearchEmails(
session: sessionCurrent!,
accountId: accountId.value!
);
void addDownloadTask(DownloadTaskState task) { void addDownloadTask(DownloadTaskState task) {
downloadController.addDownloadTask(task); downloadController.addDownloadTask(task);
@@ -1479,11 +1482,12 @@ class MailboxDashBoardController extends ReloadableController {
void _handleNotificationMessageFromEmailId(EmailId emailId, {bool onForeground = true}) { void _handleNotificationMessageFromEmailId(EmailId emailId, {bool onForeground = true}) {
final currentAccountId = accountId.value; final currentAccountId = accountId.value;
if (currentAccountId != null) { final session = sessionCurrent;
if (currentAccountId != null && session != null) {
if (onForeground) { if (onForeground) {
_showWaitingView(); _showWaitingView();
} }
_getPresentationEmailFromEmailIdAction(emailId, currentAccountId); _getPresentationEmailFromEmailIdAction(emailId, currentAccountId, session);
} else { } else {
dispatchRoute(DashboardRoutes.thread); dispatchRoute(DashboardRoutes.thread);
} }
@@ -1500,9 +1504,10 @@ class MailboxDashBoardController extends ReloadableController {
dispatchRoute(DashboardRoutes.thread); dispatchRoute(DashboardRoutes.thread);
} }
void _getPresentationEmailFromEmailIdAction(EmailId emailId, AccountId accountId) { void _getPresentationEmailFromEmailIdAction(EmailId emailId, AccountId accountId, Session session) {
log('MailboxDashBoardController:_getPresentationEmailFromEmailIdAction:emailId: $emailId'); log('MailboxDashBoardController:_getPresentationEmailFromEmailIdAction:emailId: $emailId');
consumeState(_getEmailByIdInteractor.execute( consumeState(_getEmailByIdInteractor.execute(
session,
accountId, accountId,
emailId, emailId,
properties: ThreadConstants.propertiesDefault properties: ThreadConstants.propertiesDefault
@@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart';
import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart';
@@ -103,10 +104,12 @@ class SearchController extends BaseController with DateRangePickerMixin {
} }
Future<List<PresentationEmail>> quickSearchEmails({ Future<List<PresentationEmail>> quickSearchEmails({
required Session session,
required AccountId accountId, required AccountId accountId,
UserProfile? userProfile UserProfile? userProfile
}) async { }) async {
return await _quickSearchEmailInteractor.execute( return await _quickSearchEmailInteractor.execute(
session,
accountId, accountId,
limit: UnsignedInt(5), limit: UnsignedInt(5),
sort: <Comparator>{}..add( sort: <Comparator>{}..add(
@@ -3,6 +3,7 @@ import 'package:fcm/model/firebase_subscription.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/fcm_subscription_extensions.dart'; import 'package:tmail_ui_user/features/push_notification/data/extensions/fcm_subscription_extensions.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
@@ -25,6 +26,7 @@ class FCMRepositoryImpl extends FCMRepository {
@override @override
Future<EmailsResponse> getEmailChangesToPushNotification( Future<EmailsResponse> getEmailChangesToPushNotification(
Session session,
AccountId accountId, AccountId accountId,
jmap.State currentState, jmap.State currentState,
{ {
@@ -38,6 +40,7 @@ class FCMRepositoryImpl extends FCMRepository {
while (hasMoreChanges && sinceState != null) { while (hasMoreChanges && sinceState != null) {
final changesResponse = await _threadDataSource.getChanges( final changesResponse = await _threadDataSource.getChanges(
session,
accountId, accountId,
sinceState, sinceState,
propertiesCreated: propertiesCreated, propertiesCreated: propertiesCreated,
@@ -2,6 +2,7 @@ import 'package:fcm/model/firebase_subscription.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
@@ -9,6 +10,7 @@ import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
abstract class FCMRepository { abstract class FCMRepository {
Future<EmailsResponse> getEmailChangesToPushNotification( Future<EmailsResponse> getEmailChangesToPushNotification(
Session session,
AccountId accountId, AccountId accountId,
jmap.State currentState, jmap.State currentState,
{ {
@@ -3,6 +3,7 @@ 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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/extensions/email_extension.dart'; import 'package:model/extensions/email_extension.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
@@ -14,6 +15,7 @@ class GetEmailChangesToPushNotificationInteractor {
GetEmailChangesToPushNotificationInteractor(this._fcmRepository); GetEmailChangesToPushNotificationInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
jmap.State currentState, jmap.State currentState,
{ {
@@ -25,6 +27,7 @@ class GetEmailChangesToPushNotificationInteractor {
yield Right<Failure, Success>(GetEmailChangesToPushNotificationLoading()); yield Right<Failure, Success>(GetEmailChangesToPushNotificationLoading());
final emailsResponse = await _fcmRepository.getEmailChangesToPushNotification( final emailsResponse = await _fcmRepository.getEmailChangesToPushNotification(
session,
accountId, accountId,
currentState, currentState,
propertiesCreated: propertiesCreated, propertiesCreated: propertiesCreated,
@@ -1,6 +1,7 @@
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.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:tmail_ui_user/features/base/action/ui_action.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
@@ -20,16 +21,18 @@ class SynchronizeEmailOnForegroundAction extends FcmStateChangeAction {
class PushNotificationAction extends FcmStateChangeAction { class PushNotificationAction extends FcmStateChangeAction {
final Session session;
final AccountId accountId; final AccountId accountId;
PushNotificationAction( PushNotificationAction(
TypeName typeName, TypeName typeName,
jmap.State newState, jmap.State newState,
this.session,
this.accountId this.accountId
) : super(typeName, newState); ) : super(typeName, newState);
@override @override
List<Object?> get props => [typeName, newState, accountId]; List<Object?> get props => [typeName, newState, accountId, session];
} }
class StoreEmailStateToRefreshAction extends FcmStateChangeAction { class StoreEmailStateToRefreshAction extends FcmStateChangeAction {
@@ -10,6 +10,7 @@ import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.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/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/push/state_change.dart'; import 'package:jmap_dart_client/jmap/push/state_change.dart';
import 'package:model/oidc/token_oidc.dart'; import 'package:model/oidc/token_oidc.dart';
@@ -37,6 +38,7 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class FcmController extends BaseController { class FcmController extends BaseController {
AccountId? _currentAccountId; AccountId? _currentAccountId;
Session? _currentSession;
RemoteMessage? _remoteMessageBackground; RemoteMessage? _remoteMessageBackground;
GetAuthenticatedAccountInteractor? _getAuthenticatedAccountInteractor; GetAuthenticatedAccountInteractor? _getAuthenticatedAccountInteractor;
@@ -50,7 +52,8 @@ class FcmController extends BaseController {
static FcmController get instance => _instance; static FcmController get instance => _instance;
void initialize({AccountId? accountId}) { void initialize({Session? session, AccountId? accountId}) {
_currentSession = session;
_currentAccountId = accountId; _currentAccountId = accountId;
FcmTokenHandler.instance.initialize(); FcmTokenHandler.instance.initialize();
} }
@@ -86,10 +89,10 @@ class FcmController extends BaseController {
void _handleForegroundMessageAction(RemoteMessage newRemoteMessage) { void _handleForegroundMessageAction(RemoteMessage newRemoteMessage) {
log('FcmController::_handleForegroundMessageAction():remoteMessage: ${newRemoteMessage.data}'); log('FcmController::_handleForegroundMessageAction():remoteMessage: ${newRemoteMessage.data}');
if (_currentAccountId != null) { if (_currentAccountId != null && _currentSession != null) {
final stateChange = _convertRemoteMessageToStateChange(newRemoteMessage); final stateChange = _convertRemoteMessageToStateChange(newRemoteMessage);
final mapTypeState = stateChange.getMapTypeState(_currentAccountId!); final mapTypeState = stateChange.getMapTypeState(_currentAccountId!);
_mappingTypeStateToAction(mapTypeState, _currentAccountId!); _mappingTypeStateToAction(_currentSession!, mapTypeState, _currentAccountId!);
} }
} }
@@ -105,6 +108,7 @@ class FcmController extends BaseController {
} }
void _mappingTypeStateToAction( void _mappingTypeStateToAction(
Session session,
Map<String, dynamic> mapTypeState, Map<String, dynamic> mapTypeState,
AccountId accountId, { AccountId accountId, {
bool isForeground = true, bool isForeground = true,
@@ -116,7 +120,7 @@ class FcmController extends BaseController {
final listEmailActions = listTypeName final listEmailActions = listTypeName
.where((typeName) => typeName == TypeName.emailType || typeName == TypeName.emailDelivery) .where((typeName) => typeName == TypeName.emailType || typeName == TypeName.emailDelivery)
.map((typeName) => toFcmAction(typeName, accountId, mapTypeState, isForeground)) .map((typeName) => toFcmAction(session, typeName, accountId, mapTypeState, isForeground))
.whereNotNull() .whereNotNull()
.toList(); .toList();
@@ -128,7 +132,7 @@ class FcmController extends BaseController {
final listMailboxActions = listTypeName final listMailboxActions = listTypeName
.where((typeName) => typeName == TypeName.mailboxType) .where((typeName) => typeName == TypeName.mailboxType)
.map((typeName) => toFcmAction(typeName, accountId, mapTypeState, isForeground)) .map((typeName) => toFcmAction(session, typeName, accountId, mapTypeState, isForeground))
.whereNotNull() .whereNotNull()
.toList(); .toList();
@@ -140,6 +144,7 @@ class FcmController extends BaseController {
} }
FcmAction? toFcmAction( FcmAction? toFcmAction(
Session session,
TypeName typeName, TypeName typeName,
AccountId accountId, AccountId accountId,
Map<String, dynamic> mapTypeState, Map<String, dynamic> mapTypeState,
@@ -154,7 +159,7 @@ class FcmController extends BaseController {
} }
} else if (typeName == TypeName.emailDelivery) { } else if (typeName == TypeName.emailDelivery) {
if (!isForeground) { if (!isForeground) {
return PushNotificationAction(typeName, newState, accountId); return PushNotificationAction(typeName, newState, session, accountId);
} }
} else if (typeName == TypeName.mailboxType) { } else if (typeName == TypeName.mailboxType) {
if (isForeground) { if (isForeground) {
@@ -243,10 +248,10 @@ class FcmController extends BaseController {
void _pushActionFromRemoteMessageBackground() { void _pushActionFromRemoteMessageBackground() {
log('FcmController::_pushActionFromRemoteMessageBackground():'); log('FcmController::_pushActionFromRemoteMessageBackground():');
if (_remoteMessageBackground != null && _currentAccountId != null) { if (_remoteMessageBackground != null && _currentAccountId != null && _currentSession != null) {
final stateChange = _convertRemoteMessageToStateChange(_remoteMessageBackground!); final stateChange = _convertRemoteMessageToStateChange(_remoteMessageBackground!);
final mapTypeState = stateChange.getMapTypeState(_currentAccountId!); final mapTypeState = stateChange.getMapTypeState(_currentAccountId!);
_mappingTypeStateToAction(mapTypeState, _currentAccountId!, isForeground: false); _mappingTypeStateToAction(_currentSession!, mapTypeState, _currentAccountId!, isForeground: false);
} }
_clearRemoteMessageBackground(); _clearRemoteMessageBackground();
} }
@@ -6,6 +6,7 @@ import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/build_utils.dart'; import 'package:core/utils/build_utils.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/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/email/presentation_email.dart'; import 'package:model/email/presentation_email.dart';
import 'package:model/notification/notification_payload.dart'; import 'package:model/notification/notification_payload.dart';
@@ -41,6 +42,7 @@ class EmailChangeListener extends ChangeListener {
jmap.State? _newState; jmap.State? _newState;
AccountId? _accountId; AccountId? _accountId;
Session? _session;
EmailChangeListener._internal() { EmailChangeListener._internal() {
try { try {
@@ -66,7 +68,7 @@ class EmailChangeListener extends ChangeListener {
if (action is SynchronizeEmailOnForegroundAction) { if (action is SynchronizeEmailOnForegroundAction) {
_synchronizeEmailOnForegroundAction(action.newState); _synchronizeEmailOnForegroundAction(action.newState);
} else if (action is PushNotificationAction) { } else if (action is PushNotificationAction) {
_pushNotificationAction(action.newState, action.accountId); _pushNotificationAction(action.newState, action.accountId, action.session);
} else if (action is StoreEmailStateToRefreshAction) { } else if (action is StoreEmailStateToRefreshAction) {
_handleStoreEmailStateToRefreshAction(action.newState); _handleStoreEmailStateToRefreshAction(action.newState);
} }
@@ -80,7 +82,7 @@ class EmailChangeListener extends ChangeListener {
} }
} }
void _pushNotificationAction(jmap.State newState, AccountId accountId) { void _pushNotificationAction(jmap.State newState, AccountId accountId, Session session) {
_newState = newState; _newState = newState;
_accountId = accountId; _accountId = accountId;
log('EmailChangeListener::_pushNotificationAction():newState: $newState'); log('EmailChangeListener::_pushNotificationAction():newState: $newState');
@@ -116,8 +118,9 @@ class EmailChangeListener extends ChangeListener {
} }
void _getEmailChangesAction(jmap.State state) { void _getEmailChangesAction(jmap.State state) {
if (_getEmailChangesToPushNotificationInteractor != null && _accountId != null) { if (_getEmailChangesToPushNotificationInteractor != null && _accountId != null && _session != null) {
consumeState(_getEmailChangesToPushNotificationInteractor!.execute( consumeState(_getEmailChangesToPushNotificationInteractor!.execute(
_session!,
_accountId!, _accountId!,
state, state,
propertiesCreated: ThreadConstants.propertiesDefault, propertiesCreated: ThreadConstants.propertiesDefault,
@@ -5,6 +5,7 @@ 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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:model/extensions/email_extension.dart'; import 'package:model/extensions/email_extension.dart';
@@ -18,23 +19,25 @@ class RefreshChangesSearchEmailInteractor {
RefreshChangesSearchEmailInteractor(this.threadRepository); RefreshChangesSearchEmailInteractor(this.threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
AccountId accountId, Session session,
{ AccountId accountId,
UnsignedInt? limit, {
Set<Comparator>? sort, UnsignedInt? limit,
Filter? filter, Set<Comparator>? sort,
Properties? properties, Filter? filter,
} Properties? properties,
}
) async* { ) async* {
try { try {
yield Right(RefreshingChangeSearchEmailState()); yield Right(RefreshingChangeSearchEmailState());
final emailList = await threadRepository.searchEmails( final emailList = await threadRepository.searchEmails(
accountId, session,
limit: limit, accountId,
sort: sort, limit: limit,
filter: filter, sort: sort,
properties: properties); filter: filter,
properties: properties);
final presentationEmailList = emailList final presentationEmailList = emailList
.map((email) => email.toPresentationEmail()) .map((email) => email.toPresentationEmail())
@@ -172,8 +172,8 @@ class SearchEmailController extends BaseController
textOption: value.isNotEmpty ? Some(SearchQuery(value)) : const None(), textOption: value.isNotEmpty ? Some(SearchQuery(value)) : const None(),
beforeOption: const None() beforeOption: const None()
); );
if (value.isNotEmpty && accountId != null) { if (value.isNotEmpty && session != null && accountId != null) {
listSuggestionSearch.value = await quickSearchEmails(accountId: accountId!); listSuggestionSearch.value = await quickSearchEmails(session: session!, accountId: accountId!);
} else { } else {
listSuggestionSearch.clear(); listSuggestionSearch.clear();
} }
@@ -215,12 +215,13 @@ class SearchEmailController extends BaseController
} }
void _refreshEmailChanges() { void _refreshEmailChanges() {
if (searchIsRunning.isTrue && accountId != null) { if (searchIsRunning.isTrue && session != null && accountId != null) {
final limit = listResultSearch.isNotEmpty final limit = listResultSearch.isNotEmpty
? UnsignedInt(listResultSearch.length) ? UnsignedInt(listResultSearch.length)
: ThreadConstants.defaultLimit; : ThreadConstants.defaultLimit;
_updateSimpleSearchFilter(beforeOption: const None()); _updateSimpleSearchFilter(beforeOption: const None());
consumeState(_refreshChangesSearchEmailInteractor.execute( consumeState(_refreshChangesSearchEmailInteractor.execute(
session!,
accountId!, accountId!,
limit: limit, limit: limit,
sort: <Comparator>{} sort: <Comparator>{}
@@ -259,15 +260,20 @@ class SearchEmailController extends BaseController
: <RecentSearch>[])); : <RecentSearch>[]));
} }
Future<List<PresentationEmail>> quickSearchEmails({required AccountId accountId}) async { Future<List<PresentationEmail>> quickSearchEmails({
required AccountId accountId,
required Session session,
}) async {
return _quickSearchEmailInteractor return _quickSearchEmailInteractor
.execute(accountId, .execute(
limit: UnsignedInt(5), session,
accountId,
limit: UnsignedInt(5),
sort: <Comparator>{}..add( sort: <Comparator>{}..add(
EmailComparator(EmailComparatorProperty.receivedAt) EmailComparator(EmailComparatorProperty.receivedAt)
..setIsAscending(false)), ..setIsAscending(false)),
filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), filter: simpleSearchFilter.value.mappingToEmailFilterCondition(),
properties: ThreadConstants.propertiesQuickSearch) properties: ThreadConstants.propertiesQuickSearch)
.then((result) => result.fold( .then((result) => result.fold(
(failure) => <PresentationEmail>[], (failure) => <PresentationEmail>[],
(success) => success is QuickSearchEmailSuccess (success) => success is QuickSearchEmailSuccess
@@ -282,12 +288,13 @@ class SearchEmailController extends BaseController
void _searchEmailAction(BuildContext context) { void _searchEmailAction(BuildContext context) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
if (accountId != null) { if (session != null && accountId != null) {
canSearchMore = true; canSearchMore = true;
searchIsRunning.value = true; searchIsRunning.value = true;
cancelSelectionMode(context); cancelSelectionMode(context);
consumeState(_searchEmailInteractor.execute( consumeState(_searchEmailInteractor.execute(
session!,
accountId!, accountId!,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
sort: <Comparator>{} sort: <Comparator>{}
@@ -327,19 +334,20 @@ class SearchEmailController extends BaseController
} }
void searchMoreEmailsAction() { void searchMoreEmailsAction() {
if (canSearchMore && accountId != null) { if (canSearchMore && session != null && accountId != null) {
final lastEmail = listResultSearch.last; final lastEmail = listResultSearch.last;
_updateSimpleSearchFilter(beforeOption: optionOf(lastEmail.receivedAt)); _updateSimpleSearchFilter(beforeOption: optionOf(lastEmail.receivedAt));
consumeState(_searchMoreEmailInteractor.execute( consumeState(_searchMoreEmailInteractor.execute(
accountId!, session!,
limit: ThreadConstants.defaultLimit, accountId!,
sort: <Comparator>{} limit: ThreadConstants.defaultLimit,
..add(EmailComparator(EmailComparatorProperty.receivedAt) sort: <Comparator>{}
..setIsAscending(false)), ..add(EmailComparator(EmailComparatorProperty.receivedAt)
filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), ..setIsAscending(false)),
properties: ThreadConstants.propertiesDefault, filter: simpleSearchFilter.value.mappingToEmailFilterCondition(),
lastEmailId: lastEmail.id properties: ThreadConstants.propertiesDefault,
lastEmailId: lastEmail.id
)); ));
} }
} }
@@ -3,6 +3,7 @@ import 'dart:async';
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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -15,6 +16,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option
abstract class ThreadDataSource { abstract class ThreadDataSource {
Future<EmailsResponse> getAllEmail( Future<EmailsResponse> getAllEmail(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -25,6 +27,7 @@ abstract class ThreadDataSource {
); );
Future<EmailChangeResponse> getChanges( Future<EmailChangeResponse> getChanges(
Session session,
AccountId accountId, AccountId accountId,
State sinceState, State sinceState,
{ {
@@ -38,10 +41,11 @@ abstract class ThreadDataSource {
Future<void> update({List<Email>? updated, List<Email>? created, List<EmailId>? destroyed}); Future<void> update({List<Email>? updated, List<Email>? created, List<EmailId>? destroyed});
Future<List<EmailId>> emptyTrashFolder( Future<List<EmailId>> emptyTrashFolder(
AccountId accountId, Session session,
MailboxId mailboxId, AccountId accountId,
Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache, MailboxId mailboxId,
Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache,
); );
Future<PresentationEmail> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}); Future<PresentationEmail> getEmailById(Session session, AccountId accountId, EmailId emailId, {Properties? properties});
} }
@@ -3,6 +3,7 @@ import 'dart:async';
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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -25,25 +26,27 @@ class LocalThreadDataSourceImpl extends ThreadDataSource {
@override @override
Future<EmailsResponse> getAllEmail( Future<EmailsResponse> getAllEmail(
AccountId accountId, Session session,
{ AccountId accountId,
UnsignedInt? limit, {
Set<Comparator>? sort, UnsignedInt? limit,
Filter? filter, Set<Comparator>? sort,
Properties? properties Filter? filter,
} Properties? properties
}
) { ) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<EmailChangeResponse> getChanges( Future<EmailChangeResponse> getChanges(
AccountId accountId, Session session,
State sinceState, AccountId accountId,
{ State sinceState,
Properties? propertiesCreated, {
Properties? propertiesUpdated Properties? propertiesCreated,
} Properties? propertiesUpdated
}
) { ) {
throw UnimplementedError(); throw UnimplementedError();
} }
@@ -80,6 +83,7 @@ class LocalThreadDataSourceImpl extends ThreadDataSource {
@override @override
Future<List<EmailId>> emptyTrashFolder( Future<List<EmailId>> emptyTrashFolder(
Session session,
AccountId accountId, AccountId accountId,
MailboxId mailboxId, MailboxId mailboxId,
Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache
@@ -88,7 +92,7 @@ class LocalThreadDataSourceImpl extends ThreadDataSource {
} }
@override @override
Future<PresentationEmail> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}) { Future<PresentationEmail> getEmailById(Session session, AccountId accountId, EmailId emailId, {Properties? properties}) {
throw UnimplementedError(); throw UnimplementedError();
} }
} }
@@ -3,6 +3,7 @@ import 'dart:async';
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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -32,6 +33,7 @@ class ThreadDataSourceImpl extends ThreadDataSource {
@override @override
Future<EmailsResponse> getAllEmail( Future<EmailsResponse> getAllEmail(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -42,6 +44,7 @@ class ThreadDataSourceImpl extends ThreadDataSource {
) { ) {
return Future.sync(() async { return Future.sync(() async {
return await threadAPI.getAllEmail( return await threadAPI.getAllEmail(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -52,15 +55,17 @@ class ThreadDataSourceImpl extends ThreadDataSource {
@override @override
Future<EmailChangeResponse> getChanges( Future<EmailChangeResponse> getChanges(
AccountId accountId, Session session,
State sinceState, AccountId accountId,
{ State sinceState,
Properties? propertiesCreated, {
Properties? propertiesUpdated Properties? propertiesCreated,
} Properties? propertiesUpdated
}
) { ) {
return Future.sync(() async { return Future.sync(() async {
return await threadAPI.getChanges( return await threadAPI.getChanges(
session,
accountId, accountId,
sinceState, sinceState,
propertiesCreated: propertiesCreated, propertiesCreated: propertiesCreated,
@@ -79,20 +84,26 @@ class ThreadDataSourceImpl extends ThreadDataSource {
} }
@override @override
Future<List<EmailId>> emptyTrashFolder(AccountId accountId, MailboxId mailboxId, Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache) { Future<List<EmailId>> emptyTrashFolder(
Session session,
AccountId accountId,
MailboxId mailboxId,
Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache
) {
return Future.sync(() async { return Future.sync(() async {
return await _threadIsolateWorker.emptyTrashFolder( return await _threadIsolateWorker.emptyTrashFolder(
accountId, session,
mailboxId, accountId,
updateDestroyedEmailCache, mailboxId,
updateDestroyedEmailCache,
); );
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override @override
Future<PresentationEmail> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}) { Future<PresentationEmail> getEmailById(Session session, AccountId accountId, EmailId emailId, {Properties? properties}) {
return Future.sync(() async { return Future.sync(() async {
final email = await threadAPI.getEmailById(accountId, emailId, properties: properties); final email = await threadAPI.getEmailById(session, accountId, emailId, properties: properties);
return email.toPresentationEmail(); return email.toPresentationEmail();
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@@ -1,16 +1,19 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.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/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart';
class EmptyTrashFolderArguments with EquatableMixin { class EmptyTrashFolderArguments with EquatableMixin {
final Session session;
final AccountId accountId; final AccountId accountId;
final MailboxId trashMailboxId; final MailboxId trashMailboxId;
final ThreadAPI threadAPI; final ThreadAPI threadAPI;
final EmailAPI emailAPI; final EmailAPI emailAPI;
EmptyTrashFolderArguments( EmptyTrashFolderArguments(
this.session,
this.threadAPI, this.threadAPI,
this.emailAPI, this.emailAPI,
this.accountId, this.accountId,
@@ -18,5 +21,11 @@ class EmptyTrashFolderArguments with EquatableMixin {
); );
@override @override
List<Object?> get props => [accountId, trashMailboxId]; List<Object?> get props => [
session,
accountId,
emailAPI,
threadAPI,
trashMailboxId
];
} }
@@ -2,9 +2,11 @@ import 'dart:async';
import 'package:jmap_dart_client/http/http_client.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/account_id.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/request/reference_path.dart'; import 'package:jmap_dart_client/jmap/core/request/reference_path.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -17,6 +19,7 @@ import 'package:jmap_dart_client/jmap/mail/email/get/get_email_response.dart';
import 'package:jmap_dart_client/jmap/mail/email/query/query_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/query/query_email_method.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:tmail_ui_user/main/error/capability_validator.dart';
class ThreadAPI { class ThreadAPI {
@@ -24,7 +27,25 @@ class ThreadAPI {
ThreadAPI(this.httpClient); ThreadAPI(this.httpClient);
Set<CapabilityIdentifier> _capabilitiesForEmailMethod(Session session, AccountId accountId) {
final getMailboxCreated = GetEmailMethod(accountId);
try {
requireCapability(
session,
accountId,
[CapabilityIdentifier.jmapTeamMailboxes]);
return {
CapabilityIdentifier.jmapCore,
CapabilityIdentifier.jmapMail,
CapabilityIdentifier.jmapTeamMailboxes
};
} catch (_) {
return getMailboxCreated.requiredCapabilities;
}
}
Future<EmailsResponse> getAllEmail( Future<EmailsResponse> getAllEmail(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -58,7 +79,7 @@ class ThreadAPI {
final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod); final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod);
final result = await (jmapRequestBuilder final result = await (jmapRequestBuilder
..usings(getEmailMethod.requiredCapabilities)) ..usings(_capabilitiesForEmailMethod(session, accountId)))
.build() .build()
.execute(); .execute();
@@ -75,6 +96,7 @@ class ThreadAPI {
} }
Future<EmailChangeResponse> getChanges( Future<EmailChangeResponse> getChanges(
Session session,
AccountId accountId, AccountId accountId,
State sinceState, State sinceState,
{ {
@@ -112,7 +134,7 @@ class ThreadAPI {
final getEmailCreatedInvocation = jmapRequestBuilder.invocation(getEmailCreated); final getEmailCreatedInvocation = jmapRequestBuilder.invocation(getEmailCreated);
final result = await (jmapRequestBuilder final result = await (jmapRequestBuilder
..usings(getEmailCreated.requiredCapabilities)) ..usings(_capabilitiesForEmailMethod(session, accountId)))
.build() .build()
.execute(); .execute();
@@ -140,7 +162,7 @@ class ThreadAPI {
updatedProperties: propertiesUpdated); updatedProperties: propertiesUpdated);
} }
Future<Email> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}) async { Future<Email> getEmailById(Session session, AccountId accountId, EmailId emailId, {Properties? properties}) async {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(httpClient, processingInvocation); final jmapRequestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
@@ -154,7 +176,7 @@ class ThreadAPI {
final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod); final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod);
final result = await (jmapRequestBuilder final result = await (jmapRequestBuilder
..usings(getEmailMethod.requiredCapabilities)) ..usings(_capabilitiesForEmailMethod(session, accountId)))
.build() .build()
.execute(); .execute();
@@ -4,6 +4,7 @@ import 'package:core/utils/app_logger.dart';
import 'package:core/utils/build_utils.dart'; import 'package:core/utils/build_utils.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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.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/email_comparator.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart';
@@ -25,15 +26,16 @@ class ThreadIsolateWorker {
ThreadIsolateWorker(this._threadAPI, this._emailAPI, this._isolateExecutor); ThreadIsolateWorker(this._threadAPI, this._emailAPI, this._isolateExecutor);
Future<List<EmailId>> emptyTrashFolder( Future<List<EmailId>> emptyTrashFolder(
Session session,
AccountId accountId, AccountId accountId,
MailboxId mailboxId, MailboxId mailboxId,
Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache, Future<void> Function(List<EmailId>? newDestroyed) updateDestroyedEmailCache,
) async { ) async {
if (BuildUtils.isWeb) { if (BuildUtils.isWeb) {
return _emptyTrashFolderOnWeb(accountId, mailboxId, updateDestroyedEmailCache); return _emptyTrashFolderOnWeb(session, accountId, mailboxId, updateDestroyedEmailCache);
} else { } else {
final result = await _isolateExecutor.execute( final result = await _isolateExecutor.execute(
arg1: EmptyTrashFolderArguments(_threadAPI, _emailAPI, accountId, mailboxId), arg1: EmptyTrashFolderArguments(session, _threadAPI, _emailAPI, accountId, mailboxId),
fun1: _emptyTrashFolderAction, fun1: _emptyTrashFolderAction,
notification: (value) { notification: (value) {
if (value is List<EmailId>) { if (value is List<EmailId>) {
@@ -52,12 +54,14 @@ class ThreadIsolateWorker {
Email? lastEmail; Email? lastEmail;
while (hasEmails) { while (hasEmails) {
final emailsResponse = await args.threadAPI.getAllEmail(args.accountId, final emailsResponse = await args.threadAPI.getAllEmail(
sort: <Comparator>{}..add( args.session,
EmailComparator(EmailComparatorProperty.receivedAt) args.accountId,
..setIsAscending(false)), sort: <Comparator>{}..add(
filter: EmailFilterCondition(inMailbox: args.trashMailboxId, before: lastEmail?.receivedAt), EmailComparator(EmailComparatorProperty.receivedAt)
properties: Properties({EmailProperty.id})); ..setIsAscending(false)),
filter: EmailFilterCondition(inMailbox: args.trashMailboxId, before: lastEmail?.receivedAt),
properties: Properties({EmailProperty.id}));
var newEmailList = emailsResponse.emailList ?? <Email>[]; var newEmailList = emailsResponse.emailList ?? <Email>[];
if (lastEmail != null) { if (lastEmail != null) {
@@ -89,6 +93,7 @@ class ThreadIsolateWorker {
} }
Future<List<EmailId>> _emptyTrashFolderOnWeb( Future<List<EmailId>> _emptyTrashFolderOnWeb(
Session session,
AccountId accountId, AccountId accountId,
MailboxId trashMailboxId, MailboxId trashMailboxId,
Future<void> Function(List<EmailId> newDestroyed) updateDestroyedEmailCache, Future<void> Function(List<EmailId> newDestroyed) updateDestroyedEmailCache,
@@ -99,12 +104,14 @@ class ThreadIsolateWorker {
Email? lastEmail; Email? lastEmail;
while (hasEmails) { while (hasEmails) {
final emailsResponse = await _threadAPI.getAllEmail(accountId, final emailsResponse = await _threadAPI.getAllEmail(
sort: <Comparator>{}..add( session,
EmailComparator(EmailComparatorProperty.receivedAt) accountId,
..setIsAscending(false)), sort: <Comparator>{}..add(
filter: EmailFilterCondition(inMailbox: trashMailboxId, before: lastEmail?.receivedAt), EmailComparator(EmailComparatorProperty.receivedAt)
properties: Properties({EmailProperty.id})); ..setIsAscending(false)),
filter: EmailFilterCondition(inMailbox: trashMailboxId, before: lastEmail?.receivedAt),
properties: Properties({EmailProperty.id}));
var newEmailList = emailsResponse.emailList ?? <Email>[]; var newEmailList = emailsResponse.emailList ?? <Email>[];
if (lastEmail != null) { if (lastEmail != null) {
@@ -4,6 +4,7 @@ import 'package:dartz/dartz.dart' as dartz;
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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -32,6 +33,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
@override @override
Stream<EmailsResponse> getAllEmail( Stream<EmailsResponse> getAllEmail(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -58,6 +60,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
if (!localEmailResponse.hasEmails() if (!localEmailResponse.hasEmails()
|| (localEmailResponse.emailList?.length ?? 0) < ThreadConstants.defaultLimit.value) { || (localEmailResponse.emailList?.length ?? 0) < ThreadConstants.defaultLimit.value) {
networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail( networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -65,6 +68,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
properties: propertiesCreated); properties: propertiesCreated);
if (_isApproveFilterOption(emailFilter?.filterOption, networkEmailResponse.emailList)) { if (_isApproveFilterOption(emailFilter?.filterOption, networkEmailResponse.emailList)) {
_getFirstPage( _getFirstPage(
session,
accountId, accountId,
sort: sort, sort: sort,
mailboxId: emailFilter?.mailboxId, mailboxId: emailFilter?.mailboxId,
@@ -83,6 +87,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
if (localEmailResponse.hasState()) { if (localEmailResponse.hasState()) {
log('ThreadRepositoryImpl::getAllEmail(): filter = ${emailFilter?.mailboxId} local has state: ${localEmailResponse.state}'); log('ThreadRepositoryImpl::getAllEmail(): filter = ${emailFilter?.mailboxId} local has state: ${localEmailResponse.state}');
await _synchronizeCacheWithChanges( await _synchronizeCacheWithChanges(
session,
accountId, accountId,
localEmailResponse.state!, localEmailResponse.state!,
propertiesCreated: propertiesCreated, propertiesCreated: propertiesCreated,
@@ -116,6 +121,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
Future<EmailsResponse> _getFirstPage( Future<EmailsResponse> _getFirstPage(
Session session,
AccountId accountId, AccountId accountId,
{ {
Set<Comparator>? sort, Set<Comparator>? sort,
@@ -125,6 +131,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
) async { ) async {
final networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail( final networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail(
session,
accountId, accountId,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
sort: sort, sort: sort,
@@ -187,17 +194,19 @@ class ThreadRepositoryImpl extends ThreadRepository {
@override @override
Stream<EmailsResponse> refreshChanges( Stream<EmailsResponse> refreshChanges(
AccountId accountId, Session session,
State currentState, AccountId accountId,
{ State currentState,
Set<Comparator>? sort, {
EmailFilter? emailFilter, Set<Comparator>? sort,
Properties? propertiesCreated, EmailFilter? emailFilter,
Properties? propertiesUpdated, Properties? propertiesCreated,
} Properties? propertiesUpdated,
}
) async* { ) async* {
log('ThreadRepositoryImpl::refreshChanges(): $currentState'); log('ThreadRepositoryImpl::refreshChanges(): $currentState');
await _synchronizeCacheWithChanges( await _synchronizeCacheWithChanges(
session,
accountId, accountId,
currentState, currentState,
propertiesCreated: propertiesCreated, propertiesCreated: propertiesCreated,
@@ -214,6 +223,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
if (!newEmailResponse.hasEmails() if (!newEmailResponse.hasEmails()
|| (newEmailResponse.emailList?.length ?? 0) < ThreadConstants.defaultLimit.value) { || (newEmailResponse.emailList?.length ?? 0) < ThreadConstants.defaultLimit.value) {
final networkEmailResponse = await _getFirstPage( final networkEmailResponse = await _getFirstPage(
session,
accountId, accountId,
sort: sort, sort: sort,
filter: emailFilter?.filter, filter: emailFilter?.filter,
@@ -237,14 +247,15 @@ class ThreadRepositoryImpl extends ThreadRepository {
Future<EmailsResponse> _getAllEmailsWithoutLastEmailId(GetEmailRequest emailRequest) async { Future<EmailsResponse> _getAllEmailsWithoutLastEmailId(GetEmailRequest emailRequest) async {
final emailResponse = await mapDataSource[DataSourceType.network]! final emailResponse = await mapDataSource[DataSourceType.network]!
.getAllEmail( .getAllEmail(
emailRequest.accountId, emailRequest.session,
limit: emailRequest.limit, emailRequest.accountId,
sort: emailRequest.sort, limit: emailRequest.limit,
filter: emailRequest.filter, sort: emailRequest.sort,
properties: emailRequest.properties) filter: emailRequest.filter,
properties: emailRequest.properties)
.then((response) { .then((response) {
var listEmails = response.emailList; final listEmails = response.emailList;
return EmailsResponse(emailList: listEmails, state: response.state); return EmailsResponse(emailList: listEmails, state: response.state);
}); });
return emailResponse; return emailResponse;
@@ -252,6 +263,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
@override @override
Future<List<Email>> searchEmails( Future<List<Email>> searchEmails(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -261,6 +273,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
) async { ) async {
final emailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail( final emailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -271,8 +284,9 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
@override @override
Future<List<EmailId>> emptyTrashFolder(AccountId accountId, MailboxId trashMailboxId) async { Future<List<EmailId>> emptyTrashFolder(Session session, AccountId accountId, MailboxId trashMailboxId) async {
return mapDataSource[DataSourceType.network]!.emptyTrashFolder( return mapDataSource[DataSourceType.network]!.emptyTrashFolder(
session,
accountId, accountId,
trashMailboxId, trashMailboxId,
(listEmailIdDeleted) async { (listEmailIdDeleted) async {
@@ -282,6 +296,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
Future<void> _synchronizeCacheWithChanges( Future<void> _synchronizeCacheWithChanges(
Session session,
AccountId accountId, AccountId accountId,
State currentState, State currentState,
{ {
@@ -299,10 +314,11 @@ class ThreadRepositoryImpl extends ThreadRepository {
while(hasMoreChanges && sinceState != null) { while(hasMoreChanges && sinceState != null) {
log('ThreadRepositoryImpl::_synchronizeCacheWithChanges(): sinceState = $sinceState'); log('ThreadRepositoryImpl::_synchronizeCacheWithChanges(): sinceState = $sinceState');
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges( final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(
accountId, session,
sinceState, accountId,
propertiesCreated: propertiesCreated, sinceState,
propertiesUpdated: propertiesUpdated); propertiesCreated: propertiesCreated,
propertiesUpdated: propertiesUpdated);
hasMoreChanges = changesResponse.hasMoreChanges; hasMoreChanges = changesResponse.hasMoreChanges;
sinceState = changesResponse.newStateChanges; sinceState = changesResponse.newStateChanges;
@@ -337,7 +353,12 @@ class ThreadRepositoryImpl extends ThreadRepository {
} }
@override @override
Future<PresentationEmail> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}) { Future<PresentationEmail> getEmailById(
return mapDataSource[DataSourceType.network]!.getEmailById(accountId, emailId, properties: properties); Session session,
AccountId accountId,
EmailId emailId,
{Properties? properties}
) {
return mapDataSource[DataSourceType.network]!.getEmailById(session, accountId, emailId, properties: properties);
} }
} }
@@ -2,12 +2,14 @@ import 'package:equatable/equatable.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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.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/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
class GetEmailRequest with EquatableMixin { class GetEmailRequest with EquatableMixin {
final Session session;
final AccountId accountId; final AccountId accountId;
final UnsignedInt? limit; final UnsignedInt? limit;
final Set<Comparator>? sort; final Set<Comparator>? sort;
@@ -16,15 +18,28 @@ class GetEmailRequest with EquatableMixin {
final Properties? properties; final Properties? properties;
final EmailId? lastEmailId; final EmailId? lastEmailId;
GetEmailRequest(this.accountId, { GetEmailRequest(
this.limit, this.session,
this.sort, this.accountId,
this.filter, {
this.filterOption, this.limit,
this.properties, this.sort,
this.lastEmailId, this.filter,
}); this.filterOption,
this.properties,
this.lastEmailId,
}
);
@override @override
List<Object?> get props => [limit, sort, filter, properties, lastEmailId, filterOption]; List<Object?> get props => [
session,
accountId,
limit,
sort,
filter,
properties,
lastEmailId,
filterOption
];
} }
@@ -3,6 +3,7 @@ import 'dart:async';
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/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -15,6 +16,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dar
abstract class ThreadRepository { abstract class ThreadRepository {
Stream<EmailsResponse> getAllEmail( Stream<EmailsResponse> getAllEmail(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -26,6 +28,7 @@ abstract class ThreadRepository {
); );
Stream<EmailsResponse> refreshChanges( Stream<EmailsResponse> refreshChanges(
Session session,
AccountId accountId, AccountId accountId,
jmap.State currentState, jmap.State currentState,
{ {
@@ -39,6 +42,7 @@ abstract class ThreadRepository {
Stream<EmailsResponse> loadMoreEmails(GetEmailRequest emailRequest); Stream<EmailsResponse> loadMoreEmails(GetEmailRequest emailRequest);
Future<List<Email>> searchEmails( Future<List<Email>> searchEmails(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -49,9 +53,15 @@ abstract class ThreadRepository {
); );
Future<List<EmailId>> emptyTrashFolder( Future<List<EmailId>> emptyTrashFolder(
AccountId accountId, Session session,
MailboxId trashMailboxId, AccountId accountId,
MailboxId trashMailboxId,
); );
Future<PresentationEmail> getEmailById(AccountId accountId, EmailId emailId, {Properties? properties}); Future<PresentationEmail> getEmailById(
Session session,
AccountId accountId,
EmailId emailId,
{Properties? properties}
);
} }
@@ -1,6 +1,7 @@
import 'package:core/core.dart'; import 'package:core/core.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/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.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';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
@@ -18,7 +19,7 @@ class EmptyTrashFolderInteractor {
this._emailRepository this._emailRepository
); );
Stream<Either<Failure, Success>> execute(AccountId accountId, MailboxId trashMailboxId) async* { Stream<Either<Failure, Success>> execute(Session session, AccountId accountId, MailboxId trashMailboxId) async* {
try { try {
yield Right<Failure, Success>(LoadingState()); yield Right<Failure, Success>(LoadingState());
@@ -30,7 +31,7 @@ class EmptyTrashFolderInteractor {
final currentMailboxState = listState.first; final currentMailboxState = listState.first;
final currentEmailState = listState.last; final currentEmailState = listState.last;
final result = await threadRepository.emptyTrashFolder(accountId, trashMailboxId); final result = await threadRepository.emptyTrashFolder(session, accountId, trashMailboxId);
if (result.isNotEmpty) { if (result.isNotEmpty) {
yield Right<Failure, Success>(EmptyTrashFolderSuccess( yield Right<Failure, Success>(EmptyTrashFolderSuccess(
currentMailboxState: currentMailboxState, currentMailboxState: currentMailboxState,
@@ -3,6 +3,7 @@ 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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.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:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart';
import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart';
@@ -13,6 +14,7 @@ class GetEmailByIdInteractor {
GetEmailByIdInteractor(this._threadRepository); GetEmailByIdInteractor(this._threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
EmailId emailId, EmailId emailId,
{ {
@@ -21,7 +23,7 @@ class GetEmailByIdInteractor {
) async* { ) async* {
try { try {
yield Right<Failure, Success>(GetEmailByIdLoading()); yield Right<Failure, Success>(GetEmailByIdLoading());
final email = await _threadRepository.getEmailById(accountId, emailId, properties: properties); final email = await _threadRepository.getEmailById(session, accountId, emailId, properties: properties);
yield Right<Failure, Success>(GetEmailByIdSuccess(email)); yield Right<Failure, Success>(GetEmailByIdSuccess(email));
} catch (e) { } catch (e) {
yield Left<Failure, Success>(GetEmailByIdFailure(e)); yield Left<Failure, Success>(GetEmailByIdFailure(e));
@@ -2,6 +2,7 @@ import 'package:core/core.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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
@@ -16,6 +17,7 @@ class GetEmailsInMailboxInteractor {
GetEmailsInMailboxInteractor(this.threadRepository); GetEmailsInMailboxInteractor(this.threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -30,6 +32,7 @@ class GetEmailsInMailboxInteractor {
yield* threadRepository yield* threadRepository
.getAllEmail( .getAllEmail(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -2,6 +2,7 @@ import 'package:core/core.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/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
@@ -16,6 +17,7 @@ class RefreshChangesEmailsInMailboxInteractor {
RefreshChangesEmailsInMailboxInteractor(this.threadRepository); RefreshChangesEmailsInMailboxInteractor(this.threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
jmap.State currentState, jmap.State currentState,
{ {
@@ -30,6 +32,7 @@ class RefreshChangesEmailsInMailboxInteractor {
try { try {
yield* threadRepository yield* threadRepository
.refreshChanges( .refreshChanges(
session,
accountId, accountId,
currentState, currentState,
sort: sort, sort: sort,
@@ -1,5 +1,6 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/model.dart'; import 'package:model/model.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';
@@ -17,6 +18,7 @@ class SearchEmailInteractor {
SearchEmailInteractor(this.threadRepository); SearchEmailInteractor(this.threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -29,6 +31,7 @@ class SearchEmailInteractor {
yield Right(SearchingState()); yield Right(SearchingState());
final emailList = await threadRepository.searchEmails( final emailList = await threadRepository.searchEmails(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -1,5 +1,6 @@
import 'package:core/core.dart'; import 'package:core/core.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:model/model.dart'; import 'package:model/model.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
@@ -18,6 +19,7 @@ class SearchMoreEmailInteractor {
SearchMoreEmailInteractor(this.threadRepository); SearchMoreEmailInteractor(this.threadRepository);
Stream<Either<Failure, Success>> execute( Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId, AccountId accountId,
{ {
UnsignedInt? limit, UnsignedInt? limit,
@@ -31,6 +33,7 @@ class SearchMoreEmailInteractor {
yield Right(SearchingMoreState()); yield Right(SearchingMoreState());
final emailList = await threadRepository.searchEmails( final emailList = await threadRepository.searchEmails(
session,
accountId, accountId,
limit: limit, limit: limit,
sort: sort, sort: sort,
@@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.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/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
@@ -104,6 +105,8 @@ class ThreadController extends BaseController with EmailActionController {
AccountId? get _accountId => mailboxDashBoardController.accountId.value; AccountId? get _accountId => mailboxDashBoardController.accountId.value;
Session? get _session => mailboxDashBoardController.sessionCurrent;
PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value; PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value;
SearchController get searchController => mailboxDashBoardController.searchController; SearchController get searchController => mailboxDashBoardController.searchController;
@@ -387,8 +390,9 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _getAllEmailAction() { void _getAllEmailAction() {
if (_accountId != null) { if (_session != null &&_accountId != null) {
consumeState(_getEmailsInMailboxInteractor.execute( consumeState(_getEmailsInMailboxInteractor.execute(
_session!,
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
sort: _sortOrder, sort: _sortOrder,
@@ -458,8 +462,9 @@ class ThreadController extends BaseController with EmailActionController {
} else { } else {
final newEmailState = currentEmailState ?? _currentEmailState; final newEmailState = currentEmailState ?? _currentEmailState;
log('ThreadController::_refreshEmailChanges(): newEmailState: $newEmailState'); log('ThreadController::_refreshEmailChanges(): newEmailState: $newEmailState');
if (_accountId != null && newEmailState != null) { if (_session != null && _accountId != null && newEmailState != null) {
consumeState(_refreshChangesEmailsInMailboxInteractor.execute( consumeState(_refreshChangesEmailsInMailboxInteractor.execute(
_session!,
_accountId!, _accountId!,
newEmailState, newEmailState,
sort: _sortOrder, sort: _sortOrder,
@@ -477,12 +482,13 @@ class ThreadController extends BaseController with EmailActionController {
void loadMoreEmails() { void loadMoreEmails() {
log('ThreadController::loadMoreEmails()'); log('ThreadController::loadMoreEmails()');
if (canLoadMore && _accountId != null) { if (canLoadMore && _session != null && _accountId != null) {
final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
? mailboxDashBoardController.emailsInCurrentMailbox.last ? mailboxDashBoardController.emailsInCurrentMailbox.last
: null; : null;
consumeState(_loadMoreEmailsInMailboxInteractor.execute( consumeState(_loadMoreEmailsInMailboxInteractor.execute(
GetEmailRequest( GetEmailRequest(
_session!,
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
sort: _sortOrder, sort: _sortOrder,
@@ -665,7 +671,7 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _searchEmail({UnsignedInt? limit}) { void _searchEmail({UnsignedInt? limit}) {
if (_accountId != null) { if (_session != null && _accountId != null) {
if (listEmailController.hasClients) { if (listEmailController.hasClients) {
listEmailController.jumpTo(0); listEmailController.jumpTo(0);
} }
@@ -676,6 +682,7 @@ class ThreadController extends BaseController with EmailActionController {
searchController.activateSimpleSearch(); searchController.activateSimpleSearch();
consumeState(_searchEmailInteractor.execute( consumeState(_searchEmailInteractor.execute(
_session!,
_accountId!, _accountId!,
limit: limit ?? ThreadConstants.defaultLimit, limit: limit ?? ThreadConstants.defaultLimit,
sort: _sortOrder, sort: _sortOrder,
@@ -716,12 +723,13 @@ class ThreadController extends BaseController with EmailActionController {
} }
void searchMoreEmails() { void searchMoreEmails() {
if (canSearchMore && _accountId != null) { if (canSearchMore && _session != null && _accountId != null) {
final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
? mailboxDashBoardController.emailsInCurrentMailbox.last ? mailboxDashBoardController.emailsInCurrentMailbox.last
: null; : null;
searchController.updateFilterEmail(beforeOption: optionOf(oldestEmail?.receivedAt)); searchController.updateFilterEmail(beforeOption: optionOf(oldestEmail?.receivedAt));
consumeState(_searchMoreEmailInteractor.execute( consumeState(_searchMoreEmailInteractor.execute(
_session!,
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: ThreadConstants.defaultLimit,
sort: _sortOrder, sort: _sortOrder,
@@ -935,8 +943,9 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _getEmailByIdAction(EmailId emailId) { void _getEmailByIdAction(EmailId emailId) {
if (_accountId != null) { if (_session != null && _accountId != null) {
consumeState(_getEmailByIdInteractor.execute( consumeState(_getEmailByIdInteractor.execute(
_session!,
_accountId!, _accountId!,
emailId, emailId,
properties: ThreadConstants.propertiesDefault)); properties: ThreadConstants.propertiesDefault));
@@ -21,6 +21,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/get_emails_in_mail
import '../../../../fixtures/account_fixtures.dart'; import '../../../../fixtures/account_fixtures.dart';
import '../../../../fixtures/email_fixtures.dart'; import '../../../../fixtures/email_fixtures.dart';
import '../../../../fixtures/mailbox_fixtures.dart'; import '../../../../fixtures/mailbox_fixtures.dart';
import '../../../../fixtures/session_fixtures.dart';
import 'get_emails_in_mailbox_interactor_test.mocks.dart'; import 'get_emails_in_mailbox_interactor_test.mocks.dart';
@GenerateMocks([ThreadRepository]) @GenerateMocks([ThreadRepository])
@@ -37,6 +38,7 @@ void main() {
test('getEmailsInMailboxInteractor should execute to get all email from cache and network', () async { test('getEmailsInMailboxInteractor should execute to get all email from cache and network', () async {
when(threadRepository.getAllEmail( when(threadRepository.getAllEmail(
SessionFixtures.aliceSession,
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
limit: UnsignedInt(20), limit: UnsignedInt(20),
sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
@@ -65,6 +67,7 @@ void main() {
})); }));
final streamStates = getEmailsInMailboxInteractor.execute( final streamStates = getEmailsInMailboxInteractor.execute(
SessionFixtures.aliceSession,
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
limit: UnsignedInt(20), limit: UnsignedInt(20),
sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: {}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
@@ -19,6 +19,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_em
import '../../../../fixtures/account_fixtures.dart'; import '../../../../fixtures/account_fixtures.dart';
import '../../../../fixtures/email_fixtures.dart'; import '../../../../fixtures/email_fixtures.dart';
import '../../../../fixtures/mailbox_fixtures.dart'; import '../../../../fixtures/mailbox_fixtures.dart';
import '../../../../fixtures/session_fixtures.dart';
import '../../../../fixtures/state_fixtures.dart'; import '../../../../fixtures/state_fixtures.dart';
import 'refresh_changes_emails_in_mailbox_interactor_test.mocks.dart'; import 'refresh_changes_emails_in_mailbox_interactor_test.mocks.dart';
@@ -36,6 +37,7 @@ void main() {
test('refreshChangesEmailsInMailboxInteractor should execute to get changes email from cache and network', () async { test('refreshChangesEmailsInMailboxInteractor should execute to get changes email from cache and network', () async {
when(threadRepository.refreshChanges( when(threadRepository.refreshChanges(
SessionFixtures.aliceSession,
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
StateFixtures.currentEmailState, StateFixtures.currentEmailState,
sort: <EmailComparator>{}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: <EmailComparator>{}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
@@ -56,6 +58,7 @@ void main() {
})); }));
final streamStates = refreshChangesEmailsInMailboxInteractor.execute( final streamStates = refreshChangesEmailsInMailboxInteractor.execute(
SessionFixtures.aliceSession,
AccountFixtures.aliceAccountId, AccountFixtures.aliceAccountId,
StateFixtures.currentEmailState, StateFixtures.currentEmailState,
sort: <EmailComparator>{}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)), sort: <EmailComparator>{}..add(EmailComparator(EmailComparatorProperty.sentAt)..setIsAscending(false)),
+102
View File
@@ -0,0 +1,102 @@
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/account/account.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
import 'package:jmap_dart_client/jmap/core/capability/core_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/default_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/mail_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/mdn_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/submission_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/vacation_capability.dart';
import 'package:jmap_dart_client/jmap/core/capability/websocket_capability.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/sort/collation_identifier.dart';
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
class SessionFixtures {
static final aliceSession = Session(
{
CapabilityIdentifier.jmapSubmission: SubmissionCapability(UnsignedInt(0), {}),
CapabilityIdentifier.jmapCore: CoreCapability(
UnsignedInt(20971520),
UnsignedInt(4),
UnsignedInt(10000000),
UnsignedInt(4),
UnsignedInt(16),
UnsignedInt(500),
UnsignedInt(500),
{CollationIdentifier("i;unicode-casemap")}
),
CapabilityIdentifier.jmapMail: MailCapability(
UnsignedInt(10000000),
null,
UnsignedInt(200),
UnsignedInt(20000000),
{"receivedAt", "sentAt", "size", "from", "to", "subject"},
true
),
CapabilityIdentifier.jmapWebSocket: WebSocketCapability(
true,
Uri.parse('ws://domain.com/jmap/ws')
),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:quota')): DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:shares')): DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier.jmapVacationResponse: VacationCapability(),
CapabilityIdentifier.jmapMdn: MdnCapability(),
},
{
AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')): Account(
AccountName('bob@domain.tld'),
true,
false,
{
CapabilityIdentifier.jmapSubmission: SubmissionCapability(UnsignedInt(0), {}),
CapabilityIdentifier.jmapWebSocket: WebSocketCapability(
true,
Uri.parse('ws://domain.com/jmap/ws')
),
CapabilityIdentifier.jmapCore: CoreCapability(
UnsignedInt(20971520),
UnsignedInt(4),
UnsignedInt(10000000),
UnsignedInt(4),
UnsignedInt(16),
UnsignedInt(500),
UnsignedInt(500),
{CollationIdentifier("i;unicode-casemap")}
),
CapabilityIdentifier.jmapMail: MailCapability(
UnsignedInt(10000000),
null,
UnsignedInt(200),
UnsignedInt(20000000),
{"receivedAt", "sentAt", "size", "from", "to", "subject"},
true
),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:quota')): DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:shares')): DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier.jmapVacationResponse: VacationCapability(),
CapabilityIdentifier.jmapMdn: MdnCapability()
}
)
},
{
CapabilityIdentifier.jmapSubmission: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier.jmapWebSocket: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier.jmapCore: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier.jmapMail: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:quota')): AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier(Uri.parse('urn:apache:james:params:jmap:mail:shares')): AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier.jmapVacationResponse: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
CapabilityIdentifier.jmapMdn: AccountId(Id('29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6')),
},
UserName('bob@domain.tld'),
Uri.parse('http://domain.com/jmap'),
Uri.parse('http://domain.com/download/{accountId}/{blobId}/?type={type}&name={name}'),
Uri.parse('http://domain.com/upload/{accountId}'),
Uri.parse('http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'),
State('2c9f1b12-b35a-43e6-9af2-0106fb53a943')
);
}