Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TF-3298 Fix blink when refresh email list #3299

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions lib/features/thread/data/extensions/list_email_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,24 @@ extension ListEmailExtension on List<Email> {
};
}

List<Email> sortingByOrderOfIdList(List<Id> ids) {
if (ids.length != length) {
return this;
}
List<Email> sortEmailsById(List<Id> referenceIds) {
final indexMap = {
for (var i = 0; i < referenceIds.length; i++)
referenceIds[i]: i
};

sort((email1, email2) {
final id1 = email1.id?.id;
final id2 = email2.id?.id;
final emailId1 = email1.id?.id;
final emailId2 = email2.id?.id;

if (id1 == null || id2 == null) {
return 0;
if (emailId1 == null || emailId2 == null) {
return emailId1 == null ? 1 : -1;
}

final index1 = ids.indexWhere((id) => id == id1);
final index2 = ids.indexWhere((id) => id == id2);
final indexEmail1 = indexMap[emailId1] ?? double.maxFinite;
final indexEmail2 = indexMap[emailId2] ?? double.maxFinite;

return index1.compareTo(index2);
return indexEmail1.compareTo(indexEmail2);
});

return this;
Expand Down
49 changes: 26 additions & 23 deletions lib/features/thread/data/network/thread_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import 'package:jmap_dart_client/jmap/mail/email/get/get_email_method.dart';
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_response.dart';
import 'package:model/extensions/list_email_extension.dart';
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_extension.dart';
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet.dart';
import 'package:jmap_dart_client/jmap/mail/email/search_snippet/search_snippet_get_method.dart';
Expand Down Expand Up @@ -91,24 +90,33 @@ class ThreadAPI {
QueryEmailResponse.deserialize,
);

List<Email>? emailList;
final emailList = sortEmails(
getEmailResponse: responseOfGetEmailMethod,
queryEmailResponse: responseOfQueryEmailMethod,
);

if (responseOfGetEmailMethod?.list.isNotEmpty == true &&
responseOfQueryEmailMethod?.ids.isNotEmpty == true) {
log('ThreadAPI::getAllEmail: QUERY_EMAIL_IDS = ${responseOfQueryEmailMethod?.ids}');
final listSortedEmail = responseOfGetEmailMethod!.list
.sortingByOrderOfIdList(responseOfQueryEmailMethod!.ids.toList());
emailList = listSortedEmail;
} else {
emailList = responseOfGetEmailMethod?.list;
}
log('ThreadAPI::getAllEmail: EMAIL_DISPLAYED_IDS = ${emailList?.listEmailIds}');
return EmailsResponse(
emailList: emailList,
state: responseOfGetEmailMethod?.state,
);
}

List<Email>? sortEmails({
GetEmailResponse? getEmailResponse,
QueryEmailResponse? queryEmailResponse,
}) {
final listEmails = getEmailResponse?.list;
final listIds = queryEmailResponse?.ids.toList();

if (listEmails?.isNotEmpty != true || listIds?.isNotEmpty != true) {
return listEmails;
}

final listSortedEmails = listEmails!.sortEmailsById(listIds!);

return listSortedEmails;
}

Future<SearchEmailsResponse> searchEmails(
Session session,
AccountId accountId,
Expand Down Expand Up @@ -166,29 +174,24 @@ class ThreadAPI {
.build()
.execute();

final emailResultList = result.parse<GetEmailResponse>(
final responseOfGetEmailMethod = result.parse<GetEmailResponse>(
getEmailInvocation.methodCallId, GetEmailResponse.deserialize);
final responseOfQueryEmailMethod = result.parse<QueryEmailResponse>(
queryEmailInvocation.methodCallId,
QueryEmailResponse.deserialize);

List<Email>? sortedEmailList;

if (emailResultList?.list.isNotEmpty == true &&
responseOfQueryEmailMethod?.ids.isNotEmpty == true) {
sortedEmailList = emailResultList!.list
.sortingByOrderOfIdList(responseOfQueryEmailMethod!.ids.toList());
} else {
sortedEmailList = emailResultList?.list;
}
final sortedEmailList = sortEmails(
getEmailResponse: responseOfGetEmailMethod,
queryEmailResponse: responseOfQueryEmailMethod,
);

final searchSnippets = _getSearchSnippetsFromResponse(
result,
getSearchSnippetMethodCallId: getSearchSnippetInvocation.methodCallId,
);
return SearchEmailsResponse(
emailList: sortedEmailList,
state: emailResultList?.state,
state: responseOfGetEmailMethod?.state,
searchSnippets: searchSnippets);
}

Expand Down
54 changes: 0 additions & 54 deletions test/features/email/sorting_list_email_by_order_id_list_test.dart

This file was deleted.

166 changes: 166 additions & 0 deletions test/features/thread/data/extensions/list_email_extension_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/extensions/email_id_extensions.dart';
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_extension.dart';

void main() {
group('ListEmailExtension::sortEmailsById::test', () {
test('Sort the full list', () {
final referenceIds = <Id>[
Id('id1'),
Id('id2'),
Id('id3'),
Id('id4'),
];

final emails = <Email>[
Email(id: EmailId(Id('id3'))),
Email(id: EmailId(Id('id1'))),
Email(id: EmailId(Id('id4'))),
Email(id: EmailId(Id('id2'))),
];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
['id1', 'id2', 'id3', 'id4'],
);
});

test('Emails list has more elements than referenceIds', () {
final referenceIds = <Id>[
Id('id1'),
Id('id2'),
Id('id3'),
];

final emails = <Email>[
Email(id: EmailId(Id('id3'))),
Email(id: EmailId(Id('id4'))),
Email(id: EmailId(Id('id1'))),
Email(id: EmailId(Id('id5'))),
Email(id: EmailId(Id('id2'))),
];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
['id1', 'id2', 'id3', 'id4', 'id5'],
);
});

test('Emails list has fewer elements than referenceIds', () {
final referenceIds = <Id>[
Id('id1'),
Id('id2'),
Id('id3'),
Id('id4'),
];

final emails = <Email>[
Email(id: EmailId(Id('id3'))),
Email(id: EmailId(Id('id1'))),
];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
['id1', 'id3'],
);
});

test('Emails list is empty', () {
final referenceIds = <Id>[
Id('id1'),
Id('id2'),
Id('id3'),
];

final emails = <Email>[];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
[],
);
});

test('ReferenceIds list is empty', () {
final referenceIds = <Id>[];

final emails = <Email>[
Email(id: EmailId(Id('id3'))),
Email(id: EmailId(Id('id4'))),
Email(id: EmailId(Id('id1'))),
Email(id: EmailId(Id('id5'))),
];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
['id3', 'id4', 'id1', 'id5'],
);
});

test('Both lists are empty', () {
final referenceIds = <Id>[];
final emails = <Email>[];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
[],
);
});

test('Emails have ids that do not match referenceIds', () {
final referenceIds = <Id>[
Id('id1'),
Id('id2'),
];

final emails = <Email>[
Email(id: EmailId(Id('id3'))),
Email(id: EmailId(Id('id4'))),
Email(id: EmailId(Id('id5'))),
];

final result = emails.sortEmailsById(referenceIds);

expect(
result.map((e) => e.id!.asString).toList(),
['id3', 'id4', 'id5'],
);
});

test('should keep emails with null IDs in their original order at the end', () {
// Arrange
final referenceIds = [
Id('id2'),
Id('id1'),
];

final emails = [
Email(id: EmailId(Id('id1'))),
Email(id: null),
Email(id: EmailId(Id('id2'))),
];

// Act
final sortedEmails = emails.sortEmailsById(referenceIds);

// Assert
expect(
sortedEmails.map((e) => e.id?.asString).toList(),
['id2', 'id1', null],
);
});
});
}
Loading
Loading