TF-438 Implement method for get/store/delete StateToRefresh and get email changes

This commit is contained in:
dab246
2022-11-24 14:30:58 +07:00
committed by Dat H. Pham
parent 17dde9366f
commit c1416c88fa
16 changed files with 428 additions and 2 deletions
@@ -1,3 +1,5 @@
import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/fcm/fcm_token_dto.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/local/fcm_cache_manager.dart';
@@ -36,4 +38,31 @@ class HiveFCMDatasourceImpl extends FCMDatasource {
_exceptionThrower.throwException(error);
});
}
@override
Future<bool> storeStateToRefresh(TypeName typeName, jmap.State newState) {
return Future.sync(() async {
return await _firebaseCacheManager.storeStateToRefresh(typeName, newState);
}).catchError((error) {
_exceptionThrower.throwException(error);
});
}
@override
Future<jmap.State> getStateToRefresh(TypeName typeName) {
return Future.sync(() async {
return await _firebaseCacheManager.getStateToRefresh(typeName);
}).catchError((error) {
_exceptionThrower.throwException(error);
});
}
@override
Future<bool> deleteStateToRefresh(TypeName typeName) {
return Future.sync(() async {
return await _firebaseCacheManager.deleteStateToRefresh(typeName);
}).catchError((error) {
_exceptionThrower.throwException(error);
});
}
}
@@ -1,14 +1,18 @@
import 'package:core/utils/app_logger.dart';
import 'package:fcm/model/type_name.dart';
import 'package:model/fcm/fcm_token_dto.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tmail_ui_user/features/caching/fcm_token_cache_client.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/fcm_cache_extensions.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/fcm_extensions.dart';
import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class FCMCacheManager {
final FcmTokenCacheClient _fcmTokenCacheClient;
final SharedPreferences _sharedPreferences;
FCMCacheManager(this._fcmTokenCacheClient);
FCMCacheManager(this._fcmTokenCacheClient, this._sharedPreferences);
Future<FCMTokenDto> getFCMToken(String accountId) async {
try {
@@ -33,4 +37,36 @@ class FCMCacheManager {
log('FCMCacheManager::deleteSelectedFCM(): $accountId');
return _fcmTokenCacheClient.deleteItem(accountId);
}
Future<bool> storeStateToRefresh(TypeName typeName, jmap.State newState) {
return _sharedPreferences.setString(typeName.value, newState.value);
}
Future<jmap.State> getStateToRefresh(TypeName typeName) async {
log('FCMCacheManager::getStoredFcmStateChange():keys_BEFORE: ${_sharedPreferences.getKeys().toString()}');
await _sharedPreferences.reload();
log('FCMCacheManager::getStoredFcmStateChange():keys_AFTER: ${_sharedPreferences.getKeys().toString()}');
final stateValue = _sharedPreferences.getString(typeName.value);
if (stateValue != null) {
return jmap.State(stateValue);
} else {
if (typeName == TypeName.emailDelivery) {
throw NotFoundEmailDeliveryStateException();
} else {
throw NotFoundStateToRefreshException();
}
}
}
Future<bool> deleteStateToRefresh(TypeName typeName) {
return _sharedPreferences.remove(typeName.value);
}
Future<bool> clearAllStateToRefresh() async {
return await Future.wait([
_sharedPreferences.remove(TypeName.emailType.value),
_sharedPreferences.remove(TypeName.mailboxType.value),
_sharedPreferences.remove(TypeName.emailDelivery.value)
]).then((listResult) => listResult.every((result) => result));
}
}
@@ -1,13 +1,24 @@
import 'package:core/utils/app_logger.dart';
import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:model/fcm/fcm_token_dto.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.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:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
class FCMRepositoryImpl extends FCMRepository {
final FCMDatasource _fcmDatasource;
final ThreadDataSource _threadDataSource;
FCMRepositoryImpl(this._fcmDatasource);
FCMRepositoryImpl(
this._fcmDatasource,
this._threadDataSource
);
@override
Future<FCMTokenDto> getFCMToken(String accountId) {
@@ -24,4 +35,57 @@ class FCMRepositoryImpl extends FCMRepository {
Future<void> deleteFCMToken(String accountId) {
return _fcmDatasource.deleteFCMToken(accountId);
}
@override
Future<EmailsResponse> getEmailChangesToPushNotification(
AccountId accountId,
jmap.State currentState,
{
Properties? propertiesCreated,
Properties? propertiesUpdated
}
) async {
EmailChangeResponse? emailChangeResponse;
bool hasMoreChanges = true;
jmap.State? sinceState = currentState;
while (hasMoreChanges && sinceState != null) {
final changesResponse = await _threadDataSource.getChanges(
accountId,
sinceState,
propertiesCreated: propertiesCreated,
propertiesUpdated: propertiesUpdated
);
hasMoreChanges = changesResponse.hasMoreChanges;
sinceState = changesResponse.newStateChanges;
if (emailChangeResponse != null) {
emailChangeResponse.union(changesResponse);
} else {
emailChangeResponse = changesResponse;
}
}
if (emailChangeResponse != null) {
return EmailsResponse(emailList: emailChangeResponse.created ?? []);
} else {
return EmailsResponse();
}
}
@override
Future<bool> storeStateToRefresh(TypeName typeName, jmap.State newState) {
return _fcmDatasource.storeStateToRefresh(typeName, newState);
}
@override
Future<jmap.State> getStateToRefresh(TypeName typeName) {
return _fcmDatasource.getStateToRefresh(typeName);
}
@override
Future<bool> deleteStateToRefresh(TypeName typeName) {
return _fcmDatasource.deleteStateToRefresh(typeName);
}
}
@@ -2,4 +2,6 @@ class NotFoundStoredFCMException implements Exception {}
class NotSupportFCMException implements Exception {}
class NotFoundStateToRefreshException implements Exception {}
class NotFoundEmailDeliveryStateException implements Exception {}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class DeleteEmailStateToRefreshLoading extends UIState {}
class DeleteEmailStateToRefreshSuccess extends UIState {
DeleteEmailStateToRefreshSuccess();
@override
List<Object> get props => [];
}
class DeleteEmailStateToRefreshFailure extends FeatureFailure {
final dynamic exception;
DeleteEmailStateToRefreshFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:model/email/presentation_email.dart';
class GetEmailChangesToPushNotificationLoading extends UIState {}
class GetEmailChangesToPushNotificationSuccess extends UIState {
final List<PresentationEmail> emailList;
GetEmailChangesToPushNotificationSuccess(this.emailList);
@override
List<Object> get props => [emailList];
}
class GetEmailChangesToPushNotificationFailure extends FeatureFailure {
final dynamic exception;
GetEmailChangesToPushNotificationFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class GetEmailStateToRefreshLoading extends UIState {}
class GetEmailStateToRefreshSuccess extends UIState {
final jmap.State storedState;
GetEmailStateToRefreshSuccess(this.storedState);
@override
List<Object> get props => [storedState];
}
class GetEmailStateToRefreshFailure extends FeatureFailure {
final dynamic exception;
GetEmailStateToRefreshFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class GetStoredEmailDeliveryStateLoading extends UIState {}
class GetStoredEmailDeliveryStateSuccess extends UIState {
final jmap.State state;
GetStoredEmailDeliveryStateSuccess(this.state);
@override
List<Object> get props => [state];
}
class GetStoredEmailDeliveryStateFailure extends FeatureFailure {
final dynamic exception;
GetStoredEmailDeliveryStateFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class StoreEmailDeliveryStateLoading extends UIState {}
class StoreEmailDeliveryStateSuccess extends UIState {
StoreEmailDeliveryStateSuccess();
@override
List<Object> get props => [];
}
class StoreEmailDeliveryStateFailure extends FeatureFailure {
final dynamic exception;
StoreEmailDeliveryStateFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class StoreEmailStateToRefreshLoading extends UIState {}
class StoreEmailStateToRefreshSuccess extends UIState {
StoreEmailStateToRefreshSuccess();
@override
List<Object> get props => [];
}
class StoreEmailStateToRefreshFailure extends FeatureFailure {
final dynamic exception;
StoreEmailStateToRefreshFailure(this.exception);
@override
List<Object> get props => [exception];
}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/delete_email_state_to_refresh_state.dart';
class DeleteEmailStateToRefreshInteractor {
final FCMRepository _fcmRepository;
DeleteEmailStateToRefreshInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(TypeName typeName) async* {
try {
yield Right<Failure, Success>(DeleteEmailStateToRefreshLoading());
await _fcmRepository.deleteStateToRefresh(typeName);
yield Right<Failure, Success>(DeleteEmailStateToRefreshSuccess());
} catch (e) {
yield Left<Failure, Success>(DeleteEmailStateToRefreshFailure(e));
}
}
}
@@ -0,0 +1,42 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.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:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/extensions/email_extension.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_email_changes_state.dart';
class GetEmailChangesToPushNotificationInteractor {
final FCMRepository _fcmRepository;
GetEmailChangesToPushNotificationInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(
AccountId accountId,
jmap.State currentState,
{
Properties? propertiesCreated,
Properties? propertiesUpdated
}
) async* {
try {
yield Right<Failure, Success>(GetEmailChangesToPushNotificationLoading());
final emailsResponse = await _fcmRepository.getEmailChangesToPushNotification(
accountId,
currentState,
propertiesCreated: propertiesCreated,
propertiesUpdated: propertiesUpdated);
final presentationEmailList = emailsResponse.emailList
?.map((email) => email.toPresentationEmail())
.toList() ?? List.empty();
yield Right<Failure, Success>(GetEmailChangesToPushNotificationSuccess(presentationEmailList));
} catch (e) {
yield Left<Failure, Success>(GetEmailChangesToPushNotificationFailure(e));
}
}
}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_email_state_to_refresh_state.dart';
class GetEmailStateToRefreshInteractor {
final FCMRepository _fcmRepository;
GetEmailStateToRefreshInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(GetEmailStateToRefreshLoading());
final storedState = await _fcmRepository.getStateToRefresh(TypeName.emailType);
yield Right<Failure, Success>(GetEmailStateToRefreshSuccess(storedState));
} catch (e) {
yield Left<Failure, Success>(GetEmailStateToRefreshFailure(e));
}
}
}
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_stored_email_delivery_state.dart';
class GetStoredEmailDeliveryStateInteractor {
final FCMRepository _fcmRepository;
GetStoredEmailDeliveryStateInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(GetStoredEmailDeliveryStateLoading());
final storedState = await _fcmRepository.getStateToRefresh(TypeName.emailDelivery);
yield Right<Failure, Success>(GetStoredEmailDeliveryStateSuccess(storedState));
} catch (e) {
yield Left<Failure, Success>(GetStoredEmailDeliveryStateFailure(e));
}
}
}
@@ -0,0 +1,23 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/store_email_delivery_state.dart';
class StoreEmailDeliveryStateInteractor {
final FCMRepository _fcmRepository;
StoreEmailDeliveryStateInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(jmap.State newState) async* {
try {
yield Right<Failure, Success>(StoreEmailDeliveryStateLoading());
await _fcmRepository.storeStateToRefresh(TypeName.emailDelivery, newState);
yield Right<Failure, Success>(StoreEmailDeliveryStateSuccess());
} catch (e) {
yield Left<Failure, Success>(StoreEmailDeliveryStateFailure(e));
}
}
}
@@ -0,0 +1,23 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/store_fcm_state_change_state.dart';
class StoreEmailStateToRefreshInteractor {
final FCMRepository _fcmRepository;
StoreEmailStateToRefreshInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(TypeName typeName, jmap.State newState) async* {
try {
yield Right<Failure, Success>(StoreEmailStateToRefreshLoading());
await _fcmRepository.storeStateToRefresh(typeName, newState);
yield Right<Failure, Success>(StoreEmailStateToRefreshSuccess());
} catch (e) {
yield Left<Failure, Success>(StoreEmailStateToRefreshFailure(e));
}
}
}