TF-123 Implement refresh all mailbox

This commit is contained in:
dab246
2021-09-28 15:51:10 +07:00
committed by Dat H. Pham
parent 8f5171d581
commit eb29f514dc
52 changed files with 745 additions and 368 deletions
@@ -1,6 +0,0 @@
abstract class CacheConfig {
Future initializeDatabase();
void registerAdapter();
}
@@ -1,7 +1,7 @@
import 'package:hive/hive.dart';
abstract class CacheClient<T> {
abstract class HiveCacheClient<T> {
String get tableName;
@@ -13,7 +13,7 @@ abstract class CacheClient<T> {
Future<T?> getItem(String key);
Future<List<T>> getListItem();
Future<List<T>> getAll();
Future<void> updateItem(String key, T newObject);
@@ -1,29 +1,28 @@
import 'dart:io';
import 'package:hive/hive.dart';
import 'package:model/caching/mailbox/mailbox_rights_cache.dart';
import 'package:model/model.dart';
import 'package:path_provider/path_provider.dart' as pathProvider;
import 'package:tmail_ui_user/features/caching/config/cache_config.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
class HiveCacheConfig extends CacheConfig {
class HiveCacheConfig {
Future setUp() async {
await initializeDatabase();
registerAdapter();
}
@override
Future initializeDatabase() async {
Directory directory = await pathProvider.getApplicationDocumentsDirectory();
Hive.init(directory.path);
}
@override
void registerAdapter() {
Hive.registerAdapter(MailboxCacheAdapter());
Hive.registerAdapter(MailboxRightsCacheAdapter());
Hive.registerAdapter(StateDaoAdapter());
Hive.registerAdapter(StateCacheAdapter());
Hive.registerAdapter(StateTypeAdapter());
}
}
@@ -1,9 +1,9 @@
import 'package:hive/hive.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/caching/config/cache_client.dart';
import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
class MailboxCacheClient extends CacheClient<MailboxCache> {
class MailboxCacheClient extends HiveCacheClient<MailboxCache> {
@override
String get tableName => 'MailboxCache';
@@ -51,7 +51,7 @@ class MailboxCacheClient extends CacheClient<MailboxCache> {
}
@override
Future<List<MailboxCache>> getListItem() {
Future<List<MailboxCache>> getAll() {
return Future.sync(() async {
final boxMailbox = await openTable();
return boxMailbox.values.toList();
+12 -12
View File
@@ -1,20 +1,20 @@
import 'package:hive/hive.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/caching/config/cache_client.dart';
import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
class StateCacheClient extends CacheClient<StateDao> {
class StateCacheClient extends HiveCacheClient<StateCache> {
@override
String get tableName => 'StateCache';
@override
Future<Box<StateDao>> openTable() {
Future<Box<StateCache>> openTable() {
return Future.sync(() async {
if (Hive.isBoxOpen(tableName)) {
return Hive.box<StateDao>(tableName);
return Hive.box<StateCache>(tableName);
}
return await Hive.openBox<StateDao>(tableName);
return await Hive.openBox<StateCache>(tableName);
}).catchError((error) {
throw error;
});
@@ -41,7 +41,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<StateDao?> getItem(String key) {
Future<StateCache?> getItem(String key) {
return Future.sync(() async {
final boxState = await openTable();
return boxState.get(key);
@@ -51,7 +51,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<List<StateDao>> getListItem() {
Future<List<StateCache>> getAll() {
return Future.sync(() async {
final boxState = await openTable();
return boxState.values.toList();
@@ -61,7 +61,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<void> insertItem(String key, StateDao newObject) {
Future<void> insertItem(String key, StateCache newObject) {
return Future.sync(() async {
final boxState = await openTable();
boxState.put(key, newObject);
@@ -71,7 +71,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<void> insertMultipleItem(Map<String, StateDao> mapObject) {
Future<void> insertMultipleItem(Map<String, StateCache> mapObject) {
return Future.sync(() async {
final boxState = await openTable();
boxState.putAll(mapObject);
@@ -81,7 +81,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<void> updateItem(String key, StateDao newObject) {
Future<void> updateItem(String key, StateCache newObject) {
return Future.sync(() async {
final boxState = await openTable();
boxState.put(key, newObject);
@@ -110,7 +110,7 @@ class StateCacheClient extends CacheClient<StateDao> {
}
@override
Future<void> updateMultipleItem(Map<String, StateDao> mapObject) {
Future<void> updateMultipleItem(Map<String, StateCache> mapObject) {
return Future.sync(() async {
final boxState = await openTable();
boxState.putAll(mapObject);
@@ -187,6 +187,7 @@ class ComposerController extends BaseController {
} else if (fromEmailAddress != null && fromEmailAddress.isNotEmpty) {
listReplyToEmailAddress.value = fromEmailAddress.toList();
}
listToEmailAddress = listReplyToEmailAddress;
}
_updateStatusEmailSendButton();
}
@@ -1,11 +1,14 @@
import 'package:core/core.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
import 'package:tmail_ui_user/features/destination_picker/presentation/destination_picker_controller.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/state_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
@@ -17,10 +20,15 @@ class DestinationPickerBindings extends Bindings {
Get.lazyPut(() => MailboxDataSourceImpl(Get.find<MailboxAPI>()));
Get.lazyPut<MailboxDataSource>(() => Get.find<MailboxDataSourceImpl>());
Get.lazyPut(() => MailboxCacheDataSourceImpl(Get.find<MailboxCacheManager>()));
Get.lazyPut(() => MailboxRepositoryImpl({
DataSourceType.network: Get.find<MailboxDataSource>(),
DataSourceType.local: Get.find<MailboxCacheDataSourceImpl>(),
}));
Get.lazyPut(() => StateDataSourceImpl(Get.find<StateCacheClient>()));
Get.lazyPut<StateDataSource>(() => Get.find<StateDataSourceImpl>());
Get.lazyPut(() => MailboxRepositoryImpl(
{
DataSourceType.network: Get.find<MailboxDataSource>(),
DataSourceType.local: Get.find<MailboxCacheDataSourceImpl>()
},
Get.find<StateDataSource>()
));
Get.lazyPut<MailboxRepository>(() => Get.find<MailboxRepositoryImpl>());
Get.lazyPut(() => GetAllMailboxInteractor(Get.find<MailboxRepository>()));
Get.lazyPut(() => TreeBuilder());
@@ -1,19 +1,16 @@
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/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
abstract class MailboxDataSource {
Future<GetMailboxResponse?> getAllMailbox(AccountId accountId, {Properties? properties});
Future<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties});
Future<List<Mailbox>> getAllMailboxCache();
Future<MailboxChangeResponse> getChanges(AccountId accountId, State sinceState);
Future<MailboxCacheResponse> getAllMailboxCache();
Future<MailboxChangeResponse> combineMailboxCache(MailboxChangeResponse mailboxChangeResponse, List<Mailbox> mailboxList);
Future<void> asyncUpdateCache(MailboxChangeResponse mailboxChangeResponse);
Future<void> update({List<Mailbox>? updated, List<Mailbox>? created, List<MailboxId>? destroyed});
}
@@ -0,0 +1,9 @@
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
abstract class StateDataSource {
Future<State?> getState(StateType stateType);
Future<void> saveState(StateCache stateCache);
}
@@ -1,12 +1,11 @@
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/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
class MailboxCacheDataSourceImpl extends MailboxDataSource {
@@ -15,37 +14,28 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource {
MailboxCacheDataSourceImpl(this._mailboxCacheManager);
@override
Future<GetMailboxResponse?> getAllMailbox(AccountId accountId, {Properties? properties}) {
Future<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties}) {
throw UnimplementedError();
}
@override
Future<MailboxCacheResponse> getAllMailboxCache() {
return Future.sync(() async {
return await _mailboxCacheManager.getAllMailbox();
}).catchError((error) {
throw error;
});
}
@override
Future<void> asyncUpdateCache(MailboxChangeResponse mailboxChangeResponse) {
return Future.sync(() async {
return await _mailboxCacheManager.asyncUpdateCache(mailboxChangeResponse);
}).catchError((error) {
throw error;
});
}
@override
Future<MailboxChangeResponse> getChanges(AccountId accountId, State sinceState) {
throw UnimplementedError();
}
@override
Future<MailboxChangeResponse> combineMailboxCache(MailboxChangeResponse mailboxChangeResponse, List<Mailbox> mailboxList) {
Future<void> update({List<Mailbox>? updated, List<Mailbox>? created, List<MailboxId>? destroyed}) {
return Future.sync(() async {
return await _mailboxCacheManager.combineMailboxCache(mailboxChangeResponse, mailboxList);
return await _mailboxCacheManager.update(updated: updated, created: created, destroyed: destroyed);
}).catchError((error) {
throw error;
});
}
@override
Future<List<Mailbox>> getAllMailboxCache() {
return Future.sync(() async {
return await _mailboxCacheManager.getAllMailbox();
}).catchError((error) {
throw error;
});
@@ -1,21 +1,20 @@
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/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
class MailboxDataSourceImpl extends MailboxDataSource {
final MailboxAPI mailboxAPI;
MailboxDataSourceImpl(this.mailboxAPI,);
MailboxDataSourceImpl(this.mailboxAPI);
@override
Future<GetMailboxResponse?> getAllMailbox(AccountId accountId, {Properties? properties}) {
Future<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties}) {
return Future.sync(() async {
return await mailboxAPI.getAllMailbox(accountId, properties: properties);
}).catchError((error) {
@@ -23,16 +22,6 @@ class MailboxDataSourceImpl extends MailboxDataSource {
});
}
@override
Future<MailboxCacheResponse> getAllMailboxCache() {
throw UnimplementedError();
}
@override
Future<void> asyncUpdateCache(MailboxChangeResponse mailboxChangeResponse) {
throw UnimplementedError();
}
@override
Future<MailboxChangeResponse> getChanges(AccountId accountId, State sinceState) {
return Future.sync(() async {
@@ -43,7 +32,12 @@ class MailboxDataSourceImpl extends MailboxDataSource {
}
@override
Future<MailboxChangeResponse> combineMailboxCache(MailboxChangeResponse mailboxChangeResponse, List<Mailbox> mailboxList) {
Future<void> update({List<Mailbox>? updated, List<Mailbox>? created, List<MailboxId>? destroyed}) {
throw UnimplementedError();
}
@override
Future<List<Mailbox>> getAllMailboxCache() {
throw UnimplementedError();
}
}
@@ -0,0 +1,38 @@
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/state_cache_extension.dart';
class StateDataSourceImpl extends StateDataSource {
final StateCacheClient _stateCacheClient;
StateDataSourceImpl(this._stateCacheClient);
@override
Future<State?> getState(StateType stateType) {
return Future.sync(() async {
final stateCache = await _stateCacheClient.getItem(stateType.value);
return stateCache != null ? stateCache.toState() : null;
}).catchError((error) {
throw error;
});
}
@override
Future<void> saveState(StateCache stateCache) {
return Future.sync(() async {
final stateCacheExist = await _stateCacheClient.isExistTable();
if (stateCacheExist) {
return await _stateCacheClient.updateItem(stateCache.type.value, stateCache);
} else {
return await _stateCacheClient.insertItem(stateCache.type.value, stateCache);
}
}).catchError((error) {
throw error;
});
}
}
@@ -1,6 +1,5 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
extension ListMailboxCacheExtension on List<MailboxCache> {
Map<String, MailboxCache> toMap() {
@@ -9,8 +8,4 @@ extension ListMailboxCacheExtension on List<MailboxCache> {
key: (mailboxCache) => mailboxCache.id,
value: (mailboxCache) => mailboxCache);
}
List<Mailbox> toMailboxList() {
return map((mailboxCache) => mailboxCache.toMailbox()).toList();
}
}
@@ -2,7 +2,8 @@
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/mailbox_rights_cache_extension.dart';
extension MailboxCacheExtension on MailboxCache {
Mailbox toMailbox() {
@@ -0,0 +1,18 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
extension MailboxChangeResponseExtension on MailboxChangeResponse {
MailboxChangeResponse updatedMailboxChangeResponse(List<Mailbox>? updatedMailbox) {
return MailboxChangeResponse(
updated: updatedMailbox,
created: created,
destroyed: destroyed,
newStateMailbox: newStateMailbox,
newStateChanges: newStateChanges,
hasMoreChanges: hasMoreChanges,
updatedProperties: updatedProperties
);
}
}
@@ -0,0 +1,22 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/mailbox_rights_extension.dart';
extension MailboxExtension on Mailbox {
MailboxCache toMailboxCache() {
return MailboxCache(
id.id.value,
name: name?.name,
parentId: parentId?.id.value,
role: role?.value,
sortOrder: sortOrder?.value.value.round(),
totalEmails: totalEmails?.value.value.round(),
unreadEmails: unreadEmails?.value.value.round(),
totalThreads: totalThreads?.value.value.round(),
unreadThreads: unreadThreads?.value.value.round(),
myRights: myRights != null ? myRights!.toMailboxRightsCache() : null,
isSubscribed: isSubscribed?.value
);
}
}
@@ -1,5 +1,5 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart';
import 'package:model/caching/mailbox/mailbox_rights_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.dart';
extension MailboxRightsCacheExtension on MailboxRightsCache {
MailboxRights toMailboxRights() {
@@ -1,5 +1,5 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart';
import 'package:model/caching/mailbox/mailbox_rights_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.dart';
extension MailboxRightsExtension on MailboxRights {
MailboxRightsCache toMailboxRightsCache() {
@@ -0,0 +1,9 @@
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
extension StateCacheExtension on StateCache {
State toState() {
return State(state);
}
}
@@ -0,0 +1,10 @@
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
extension StateExtension on State {
StateCache toStateCache(StateType stateType) {
return StateCache(stateType, value);
}
}
@@ -0,0 +1,41 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/caching/mailbox_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/list_mailbox_cache_extension.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/mailbox_cache_extension.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart';
class MailboxCacheManager {
final MailboxCacheClient _mailboxCacheClient;
MailboxCacheManager(this._mailboxCacheClient);
Future<List<Mailbox>> getAllMailbox() async {
final mailboxCacheList = await _mailboxCacheClient.getAll();
final mailboxList = mailboxCacheList.map((mailboxCache) => mailboxCache.toMailbox()).toList();
return mailboxList;
}
Future<void> update({List<Mailbox>? updated, List<Mailbox>? created, List<MailboxId>? destroyed}) async {
final mailboxCacheExist = await _mailboxCacheClient.isExistTable();
if (mailboxCacheExist) {
final updatedCacheMailboxes = updated
?.map((mailbox) => mailbox.toMailboxCache()).toList() ?? <MailboxCache>[];
final createdCacheMailboxes = created
?.map((mailbox) => mailbox.toMailboxCache()).toList() ?? <MailboxCache>[];
final destroyedCacheMailboxes = destroyed
?.map((mailboxId) => mailboxId.id.value).toList() ?? <String>[];
await Future.wait([
_mailboxCacheClient.updateMultipleItem(updatedCacheMailboxes.toMap()),
_mailboxCacheClient.insertMultipleItem(createdCacheMailboxes.toMap()),
_mailboxCacheClient.deleteMultipleItem(destroyedCacheMailboxes)
]);
} else {
final createdCacheMailboxes = created
?.map((mailbox) => mailbox.toMailboxCache()).toList() ?? <MailboxCache>[];
await _mailboxCacheClient.insertMultipleItem(createdCacheMailboxes.toMap());
}
}
}
@@ -1,8 +1,8 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:model/caching/mailbox/mailbox_rights_cache.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.dart';
import 'package:tmail_ui_user/features/mailbox/data/utils/caching_constants.dart';
part 'mailbox_cache.g.dart';
@@ -0,0 +1,74 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'mailbox_cache.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class MailboxCacheAdapter extends TypeAdapter<MailboxCache> {
@override
final int typeId = 1;
@override
MailboxCache read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return MailboxCache(
fields[0] as String,
name: fields[1] as String?,
parentId: fields[2] as String?,
role: fields[3] as String?,
sortOrder: fields[4] as int?,
totalEmails: fields[5] as int?,
unreadEmails: fields[6] as int?,
totalThreads: fields[7] as int?,
unreadThreads: fields[8] as int?,
myRights: fields[9] as MailboxRightsCache?,
isSubscribed: fields[10] as bool?,
lastOpened: fields[11] as DateTime?,
);
}
@override
void write(BinaryWriter writer, MailboxCache obj) {
writer
..writeByte(12)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.name)
..writeByte(2)
..write(obj.parentId)
..writeByte(3)
..write(obj.role)
..writeByte(4)
..write(obj.sortOrder)
..writeByte(5)
..write(obj.totalEmails)
..writeByte(6)
..write(obj.unreadEmails)
..writeByte(7)
..write(obj.totalThreads)
..writeByte(8)
..write(obj.unreadThreads)
..writeByte(9)
..write(obj.myRights)
..writeByte(10)
..write(obj.isSubscribed)
..writeByte(11)
..write(obj.lastOpened);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MailboxCacheAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
@@ -1,16 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:model/model.dart';
class MailboxCacheResponse with EquatableMixin {
final List<MailboxCache>? mailboxCaches;
final StateDao? oldState;
MailboxCacheResponse({
this.mailboxCaches,
this.oldState
});
@override
List<Object?> get props => [mailboxCaches, oldState];
}
@@ -8,17 +8,29 @@ class MailboxChangeResponse with EquatableMixin {
final List<Mailbox>? updated;
final List<Mailbox>? created;
final List<MailboxId>? destroyed;
final State? newState;
final State? newStateMailbox;
final State? newStateChanges;
final bool hasMoreChanges;
final Properties? updatedProperties;
MailboxChangeResponse({
this.updated,
this.created,
this.destroyed,
this.newState,
this.newStateMailbox,
this.newStateChanges,
this.hasMoreChanges = false,
this.updatedProperties,
});
@override
List<Object?> get props => [updated, created, destroyed, newState, updatedProperties];
List<Object?> get props => [
updated,
created,
destroyed,
newStateMailbox,
newStateChanges,
hasMoreChanges,
updatedProperties
];
}
@@ -0,0 +1,23 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
class MailboxResponse with EquatableMixin {
final List<Mailbox>? mailboxes;
final State? state;
MailboxResponse({
this.mailboxes,
this.state
});
bool hasData() {
return mailboxes != null
&& mailboxes!.isNotEmpty
&& state != null;
}
@override
List<Object?> get props => [mailboxes, state];
}
@@ -1,7 +1,7 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/utils/caching_constants.dart';
part 'mailbox_rights_cache.g.dart';
@@ -0,0 +1,65 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'mailbox_rights_cache.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class MailboxRightsCacheAdapter extends TypeAdapter<MailboxRightsCache> {
@override
final int typeId = 2;
@override
MailboxRightsCache read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return MailboxRightsCache(
fields[0] as bool,
fields[1] as bool,
fields[2] as bool,
fields[3] as bool,
fields[4] as bool,
fields[5] as bool,
fields[6] as bool,
fields[7] as bool,
fields[8] as bool,
);
}
@override
void write(BinaryWriter writer, MailboxRightsCache obj) {
writer
..writeByte(9)
..writeByte(0)
..write(obj.mayReadItems)
..writeByte(1)
..write(obj.mayAddItems)
..writeByte(2)
..write(obj.mayRemoveItems)
..writeByte(3)
..write(obj.maySetSeen)
..writeByte(4)
..write(obj.maySetKeywords)
..writeByte(5)
..write(obj.mayCreateChild)
..writeByte(6)
..write(obj.mayRename)
..writeByte(7)
..write(obj.mayDelete)
..writeByte(8)
..write(obj.maySubmit);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MailboxRightsCacheAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
@@ -0,0 +1,22 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/mailbox/data/utils/caching_constants.dart';
part 'state_cache.g.dart';
@HiveType(typeId: CachingConstants.STATE_CACHE_IDENTIFY)
class StateCache extends HiveObject with EquatableMixin {
@HiveField(0)
final StateType type;
@HiveField(1)
final String state;
StateCache(this.type, this.state);
@override
List<Object?> get props => [type, state];
}
@@ -0,0 +1,44 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'state_cache.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class StateCacheAdapter extends TypeAdapter<StateCache> {
@override
final int typeId = 3;
@override
StateCache read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return StateCache(
fields[0] as StateType,
fields[1] as String,
);
}
@override
void write(BinaryWriter writer, StateCache obj) {
writer
..writeByte(2)
..writeByte(0)
..write(obj.type)
..writeByte(1)
..write(obj.state);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is StateCacheAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
@@ -1,6 +1,6 @@
import 'package:hive/hive.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/utils/caching_constants.dart';
part 'state_type.g.dart';
@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'state_type.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class StateTypeAdapter extends TypeAdapter<StateType> {
@override
final int typeId = 4;
@override
StateType read(BinaryReader reader) {
switch (reader.readByte()) {
case 0:
return StateType.mailbox;
default:
return StateType.mailbox;
}
}
@override
void write(BinaryWriter writer, StateType obj) {
switch (obj) {
case StateType.mailbox:
writer.writeByte(0);
break;
}
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is StateTypeAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
@@ -13,6 +13,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
class MailboxAPI {
@@ -20,7 +21,7 @@ class MailboxAPI {
MailboxAPI(this.httpClient);
Future<GetMailboxResponse?> getAllMailbox(AccountId accountId, {Properties? properties}) async {
Future<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties}) async {
final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
@@ -38,7 +39,7 @@ class MailboxAPI {
queryInvocation.methodCallId,
GetMailboxResponse.deserialize);
return resultCreated;
return MailboxResponse(mailboxes: resultCreated?.list, state: resultCreated?.state);
}
Future<MailboxChangeResponse> getChanges(AccountId accountId, State sinceState) async {
@@ -85,19 +86,13 @@ class MailboxAPI {
final listMailboxIdDestroyed = resultChanges?.destroyed.map((id) => MailboxId(id)).toList() ?? <MailboxId>[];
final updatedProperties = resultChanges?.updatedProperties;
final listMailboxUpdated = resultUpdated?.list ?? <Mailbox>[];
final listMailboxCreated = resultCreated?.list ?? <Mailbox>[];
final newState = resultChanges?.newState;
return MailboxChangeResponse(
updated: listMailboxUpdated,
created: listMailboxCreated,
updated: resultUpdated?.list,
created: resultCreated?.list,
destroyed: listMailboxIdDestroyed,
newState: newState,
updatedProperties: updatedProperties);
newStateMailbox: resultUpdated?.state,
newStateChanges: resultChanges?.newState,
hasMoreChanges: resultChanges?.hasMoreChanges ?? false,
updatedProperties: resultChanges?.updatedProperties);
}
}
@@ -1,105 +0,0 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/caching/mailbox_cache_client.dart';
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
class MailboxCacheManager {
final MailboxCacheClient _mailboxCacheClient;
final StateCacheClient _stateCacheClient;
MailboxCacheManager(this._mailboxCacheClient, this._stateCacheClient);
Future<MailboxCacheResponse> getAllMailbox() async {
return await Future.wait(
[
_stateCacheClient.getItem(StateType.mailbox.value),
_mailboxCacheClient.getListItem()
],
eagerError: true
).then((List responses) {
return MailboxCacheResponse(mailboxCaches: responses.last, oldState: responses.first);
});
}
Future<MailboxChangeResponse> combineMailboxCache(MailboxChangeResponse mailboxChangeResponse, List<Mailbox> mailboxList) async {
final mailboxUpdated = mailboxChangeResponse.updated;
final updatedProperties = mailboxChangeResponse.updatedProperties;
if (mailboxUpdated != null && mailboxUpdated.isNotEmpty) {
final newListMailboxUpdated = mailboxUpdated.map((mailboxUpdated) {
if (updatedProperties == null) {
return mailboxUpdated;
} else {
final mailboxOld = findMailbox(mailboxUpdated.id, mailboxList);
if (mailboxOld != null) {
return mailboxOld.combineMailbox(mailboxUpdated, updatedProperties);
} else {
return mailboxUpdated;
}
}
}).toList();
final newMailboxChangeResponse = MailboxChangeResponse(
created: mailboxChangeResponse.created,
destroyed: mailboxChangeResponse.destroyed,
updated: newListMailboxUpdated,
newState: mailboxChangeResponse.newState,
updatedProperties: mailboxChangeResponse.updatedProperties
);
return newMailboxChangeResponse;
}
return mailboxChangeResponse;
}
Mailbox? findMailbox(MailboxId mailboxId, List<Mailbox> mailboxList) {
try {
return mailboxList.firstWhere((element) => element.id == mailboxId);
} catch (e) {
return null;
}
}
Future<void> asyncUpdateCache(MailboxChangeResponse mailboxChangeResponse) async {
if (mailboxChangeResponse.newState != null) {
final stateCacheExist = await _stateCacheClient.isExistTable();
if (stateCacheExist) {
_stateCacheClient.updateItem(
StateType.mailbox.value,
mailboxChangeResponse.newState!.toStateDao(StateType.mailbox));
} else {
_stateCacheClient.insertItem(
StateType.mailbox.value,
mailboxChangeResponse.newState!.toStateDao(StateType.mailbox));
}
}
final mailboxCacheExist = await _mailboxCacheClient.isExistTable();
if (mailboxCacheExist) {
final updatedCacheMailboxes = mailboxChangeResponse.updated
?.map((mailbox) => mailbox.toMailboxCache())
.toList() ?? <MailboxCache>[];
final createdCacheMailboxes = mailboxChangeResponse.created
?.map((mailbox) => mailbox.toMailboxCache())
.toList() ?? <MailboxCache>[];
final destroyedCacheMailboxes = mailboxChangeResponse.destroyed
?.map((mailboxId) => mailboxId.id.value)
.toList() ?? <String>[];
await Future.wait([
_mailboxCacheClient.updateMultipleItem(updatedCacheMailboxes.toMap()),
_mailboxCacheClient.insertMultipleItem(createdCacheMailboxes.toMap()),
_mailboxCacheClient.deleteMultipleItem(destroyedCacheMailboxes)
]);
} else {
final createdCacheMailboxes = mailboxChangeResponse.created
?.map((mailbox) => mailbox.toMailboxCache())
.toList() ?? <MailboxCache>[];
await _mailboxCacheClient.insertMultipleItem(createdCacheMailboxes.toMap());
}
}
}
@@ -1,65 +1,137 @@
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/properties/properties.dart';
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/extensions/state_extension.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
class MailboxRepositoryImpl extends MailboxRepository {
final Map<DataSourceType, MailboxDataSource> mapDataSource;
final StateDataSource stateDataSource;
MailboxRepositoryImpl(this.mapDataSource);
MailboxRepositoryImpl(this.mapDataSource, this.stateDataSource);
@override
Stream<List<Mailbox>> getAllMailbox(AccountId accountId, {Properties? properties}) async* {
final mailboxCacheResponse = await mapDataSource[DataSourceType.local]!.getAllMailboxCache();
Stream<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties}) async* {
final localMailboxResponse = await Future.wait([
mapDataSource[DataSourceType.local]!.getAllMailboxCache(),
stateDataSource.getState(StateType.mailbox)
]).then((List response) {
return MailboxResponse(mailboxes: response.first, state: response.last);
});
final mailboxList = mailboxCacheResponse.mailboxCaches != null
? mailboxCacheResponse.mailboxCaches!.toMailboxList()
: <Mailbox>[];
final oldState = mailboxCacheResponse.oldState?.state;
yield localMailboxResponse;
yield mailboxList;
if (localMailboxResponse.hasData()) {
bool hasMoreChanges = true;
State? sinceState = localMailboxResponse.state!;
if (mailboxList.isNotEmpty && oldState != null) {
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(accountId, State(oldState));
while(hasMoreChanges && sinceState != null) {
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(accountId, sinceState);
final newChangesResponse = await mapDataSource[DataSourceType.local]!.combineMailboxCache(changesResponse, mailboxList);
hasMoreChanges = changesResponse.hasMoreChanges;
sinceState = changesResponse.newStateChanges;
await mapDataSource[DataSourceType.local]!.asyncUpdateCache(newChangesResponse);
final newMailboxUpdated = await _combineMailboxCache(
mailboxUpdated: changesResponse.updated,
updatedProperties: changesResponse.updatedProperties,
mailboxCacheList: localMailboxResponse.mailboxes!);
await Future.wait([
mapDataSource[DataSourceType.local]!.update(
updated: newMailboxUpdated,
created: changesResponse.created,
destroyed: changesResponse.destroyed),
if (changesResponse.newStateMailbox != null)
stateDataSource.saveState(changesResponse.newStateMailbox!.toStateCache(StateType.mailbox)),
]);
}
} else {
final getMailboxResponse = await mapDataSource[DataSourceType.network]!.getAllMailbox(accountId);
final mailboxResponse = await mapDataSource[DataSourceType.network]!.getAllMailbox(accountId);
await mapDataSource[DataSourceType.local]!.asyncUpdateCache(MailboxChangeResponse(
created: getMailboxResponse?.list,
newState: getMailboxResponse?.state));
await Future.wait([
mapDataSource[DataSourceType.local]!.update(created: mailboxResponse.mailboxes),
if (mailboxResponse.state != null)
stateDataSource.saveState(mailboxResponse.state!.toStateCache(StateType.mailbox)),
]);
}
final newMailboxCacheResponse = await mapDataSource[DataSourceType.local]!.getAllMailboxCache();
final newMailboxResponse = await Future.wait([
mapDataSource[DataSourceType.local]!.getAllMailboxCache(),
stateDataSource.getState(StateType.mailbox)
]).then((List response) {
return MailboxResponse(mailboxes: response.first, state: response.last);
});
final newMailboxList = newMailboxCacheResponse.mailboxCaches != null
? newMailboxCacheResponse.mailboxCaches!.toMailboxList()
: <Mailbox>[];
yield newMailboxResponse;
}
yield newMailboxList;
Future<List<Mailbox>?> _combineMailboxCache({
List<Mailbox>? mailboxUpdated,
Properties? updatedProperties,
List<Mailbox>? mailboxCacheList
}) async {
if (mailboxUpdated != null && mailboxUpdated.isNotEmpty) {
final newMailboxUpdated = mailboxUpdated.map((mailboxUpdated) {
if (updatedProperties == null) {
return mailboxUpdated;
} else {
final mailboxOld = mailboxCacheList?.findMailbox(mailboxUpdated.id);
if (mailboxOld != null) {
return mailboxOld.combineMailbox(mailboxUpdated, updatedProperties);
} else {
return mailboxUpdated;
}
}
}).toList();
return newMailboxUpdated;
}
return mailboxUpdated;
}
@override
Stream<List<Mailbox>> refresh(AccountId accountId, State currentState) async* {
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(accountId, currentState);
Stream<MailboxResponse> refresh(AccountId accountId, State currentState) async* {
final localMailboxList = await mapDataSource[DataSourceType.local]!.getAllMailboxCache();
await mapDataSource[DataSourceType.local]!.asyncUpdateCache(changesResponse);
bool hasMoreChanges = true;
State? sinceState = currentState;
final newMailboxCacheResponse = await mapDataSource[DataSourceType.local]!.getAllMailboxCache();
while(hasMoreChanges && sinceState != null) {
final changesResponse = await mapDataSource[DataSourceType.network]!.getChanges(accountId, sinceState);
final newMailboxList = newMailboxCacheResponse.mailboxCaches != null
? newMailboxCacheResponse.mailboxCaches!.toMailboxList()
: <Mailbox>[];
hasMoreChanges = changesResponse.hasMoreChanges;
sinceState = changesResponse.newStateChanges;
yield newMailboxList;
final newMailboxUpdated = await _combineMailboxCache(
mailboxUpdated: changesResponse.updated,
updatedProperties: changesResponse.updatedProperties,
mailboxCacheList: localMailboxList);
await Future.wait([
mapDataSource[DataSourceType.local]!.update(
updated: newMailboxUpdated,
created: changesResponse.created,
destroyed: changesResponse.destroyed),
if (changesResponse.newStateMailbox != null)
stateDataSource.saveState(changesResponse.newStateMailbox!.toStateCache(StateType.mailbox)),
]);
}
final newMailboxResponse = await Future.wait([
mapDataSource[DataSourceType.local]!.getAllMailboxCache(),
stateDataSource.getState(StateType.mailbox)
]).then((List response) {
return MailboxResponse(mailboxes: response.first, state: response.last);
});
yield newMailboxResponse;
}
}
@@ -2,6 +2,6 @@
class CachingConstants {
static const int MAILBOX_CACHE_IDENTIFY = 1;
static const int MAILBOX_RIGHTS_CACHE_IDENTIFY = 2;
static const int STATE_DAO_IDENTIFY = 3;
static const int STATE_CACHE_IDENTIFY = 3;
static const int STATE_TYPE_IDENTIFY = 4;
}
@@ -1,10 +1,10 @@
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/state.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
abstract class MailboxRepository {
Stream<List<Mailbox>> getAllMailbox(AccountId accountId, {Properties? properties});
Stream<MailboxResponse> getAllMailbox(AccountId accountId, {Properties? properties});
Stream<List<Mailbox>> refresh(AccountId accountId, State currentState);
Stream<MailboxResponse> refresh(AccountId accountId, State currentState);
}
@@ -1,14 +1,20 @@
import 'package:core/core.dart';
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
class GetAllMailboxSuccess extends UIState {
final List<PresentationMailbox> defaultMailboxList;
final List<PresentationMailbox> folderMailboxList;
final State? currentMailboxState;
GetAllMailboxSuccess({required this.defaultMailboxList, required this.folderMailboxList});
GetAllMailboxSuccess({
required this.defaultMailboxList,
required this.folderMailboxList,
required this.currentMailboxState
});
@override
List<Object> get props => [folderMailboxList];
List<Object?> get props => [defaultMailboxList, folderMailboxList, currentMailboxState];
}
class GetAllMailboxFailure extends FeatureFailure {
@@ -2,6 +2,7 @@ import 'package:core/core.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/extensions/list_mailbox_extension.dart';
@@ -16,18 +17,21 @@ class GetAllMailboxInteractor {
try {
yield Right<Failure, Success>(LoadingState());
final streamListMailbox = _mailboxRepository.getAllMailbox(accountId, properties: properties);
final streamResult = streamListMailbox.asyncExpand((mailboxList) async* {
final tupleList = mailboxList.splitMailboxList((mailbox) => mailbox.hasRole());
yield Right<Failure, Success>(GetAllMailboxSuccess(
defaultMailboxList: tupleList.value1,
folderMailboxList: tupleList.value2));
});
yield* streamResult;
yield* _mailboxRepository
.getAllMailbox(accountId, properties: properties)
.map(_toGetMailboxState);
} catch (e) {
yield Left<Failure, Success>(GetAllMailboxFailure(e));
}
}
Either<Failure, Success> _toGetMailboxState(MailboxResponse mailboxResponse) {
final tupleList = mailboxResponse.mailboxes
?.splitMailboxList((mailbox) => mailbox.hasRole()) ?? Tuple2([], []);
return Right<Failure, Success>(GetAllMailboxSuccess(
defaultMailboxList: tupleList.value1,
folderMailboxList: tupleList.value2,
currentMailboxState: mailboxResponse.state));
}
}
@@ -0,0 +1,37 @@
import 'package:core/core.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/extensions/list_mailbox_extension.dart';
import 'package:model/model.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmapState;
class RefreshAllMailboxInteractor {
final MailboxRepository _mailboxRepository;
RefreshAllMailboxInteractor(this._mailboxRepository);
Stream<Either<Failure, Success>> execute(AccountId accountId, jmapState.State currentState) async* {
try {
yield Right<Failure, Success>(LoadingState());
yield* _mailboxRepository
.refresh(accountId, currentState)
.map(_toGetMailboxState);
} catch (e) {
yield Left<Failure, Success>(GetAllMailboxFailure(e));
}
}
Either<Failure, Success> _toGetMailboxState(MailboxResponse mailboxResponse) {
final tupleList = mailboxResponse.mailboxes
?.splitMailboxList((mailbox) => mailbox.hasRole()) ?? Tuple2([], []);
return Right<Failure, Success>(GetAllMailboxSuccess(
defaultMailboxList: tupleList.value1,
folderMailboxList: tupleList.value2,
currentMailboxState: mailboxResponse.state));
}
}
@@ -1,17 +1,21 @@
import 'package:core/core.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
import 'package:tmail_ui_user/features/login/data/repository/credential_repository_impl.dart';
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/state_datasource_impl.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -24,16 +28,23 @@ class MailboxBindings extends Bindings {
Get.lazyPut(() => MailboxDataSourceImpl(Get.find<MailboxAPI>()));
Get.lazyPut<MailboxDataSource>(() => Get.find<MailboxDataSourceImpl>());
Get.lazyPut(() => MailboxCacheDataSourceImpl(Get.find<MailboxCacheManager>()));
Get.lazyPut(() => MailboxRepositoryImpl({
DataSourceType.network: Get.find<MailboxDataSource>(),
DataSourceType.local: Get.find<MailboxCacheDataSourceImpl>(),
}));
Get.lazyPut(() => StateDataSourceImpl(Get.find<StateCacheClient>()));
Get.lazyPut<StateDataSource>(() => Get.find<StateDataSourceImpl>());
Get.lazyPut(() => MailboxRepositoryImpl(
{
DataSourceType.network: Get.find<MailboxDataSource>(),
DataSourceType.local: Get.find<MailboxCacheDataSourceImpl>()
},
Get.find<StateDataSource>()
));
Get.lazyPut<MailboxRepository>(() => Get.find<MailboxRepositoryImpl>());
Get.lazyPut(() => GetAllMailboxInteractor(Get.find<MailboxRepository>()));
Get.lazyPut(() => RefreshAllMailboxInteractor(Get.find<MailboxRepository>()));
Get.lazyPut(() => TreeBuilder());
Get.put(MailboxController(
Get.find<GetAllMailboxInteractor>(),
Get.find<DeleteCredentialInteractor>(),
Get.find<RefreshAllMailboxInteractor>(),
Get.find<TreeBuilder>(),
Get.find<ResponsiveUtils>()));
}
@@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_sta
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
@@ -19,21 +20,26 @@ import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_emai
import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmapState;
class MailboxController extends BaseController {
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
final GetAllMailboxInteractor _getAllMailboxInteractor;
final DeleteCredentialInteractor _deleteCredentialInteractor;
final RefreshAllMailboxInteractor _refreshAllMailboxInteractor;
final TreeBuilder _treeBuilder;
final ResponsiveUtils responsiveUtils;
final defaultMailboxList = <PresentationMailbox>[].obs;
final folderMailboxNodeList = <MailboxNode>[].obs;
jmapState.State? currentMailboxState;
MailboxController(
this._getAllMailboxInteractor,
this._deleteCredentialInteractor,
this._refreshAllMailboxInteractor,
this._treeBuilder,
this.responsiveUtils
);
@@ -52,11 +58,11 @@ class MailboxController extends BaseController {
if (success is MarkAsEmailReadSuccess ||
success is MarkAsMultipleEmailReadAllSuccess ||
success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
refreshGetAllMailboxAction();
refreshMailboxChanges();
} else if (success is MoveMultipleEmailToMailboxAllSuccess
|| success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshGetAllMailboxAction();
refreshMailboxChanges();
}
});
});
@@ -68,17 +74,6 @@ class MailboxController extends BaseController {
super.onClose();
}
void refreshGetAllMailboxAction() {
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null) {
getAllMailboxAction(accountId);
}
}
void getAllMailboxAction(AccountId accountId) async {
consumeState(_getAllMailboxInteractor.execute(accountId));
}
@override
void onData(Either<Failure, Success> newState) {
super.onData(newState);
@@ -93,6 +88,7 @@ class MailboxController extends BaseController {
void onDone() {
viewState.value.map((success) {
if (success is GetAllMailboxSuccess) {
currentMailboxState = success.currentMailboxState;
defaultMailboxList.value = success.defaultMailboxList;
_setUpMapMailboxIdDefault(success.defaultMailboxList);
}
@@ -100,8 +96,24 @@ class MailboxController extends BaseController {
}
@override
void onError(error) {
print('$error');
void onError(error) {}
void getAllMailboxAction(AccountId accountId) async {
consumeState(_getAllMailboxInteractor.execute(accountId));
}
void refreshAllMailbox() {
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null) {
consumeState(_getAllMailboxInteractor.execute(accountId));
}
}
void refreshMailboxChanges() {
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null && currentMailboxState != null) {
consumeState(_refreshAllMailboxInteractor.execute(accountId, currentMailboxState!));
}
}
void _buildTree(List<PresentationMailbox> folderMailboxList) async {
@@ -31,7 +31,7 @@ class MailboxView extends GetWidget<MailboxController> {
left: false,
child: RefreshIndicator(
color: AppColor.primaryColor,
onRefresh: () async => controller.refreshGetAllMailboxAction(),
onRefresh: () async => controller.refreshAllMailbox(),
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Padding(
@@ -55,7 +55,7 @@ class MailboxDashBoardController extends BaseController {
(failure) {
if (failure is SendEmailFailure) {
if (Get.context != null) {
_appToast.showSuccessToast(AppLocalizations.of(Get.context!).error_message_sent);
_appToast.showErrorToast(AppLocalizations.of(Get.context!).error_message_sent);
clearState();
}
}
+2 -2
View File
@@ -3,7 +3,7 @@ import 'package:core/core.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/caching/mailbox_cache_client.dart';
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart';
class LocalBindings extends Bindings {
@@ -20,6 +20,6 @@ class LocalBindings extends Bindings {
void _bindingCaching() {
Get.put(MailboxCacheClient());
Get.put(StateCacheClient());
Get.put(MailboxCacheManager(Get.find<MailboxCacheClient>(), Get.find<StateCacheClient>()));
Get.put(MailboxCacheManager(Get.find<MailboxCacheClient>()));
}
}
-21
View File
@@ -1,21 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:model/model.dart';
part 'state_dao.g.dart';
@HiveType(typeId: CachingConstants.STATE_DAO_IDENTIFY)
class StateDao extends HiveObject with EquatableMixin {
@HiveField(0)
final StateType type;
@HiveField(1)
final String state;
StateDao(this.type, this.state);
@override
List<Object?> get props => [type, state];
}
@@ -0,0 +1,13 @@
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
extension ListMailboxExtension on List<Mailbox> {
Mailbox? findMailbox(MailboxId mailboxId) {
try {
return firstWhere((element) => element.id == mailboxId);
} catch (e) {
return null;
}
}
}
@@ -23,22 +23,6 @@ extension MailboxExtension on Mailbox {
);
}
MailboxCache toMailboxCache() {
return MailboxCache(
id.id.value,
name: name?.name,
parentId: parentId?.id.value,
role: role?.value,
sortOrder: sortOrder?.value.value.round(),
totalEmails: totalEmails?.value.value.round(),
unreadEmails: unreadEmails?.value.value.round(),
totalThreads: totalThreads?.value.value.round(),
unreadThreads: unreadThreads?.value.value.round(),
myRights: myRights != null ? myRights!.toMailboxRightsCache() : null,
isSubscribed: isSubscribed?.value
);
}
Mailbox combineMailbox(Mailbox newMailbox, Properties updatedProperties) {
return Mailbox(
newMailbox.id,
@@ -1,9 +0,0 @@
import 'package:jmap_dart_client/jmap/core/state.dart';
import 'package:model/model.dart';
extension StateExtension on State {
StateDao toStateDao(StateType stateType) {
return StateDao(stateType, value);
}
}
+2 -12
View File
@@ -44,12 +44,8 @@ export 'extensions/list_email_id_extension.dart';
export 'extensions/mailbox_id_extension.dart';
export 'extensions/mailbox_extension.dart';
export 'extensions/mailbox_name_extension.dart';
export 'extensions/list_mailbox_cache_extension.dart';
export 'extensions/state_extension.dart';
export 'extensions/mailbox_rights_extension.dart';
export 'extensions/mailbox_rights_cache_extension.dart';
export 'extensions/mailbox_cache_extension.dart';
export 'extensions/properties_extension.dart';
export 'extensions/list_mailbox_extension.dart';
// Download
export 'download/download_task_id.dart';
@@ -61,10 +57,4 @@ export 'contact/device_contact.dart';
// Upload
export 'upload/file_info.dart';
export 'upload/upload_request.dart';
export 'upload/upload_response.dart';
// Caching
export 'caching/caching_constants.dart';
export 'caching/mailbox/mailbox_cache.dart';
export 'caching/state/state_dao.dart';
export 'caching/state/state_type.dart';
export 'upload/upload_response.dart';
-5
View File
@@ -55,9 +55,6 @@ dependencies:
# http_parser
http_parser: 4.0.0
# hive
hive: 2.0.4
dev_dependencies:
flutter_test:
sdk: flutter
@@ -65,8 +62,6 @@ dev_dependencies:
build_runner: 2.0.5
json_serializable: 4.1.3
hive_generator: 1.1.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
+2
View File
@@ -132,6 +132,8 @@ dev_dependencies:
build_runner: 2.0.5
mockito: 5.0.10
hive_generator: 1.1.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec