TF-145 Add data layer for getAllEmail in Caching

This commit is contained in:
dab246
2021-10-07 15:02:07 +07:00
committed by Dat H. Pham
parent 3cac5e4e83
commit bfd5901bf4
16 changed files with 524 additions and 22 deletions
@@ -1,37 +1,163 @@
import 'package:core/core.dart';
import 'package:model/model.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/properties/properties.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/unsigned_int.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/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.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/repository/thread_repository.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/state_extension.dart';
class ThreadRepositoryImpl extends ThreadRepository {
final ThreadDataSource threadDataSource;
final Map<DataSourceType, ThreadDataSource> mapDataSource;
final StateDataSource stateDataSource;
ThreadRepositoryImpl(this.threadDataSource);
ThreadRepositoryImpl(this.mapDataSource, this.stateDataSource);
@override
Future<List<Email>> getAllEmail(
Stream<EmailResponse> getAllEmail(
AccountId accountId,
{
int? position,
UnsignedInt? limit,
Set<Comparator>? sort,
Filter? filter,
Properties? properties
Properties? propertiesCreated,
Properties? propertiesUpdated,
MailboxId? inMailboxId
}
) {
return threadDataSource.getAllEmail(
accountId,
position: position,
limit: limit,
sort: sort,
filter: filter,
properties: properties
);
) async* {
final localEmailResponse = await Future.wait([
mapDataSource[DataSourceType.local]!.getAllEmailCache(inMailboxId: inMailboxId, sort: sort),
stateDataSource.getState(StateType.email)
]).then((List response) {
return EmailResponse(emailList: response.first, state: response.last);
});
EmailResponse? networkEmailResponse;
if (!localEmailResponse.hasEmails()) {
networkEmailResponse = await mapDataSource[DataSourceType.network]!.getAllEmail(
accountId,
position: position,
limit: limit,
sort: sort,
filter: filter,
properties: propertiesCreated);
yield networkEmailResponse;
} else {
yield localEmailResponse;
}
if (localEmailResponse.hasState()) {
EmailChangeResponse? emailChangeResponse;
bool hasMoreChanges = true;
State? sinceState = localEmailResponse.state!;
while(hasMoreChanges && sinceState != null) {
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(
accountId,
sinceState,
propertiesCreated: propertiesCreated,
propertiesUpdated: propertiesUpdated);
hasMoreChanges = changesResponse.hasMoreChanges;
sinceState = changesResponse.newStateChanges;
if (emailChangeResponse != null) {
emailChangeResponse.union(changesResponse);
} else {
emailChangeResponse = changesResponse;
}
}
final totalEmails = networkEmailResponse != null
? networkEmailResponse.emailList
: localEmailResponse.emailList;
final newEmailUpdated = await _combineEmailCache(
emailUpdated: emailChangeResponse?.updated,
updatedProperties: emailChangeResponse?.updatedProperties,
emailCacheList: totalEmails);
final newEmailCreated = networkEmailResponse != null
? networkEmailResponse.emailList
: emailChangeResponse?.created;
await _updateEmailCache(
newCreated: newEmailCreated,
newUpdated: newEmailUpdated,
newDestroyed: emailChangeResponse?.destroyed);
if (emailChangeResponse != null && emailChangeResponse.newStateEmail != null) {
await _updateState(emailChangeResponse.newStateEmail!);
}
} else {
if (networkEmailResponse != null) {
await _updateEmailCache(newCreated: networkEmailResponse.emailList);
if (networkEmailResponse.state != null) {
await _updateState(networkEmailResponse.state!);
}
}
}
final newEmailResponse = await Future.wait([
mapDataSource[DataSourceType.local]!.getAllEmailCache(inMailboxId: inMailboxId, sort: sort),
stateDataSource.getState(StateType.email)
]).then((List response) {
return EmailResponse(emailList: response.first, state: response.last);
});
yield newEmailResponse;
}
Future<List<Email>?> _combineEmailCache({
List<Email>? emailUpdated,
Properties? updatedProperties,
List<Email>? emailCacheList
}) async {
if (emailUpdated != null && emailUpdated.isNotEmpty) {
final newEmailUpdated = emailUpdated.map((email) {
if (updatedProperties == null) {
return email;
} else {
final emailOld = emailCacheList?.findEmail(email.id);
if (emailOld != null) {
return emailOld.combineEmail(email, updatedProperties);
} else {
return email;
}
}
}).toList();
return newEmailUpdated;
}
return emailUpdated;
}
Future<void> _updateEmailCache({
List<Email>? newUpdated,
List<Email>? newCreated,
List<EmailId>? newDestroyed
}) async {
await mapDataSource[DataSourceType.local]!.update(
updated: newUpdated,
created: newCreated,
destroyed: newDestroyed);
}
Future<void> _updateState(State newState) async {
await stateDataSource.saveState(newState.toStateCache(StateType.email));
}
}