TF-3941 Thread Detail Thread level mark read/star, archive and spam

This commit is contained in:
DatDang
2025-08-05 14:15:03 +07:00
committed by Dat H. Pham
parent f44118af48
commit b7cd3f7179
35 changed files with 902 additions and 552 deletions
@@ -0,0 +1,9 @@
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
extension ListEmailInThreadDetailInfoExtension on List<EmailInThreadDetailInfo> {
List<EmailId> get emailIdsToDisplay =>
where((email) => email.isValidToDisplay)
.map((email) => email.emailId)
.toList();
}
@@ -0,0 +1,42 @@
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
class EmailInThreadDetailInfo with EquatableMixin {
const EmailInThreadDetailInfo({
required this.emailId,
required this.keywords,
required this.mailboxIds,
required this.isValidToDisplay,
});
final EmailId emailId;
final Map<KeyWordIdentifier, bool>? keywords;
final Map<MailboxId, bool>? mailboxIds;
final bool isValidToDisplay;
@override
List<Object?> get props => [emailId, keywords, mailboxIds, isValidToDisplay];
EmailInThreadDetailInfo copyWith({
EmailId? emailId,
Map<KeyWordIdentifier, bool>? keywords,
Map<MailboxId, bool>? mailboxIds,
bool? isValidToDisplay,
}) {
return EmailInThreadDetailInfo(
emailId: emailId ?? this.emailId,
keywords: keywords ?? this.keywords,
mailboxIds: mailboxIds ?? this.mailboxIds,
isValidToDisplay: isValidToDisplay ?? this.isValidToDisplay,
);
}
MailboxId? get mailboxIdContain {
return mailboxIds?.entries
.firstWhereOrNull((entry) => entry.value)
?.key;
}
}
@@ -3,16 +3,16 @@ 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/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
abstract class ThreadDetailRepository {
Future<List<EmailId>> getThreadById(
Future<List<EmailInThreadDetailInfo>> getThreadById(
ThreadId threadId,
Session session,
AccountId accountId,
MailboxId sentMailboxId,
String ownEmailAddress, {
required EmailId? selectedEmailId,
});
String ownEmailAddress,
);
Future<List<Email>> getEmailsByIds(
Session session,
@@ -1,6 +1,7 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
class GettingThreadById extends LoadingState {
final bool updateCurrentThreadDetail;
@@ -16,25 +17,32 @@ class GetThreadByIdSuccess extends UIState {
final ThreadId? threadId;
final bool updateCurrentThreadDetail;
final bool skipLoadingMetadata;
final List<EmailInThreadDetailInfo> emailsInThreadDetailInfo;
GetThreadByIdSuccess(
this.emailIds, {
required this.threadId,
this.updateCurrentThreadDetail = false,
this.skipLoadingMetadata = false,
this.emailsInThreadDetailInfo = const [],
});
@override
List<Object?> get props => [
emailIds,
threadId,
emailsInThreadDetailInfo,
updateCurrentThreadDetail,
skipLoadingMetadata,
];
}
class PreloadEmailIdsInThreadSuccess extends GetThreadByIdSuccess {
PreloadEmailIdsInThreadSuccess(super.emailIds, {required super.threadId});
PreloadEmailIdsInThreadSuccess(
super.emailIds, {
required super.threadId,
super.emailsInThreadDetailInfo,
});
}
class GetThreadByIdFailure extends FeatureFailure {
@@ -6,6 +6,7 @@ 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/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/extensions/list_email_in_thread_detail_info_extension.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/repository/thread_detail_repository.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
@@ -20,7 +21,6 @@ class GetThreadByIdInteractor {
AccountId accountId,
MailboxId sentMailboxId,
String ownEmailAddress, {
required EmailId? selectedEmailId,
bool updateCurrentThreadDetail = false,
}) async* {
try {
@@ -33,13 +33,13 @@ class GetThreadByIdInteractor {
accountId,
sentMailboxId,
ownEmailAddress,
selectedEmailId: selectedEmailId,
);
yield Right(GetThreadByIdSuccess(
result,
result.emailIdsToDisplay,
threadId: threadId,
updateCurrentThreadDetail: updateCurrentThreadDetail,
emailsInThreadDetailInfo: result,
));
} catch (e) {
logError('GetEmailIdsByThreadIdInteractor::execute(): Exception: $e');
@@ -51,7 +51,6 @@ class GetThreadByIdInteractor {
accountId,
sentMailboxId,
ownEmailAddress,
selectedEmailId: selectedEmailId,
),
updateCurrentThreadDetail: updateCurrentThreadDetail,
));