Skip to content

Commit 23d550e

Browse files
committed
TF-4400 Enable collapse threads on Force Query path
Signed-off-by: dab246 <tdvu@linagora.com>
1 parent 746ebe8 commit 23d550e

15 files changed

Lines changed: 89 additions & 17 deletions

lib/features/base/mixin/mail_api_mixin.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/exceptions/mailbox_excepti
3838
import 'package:tmail_ui_user/features/mailbox/domain/state/move_folder_content_state.dart';
3939
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_extension.dart';
4040
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_id_extension.dart';
41+
import 'package:tmail_ui_user/features/thread/data/extensions/query_email_method_extension.dart';
4142
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
4243
import 'package:tmail_ui_user/main/error/capability_validator.dart';
4344

@@ -109,6 +110,7 @@ mixin MailAPIMixin on HandleSetErrorMixin, SessionMixin {
109110
int? position,
110111
Set<Comparator>? sort,
111112
Filter? filter,
113+
bool? collapseThreads,
112114
Properties? properties,
113115
}) async {
114116
final processingInvocation = ProcessingInvocation();
@@ -118,15 +120,12 @@ mixin MailAPIMixin on HandleSetErrorMixin, SessionMixin {
118120
processingInvocation,
119121
);
120122

121-
final queryEmailMethod = QueryEmailMethod(accountId);
122-
123-
if (limit != null) queryEmailMethod.addLimit(limit);
124-
125-
if (position != null && position > 0) queryEmailMethod.addPosition(position);
126-
127-
if (sort != null) queryEmailMethod.addSorts(sort);
128-
129-
if (filter != null) queryEmailMethod.addFilters(filter);
123+
final queryEmailMethod = QueryEmailMethod(accountId)
124+
..addLimitIfNotNull(limit)
125+
..addPositionIfAvailable(position)
126+
..addSortsIfNotNull(sort)
127+
..addFiltersIfNotNull(filter)
128+
..addCollapseThreadsIfAvailable(collapseThreads);
130129

131130
final queryEmailInvocation =
132131
jmapRequestBuilder.invocation(queryEmailMethod);

lib/features/thread/data/datasource/thread_datasource.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ abstract class ThreadDataSource {
2828
int? position,
2929
Set<Comparator>? sort,
3030
Filter? filter,
31+
bool? collapseThreads,
3132
Properties? properties
3233
}
3334
);

lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class LocalThreadDataSourceImpl extends ThreadDataSource {
4444
int? position,
4545
Set<Comparator>? sort,
4646
Filter? filter,
47+
bool? collapseThreads,
4748
Properties? properties
4849
}
4950
) {

lib/features/thread/data/datasource_impl/thread_datasource_impl.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ThreadDataSourceImpl extends ThreadDataSource {
4545
int? position,
4646
Set<Comparator>? sort,
4747
Filter? filter,
48+
bool? collapseThreads,
4849
Properties? properties,
4950
}
5051
) {
@@ -56,6 +57,7 @@ class ThreadDataSourceImpl extends ThreadDataSource {
5657
position: position,
5758
sort: sort,
5859
filter: filter,
60+
collapseThreads: collapseThreads,
5961
properties: properties);
6062
}).catchError(_exceptionThrower.throwException);
6163
}

lib/features/thread/data/extensions/query_email_method_extension.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
33
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
44
import 'package:jmap_dart_client/jmap/mail/email/query/query_email_method.dart';
55

6+
/// Naming convention:
7+
/// - `IfNotNull` — applies the method only when the value is non-null.
8+
/// - `IfAvailable` — applies the method when the value meets an additional
9+
/// semantic condition beyond null (e.g. position > 0, collapseThreads == true).
610
extension QueryEmailMethodExtension on QueryEmailMethod {
711
void addLimitIfNotNull(UnsignedInt? limit) {
812
if (limit != null) addLimit(limit);
913
}
1014

15+
/// Only sets position when it is positive; position 0 is the default start
16+
/// and does not need to be sent explicitly.
1117
void addPositionIfAvailable(int? position) {
1218
if (position != null && position > 0) addPosition(position);
1319
}
@@ -20,6 +26,8 @@ extension QueryEmailMethodExtension on QueryEmailMethod {
2026
if (filter != null) addFilters(filter);
2127
}
2228

29+
/// Only enables collapse-threads when the flag is explicitly `true`;
30+
/// null or false means the feature is not requested.
2331
void addCollapseThreadsIfAvailable(bool? collapseThreads) {
2432
if (collapseThreads == true) {
2533
addCollapseThreads(true);

lib/features/thread/data/network/thread_api.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class ThreadAPI with HandleSetErrorMixin, SessionMixin, MailAPIMixin {
4848
int? position,
4949
Set<Comparator>? sort,
5050
Filter? filter,
51+
bool? collapseThreads,
5152
Properties? properties
5253
}
5354
) async {
@@ -59,6 +60,7 @@ class ThreadAPI with HandleSetErrorMixin, SessionMixin, MailAPIMixin {
5960
position: position,
6061
sort: sort,
6162
filter: filter,
63+
collapseThreads: collapseThreads,
6264
properties: properties,
6365
);
6466
}

lib/features/thread/data/repository/thread_repository_impl.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
165165
int? position,
166166
Set<Comparator>? sort,
167167
EmailFilter? emailFilter,
168+
bool? collapseThreads,
168169
Properties? propertiesCreated,
169170
}) async* {
170171
jmap.State? cachedState;
@@ -196,6 +197,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
196197
position: position,
197198
sort: sort,
198199
filter: emailFilter?.filter,
200+
collapseThreads: collapseThreads,
199201
properties: propertiesCreated,
200202
);
201203

@@ -205,6 +207,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
205207

206208
logTrace(
207209
'ThreadRepositoryImpl::forceQueryAllEmailsForWeb(): '
210+
'collapseThreads = $collapseThreads, '
208211
'ServerEmailCount = $serverCount, '
209212
'ServerNotFoundEmailIds = ${notFoundEmailIds.length}, '
210213
'StateResponse = ${stateResponse?.value}',
@@ -240,6 +243,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
240243
MailboxId? mailboxId,
241244
Properties? propertiesCreated,
242245
Filter? filter,
246+
bool? collapseThreads,
243247
}
244248
) async {
245249
final networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail(
@@ -250,6 +254,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
250254
sort: sort,
251255
filter: filter ?? EmailFilterCondition(inMailbox: mailboxId),
252256
properties: propertiesCreated,
257+
collapseThreads: collapseThreads,
253258
);
254259
await _updateEmailCache(
255260
accountId,
@@ -360,6 +365,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
360365
EmailFilter? emailFilter,
361366
Properties? propertiesCreated,
362367
Properties? propertiesUpdated,
368+
bool? collapseThreads,
363369
}
364370
) async* {
365371
log('ThreadRepositoryImpl::refreshChanges(): $currentState');
@@ -395,9 +401,11 @@ class ThreadRepositoryImpl extends ThreadRepository {
395401
filter: emailFilter?.filter,
396402
mailboxId: emailFilter?.mailboxId,
397403
propertiesCreated: propertiesCreated,
404+
collapseThreads: collapseThreads,
398405
);
399406
logTrace(
400407
'ThreadRepositoryImpl::refreshChanges():'
408+
'collapseThreads = $collapseThreads, '
401409
'CountEmailCached = ${newEmailResponse.emailList?.length}, '
402410
'EmailStateCache = ${newEmailResponse.state?.value}, '
403411
'InMailboxId = ${emailFilter?.mailboxId?.asString}, '
@@ -410,6 +418,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
410418
} else {
411419
logTrace(
412420
'ThreadRepositoryImpl::refreshChanges():'
421+
'collapseThreads = $collapseThreads, '
413422
'CountEmailCached = ${newEmailResponse.emailList?.length}, '
414423
'EmailStateCache = ${newEmailResponse.state?.value}, '
415424
'InMailboxId = ${emailFilter?.mailboxId?.asString}, '
@@ -432,7 +441,9 @@ class ThreadRepositoryImpl extends ThreadRepository {
432441
);
433442
}
434443
logTrace(
435-
'ThreadRepositoryImpl::loadMoreEmails(): emailList = ${response.emailList?.length},'
444+
'ThreadRepositoryImpl::loadMoreEmails(): '
445+
'collapseThreads = ${emailRequest.collapseThreads},'
446+
'emailList = ${response.emailList?.length},'
436447
'notFoundEmailIds = ${response.notFoundEmailIds?.length}, '
437448
'existNotFoundEmails = ${response.existNotFoundEmails}, '
438449
'state = ${response.state?.value}',
@@ -449,6 +460,7 @@ class ThreadRepositoryImpl extends ThreadRepository {
449460
position: emailRequest.position,
450461
sort: emailRequest.sort,
451462
filter: emailRequest.filter,
463+
collapseThreads: emailRequest.collapseThreads,
452464
properties: emailRequest.properties)
453465
.then((response) {
454466
final listEmails = response.emailList;

lib/features/thread/domain/model/get_email_request.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class GetEmailRequest with EquatableMixin {
1919
final Properties? properties;
2020
final EmailId? lastEmailId;
2121
final bool useCache;
22+
final bool? collapseThreads;
2223

2324
GetEmailRequest(
2425
this.session,
@@ -32,6 +33,7 @@ class GetEmailRequest with EquatableMixin {
3233
this.properties,
3334
this.lastEmailId,
3435
this.useCache = true,
36+
this.collapseThreads,
3537
}
3638
);
3739

@@ -47,5 +49,6 @@ class GetEmailRequest with EquatableMixin {
4749
lastEmailId,
4850
filterOption,
4951
useCache,
52+
collapseThreads,
5053
];
5154
}

lib/features/thread/domain/repository/thread_repository.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ abstract class ThreadRepository {
5050
int? position,
5151
Set<Comparator>? sort,
5252
EmailFilter? emailFilter,
53+
bool? collapseThreads,
5354
Properties? propertiesCreated,
5455
});
5556

@@ -63,6 +64,7 @@ abstract class ThreadRepository {
6364
EmailFilter? emailFilter,
6465
Properties? propertiesCreated,
6566
Properties? propertiesUpdated,
67+
bool? collapseThreads,
6668
}
6769
);
6870

lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class GetEmailsInMailboxInteractor {
2727
EmailFilter? emailFilter,
2828
Properties? propertiesCreated,
2929
Properties? propertiesUpdated,
30+
bool? collapseThreads,
3031
bool getLatestChanges = true,
3132
bool useCache = true,
3233
bool forceEmailQuery = false,
@@ -44,6 +45,7 @@ class GetEmailsInMailboxInteractor {
4445
limit: limit,
4546
sort: sort,
4647
emailFilter: emailFilter,
48+
collapseThreads: collapseThreads,
4749
propertiesCreated: propertiesCreated,
4850
);
4951
} else if (useCache) {

0 commit comments

Comments
 (0)