diff --git a/lib/features/push_notification/presentation/utils/fcm_utils.dart b/lib/features/push_notification/presentation/utils/fcm_utils.dart new file mode 100644 index 000000000..ecdf47622 --- /dev/null +++ b/lib/features/push_notification/presentation/utils/fcm_utils.dart @@ -0,0 +1,76 @@ + +import 'package:core/utils/app_logger.dart'; +import 'package:dartz/dartz.dart'; +import 'package:fcm/model/type_name.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/push/state_change.dart'; +import 'package:jmap_dart_client/jmap/push/type_state.dart'; + +class FcmUtils { + FcmUtils._internal(); + + static final FcmUtils _instance = FcmUtils._internal(); + + static FcmUtils get instance => _instance; + + StateChange? convertFirebaseDataMessageToStateChange(Map dataMessage) { + log('FcmUtils::convertFirebaseDataMessageToStateChange():dataMessage: $dataMessage'); + Map mapData; + if (dataMessage.containsKey('data')) { + mapData = dataMessage['data']; + } else { + mapData = dataMessage; + } + + final listKeys = mapData.keys; + Map mapTypeStateChanged = {}; + + for (var key in listKeys) { + final tupleKey = _parseFromKeyFirebaseDataMessage(key); + final accountId = tupleKey.value1; + final typeName = tupleKey.value2; + final value = mapData[key]; + + if (accountId == null || typeName == null || isEmpty(value)) { + log('FcmUtils::convertFirebaseDataMessageToStateChange(): key or value is null'); + continue; + } + + if (mapTypeStateChanged.containsKey(accountId)) { + mapTypeStateChanged[accountId]!.typeState[typeName.value] = value; + } else { + mapTypeStateChanged[accountId] = TypeState({typeName.value: value}); + } + } + + if (mapTypeStateChanged.isEmpty) { + return null; + } else { + return StateChange('StateChange', mapTypeStateChanged); + } + } + + Tuple2 _parseFromKeyFirebaseDataMessage(String key) { + if (_keyFirebaseDataMessageIsValid(key)) { + final listObject = key.split(':'); + final accountId = AccountId(Id(listObject.first)); + final typeName = TypeName(listObject.last); + return Tuple2(accountId, typeName); + } else { + return const Tuple2(null, null); + } + } + + bool _keyFirebaseDataMessageIsValid(String key) { + if (key.contains(':')) { + return key.split(':').length == 2; + } else { + return false; + } + } + + bool isEmpty(dynamic object) { + return object == null || (object is String && object.isEmpty); + } +} \ No newline at end of file diff --git a/test/features/fcm/fcm_utils_test.dart b/test/features/fcm/fcm_utils_test.dart new file mode 100644 index 000000000..902161942 --- /dev/null +++ b/test/features/fcm/fcm_utils_test.dart @@ -0,0 +1,95 @@ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/push/state_change.dart'; +import 'package:jmap_dart_client/jmap/push/type_state.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart'; + +void main() { + + final expectStateChange1 = StateChange( + 'StateChange', + { + AccountId(Id('a3123')): TypeState({ + 'Email': 'd35ecb040aab', + 'EmailDelivery': '428d565f2440', + 'CalendarEvent': '87accfac587a' + }), + AccountId(Id('a43461d')): TypeState({ + 'Mailbox': '0af7a512ce70', + 'CalendarEvent': '7a4297cecd76' + }) + } + ); + + final expectStateChange2 = StateChange( + 'StateChange', + { + AccountId(Id('a3123')): TypeState({ + 'EmailDelivery': '428d565f2440', + 'CalendarEvent': '87accfac587a' + }), + AccountId(Id('a43461d')): TypeState({ + 'Mailbox': '0af7a512ce70', + 'CalendarEvent': '7a4297cecd76' + }) + } + ); + + group('decodeFirebaseDataMessageToStateChange test', () { + test('should return StateChange when parse from firebase data message with key/value is not empty', () { + + final dataMessage = { + "data": { + "a3123:Email": "d35ecb040aab", + "a3123:EmailDelivery": "428d565f2440", + "a3123:CalendarEvent": "87accfac587a", + "a43461d:Mailbox": "0af7a512ce70", + "a43461d:CalendarEvent": "7a4297cecd76" + }, + "token": "fcm-client-token" + }; + + final stateChange = FcmUtils.instance.convertFirebaseDataMessageToStateChange(dataMessage); + + expect(stateChange, equals(expectStateChange1)); + }); + + test('should return StateChange when parse from firebase data message with value is empty', () { + + final dataMessage = { + "data": { + "a3123:Email": "", + "a3123:EmailDelivery": "428d565f2440", + "a3123:CalendarEvent": "87accfac587a", + "a43461d:Mailbox": "0af7a512ce70", + "a43461d:CalendarEvent": "7a4297cecd76" + }, + "token": "fcm-client-token" + }; + + final stateChange = FcmUtils.instance.convertFirebaseDataMessageToStateChange(dataMessage); + + expect(stateChange, equals(expectStateChange2)); + }); + + test('should return StateChange when parse from firebase data message with key is empty', () { + + final dataMessage = { + "data": { + "": "d35ecb040aab", + "a3123:EmailDelivery": "428d565f2440", + "a3123:CalendarEvent": "87accfac587a", + "a43461d:Mailbox": "0af7a512ce70", + "a43461d:CalendarEvent": "7a4297cecd76" + }, + "token": "fcm-client-token" + }; + + final stateChange = FcmUtils.instance.convertFirebaseDataMessageToStateChange(dataMessage); + + expect(stateChange, equals(expectStateChange2)); + }); + }); +} \ No newline at end of file