diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 000000000..52e600326 --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + example + REVERSED_CLIENT_ID + example + API_KEY + example + GCM_SENDER_ID + example + PLIST_VERSION + 1 + BUNDLE_ID + com.linagora.ios.teammail + PROJECT_ID + example + STORAGE_BUCKET + example + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + example + DATABASE_URL + example + + \ No newline at end of file diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index 07be00a38..3d8ffef27 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -1,6 +1,8 @@ import 'package:contact/contact/model/capability_contact.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:forward/forward/capability_forward.dart'; @@ -17,6 +19,10 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/c import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/tmail_autocomplete_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forwarding_interactors_bindings.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/model/capability_push_notification.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/firebase_bindings.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/firebase_options.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/notification_service.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -119,7 +125,7 @@ abstract class BaseController extends GetxController requireCapability(session!, accountId!, [CapabilityIdentifier.jmapMdn]); MdnInteractorBindings().dependencies(); } catch(e) { - logError('BaseController::injectMdnBindings(): exception: $e'); + logError('BaseController::injectVacationBindings(): exception: $e'); } } @@ -140,4 +146,15 @@ abstract class BaseController extends GetxController logError('BaseController::injectRuleFilterBindings(): exception: $e'); } } + + Future injectFirebaseBindings(Session? session, AccountId? accountId) async { + try { + requireCapability(session!, accountId!, [capabilityPushNotification]); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); + FireBaseBindings().dependencies(); + } catch(e) { + logError('BaseController::injectFirebaseBindings(): exception: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/caching/config/hive_cache_config.dart b/lib/features/caching/config/hive_cache_config.dart index ee2b6fe04..963101416 100644 --- a/lib/features/caching/config/hive_cache_config.dart +++ b/lib/features/caching/config/hive_cache_config.dart @@ -18,6 +18,7 @@ import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.d 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_dashboard/data/model/recent_search_cache.dart'; +import 'package:tmail_ui_user/features/push_notification/data/model/firebase_cache.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_address_hive_cache.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; @@ -78,6 +79,7 @@ class HiveCacheConfig { Hive.registerAdapter(AuthenticationInfoCacheAdapter()); Hive.registerAdapter(RecentLoginUrlCacheAdapter()); Hive.registerAdapter(RecentLoginUsernameCacheAdapter()); + Hive.registerAdapter(FirebaseCacheAdapter()); } Future closeHive() async { diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 9e81282e3..19cf902c9 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -14,6 +14,7 @@ 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:jmap_dart_client/jmap/mail/vacation/vacation_response.dart'; +import 'package:model/firebase/firebase_dto.dart'; import 'package:model/model.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; @@ -64,6 +65,8 @@ import 'package:tmail_ui_user/features/manage_account/presentation/extensions/va import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; import 'package:tmail_ui_user/features/network_status_handle/presentation/network_connnection_controller.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/usecases/save_firebase_cache_interactor.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/notification_service.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart'; @@ -108,6 +111,7 @@ class MailboxDashBoardController extends ReloadableController { GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; + SaveFirebaseCacheInteractor? _saveFirebaseCacheInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -333,6 +337,7 @@ class MailboxDashBoardController extends ReloadableController { injectAutoCompleteBindings(sessionCurrent, accountId.value); injectRuleFilterBindings(sessionCurrent, accountId.value); injectVacationBindings(sessionCurrent, accountId.value); + injectFirebaseBindings(sessionCurrent, accountId.value); _getVacationResponse(); } else { reload(); @@ -350,6 +355,22 @@ class MailboxDashBoardController extends ReloadableController { } } + @override + Future injectFirebaseBindings(Session? session, AccountId? accountId) async { + try { + await super.injectFirebaseBindings(session, accountId); + _saveFirebaseCacheInteractor = Get.find(); + NotificationService.initializeNotificationService( + onDidReceiveNotificationResponse); + NotificationService.onTokenRefresh.listen((token) { + _saveFirebaseCacheInteractor?.execute(FirebaseDto(token)); + }); + } catch (e) { + logError('MailboxDashBoardController::injectVacationBindings(): $e'); + } + } + + Future _getAppVersion() async { final info = await PackageInfo.fromPlatform(); log('MailboxDashBoardController::_getAppVersion(): ${info.version}'); diff --git a/lib/features/push_notification/domain/model/capability_push_notification.dart b/lib/features/push_notification/domain/model/capability_push_notification.dart new file mode 100644 index 000000000..d523110cc --- /dev/null +++ b/lib/features/push_notification/domain/model/capability_push_notification.dart @@ -0,0 +1,3 @@ +import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; + +final capabilityPushNotification = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:firebase:push')); \ No newline at end of file diff --git a/lib/features/push_notification/presentation/firebase_options.dart b/lib/features/push_notification/presentation/firebase_options.dart new file mode 100644 index 000000000..ed326fe69 --- /dev/null +++ b/lib/features/push_notification/presentation/firebase_options.dart @@ -0,0 +1,69 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static FirebaseOptions web = FirebaseOptions( + apiKey: dotenv.get('FIREBASE_WEB_API_KEY', fallback: ''), + appId: dotenv.get('FIREBASE_WEB_APP_ID', fallback: ''), + messagingSenderId: dotenv.get('FIREBASE_WEB_MESSAGING_SENDER_ID', fallback: ''), + projectId: dotenv.get('FIREBASE_WEB_PROJECT_ID', fallback: ''), + authDomain: dotenv.get('FIREBASE_WEB_AUTH_DOMAIN', fallback: ''), + databaseURL: dotenv.get('FIREBASE_WEB_DATABASE_URL', fallback: ''), + storageBucket: dotenv.get('FIREBASE_WEB_STORAGE_BUCKET', fallback: ''), + ); + + static FirebaseOptions android = FirebaseOptions( + apiKey: dotenv.get('FIREBASE_ANDROID_API_KEY', fallback: ''), + appId: dotenv.get('FIREBASE_ANDROID_APP_ID', fallback: ''), + messagingSenderId: dotenv.get('FIREBASE_ANDROID_MESSAGING_SENDER_ID', fallback: ''), + projectId: dotenv.get('FIREBASE_ANDROID_PROJECT_ID', fallback: ''), + databaseURL: dotenv.get('FIREBASE_ANDROID_DATABASE_URL', fallback: ''), + storageBucket: dotenv.get('FIREBASE_ANDROID_STORAGE_BUCKET', fallback: ''), + ); + + static FirebaseOptions ios = FirebaseOptions( + apiKey: dotenv.get('FIREBASE_IOS_API_KEY', fallback: ''), + appId: dotenv.get('FIREBASE_IOS_APP_ID', fallback: ''), + messagingSenderId: dotenv.get('FIREBASE_IOS_MESSAGING_SENDER_ID', fallback: ''), + projectId: dotenv.get('FIREBASE_IOS_PROJECT_ID', fallback: ''), + databaseURL: dotenv.get('FIREBASE_IOS_DATABASE_URL', fallback: ''), + storageBucket: dotenv.get('FIREBASE_IOS_STORAGE_BUCKET', fallback: ''), + iosClientId: dotenv.get('FIREBASE_IOS_CLIENT_ID', fallback: ''), + iosBundleId: dotenv.get('FIREBASE_IOS_BUNDLE_ID', fallback: ''), + ); +} diff --git a/lib/features/push_notification/presentation/notification_service.dart b/lib/features/push_notification/presentation/notification_service.dart index c7696df13..84e814234 100644 --- a/lib/features/push_notification/presentation/notification_service.dart +++ b/lib/features/push_notification/presentation/notification_service.dart @@ -4,12 +4,12 @@ import 'dart:io'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; import 'package:model/firebase/firebase_dto.dart'; -import 'package:rxdart/rxdart.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/save_firebase_cache_interactor.dart'; -import 'package:tmail_ui_user/firebase_options.dart'; +import 'package:tmail_ui_user/features/push_notification/presentation/firebase_options.dart'; import 'notification_strings.dart'; final StreamController selectNotificationStream = @@ -17,6 +17,7 @@ StreamController.broadcast(); @pragma('vm:entry-point') Future firebaseMessagingBackgroundHandler(RemoteMessage message) async { + await dotenv.load(fileName: 'env.file'); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await NotificationService.displayPushNotification(message); } @@ -44,13 +45,6 @@ class NotificationService { static get _flutterLocalNotificationsPlugin => FlutterLocalNotificationsPlugin(); - static final BehaviorSubject - _notificationActionStream = - BehaviorSubject.seeded(null); - - static Stream get notificationActionStream => - _notificationActionStream.stream; - static Stream get onTokenRefresh => _firebaseMessaging.onTokenRefresh; static bool _isFlutterLocalNotificationsInitialized = false; @@ -130,7 +124,6 @@ class NotificationService { selectNotificationStream.stream .listen((event) => event) .onData((data) async { - _notificationActionStream.add(data); switch (data?.notificationResponseType) { case NotificationResponseType.selectedNotification: break; diff --git a/lib/features/session/presentation/session_controller.dart b/lib/features/session/presentation/session_controller.dart index e8663eba4..a5d295aa3 100644 --- a/lib/features/session/presentation/session_controller.dart +++ b/lib/features/session/presentation/session_controller.dart @@ -3,7 +3,6 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/utils/app_toast.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:model/firebase/firebase_dto.dart'; import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart'; @@ -12,8 +11,6 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oi import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; -import 'package:tmail_ui_user/features/push_notification/domain/usecases/save_firebase_cache_interactor.dart'; -import 'package:tmail_ui_user/features/push_notification/presentation/notification_service.dart'; import 'package:tmail_ui_user/features/session/domain/state/get_session_state.dart'; import 'package:tmail_ui_user/features/session/domain/usecases/get_session_interactor.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception.dart'; @@ -29,7 +26,6 @@ class SessionController extends ReloadableController { final CachingManager _cachingManager; final DeleteAuthorityOidcInteractor _deleteAuthorityOidcInteractor; final AuthorizationInterceptors _authorizationInterceptors; - final SaveFirebaseCacheInteractor _saveFirebaseCacheInteractor; final AppToast _appToast; final DynamicUrlInterceptors _dynamicUrlInterceptors; @@ -44,19 +40,13 @@ class SessionController extends ReloadableController { this._authorizationInterceptors, this._appToast, this._dynamicUrlInterceptors, - this._saveFirebaseCacheInteractor, ) : super(logoutOidcInteractor, deleteAuthorityOidcInteractor, getAuthenticatedAccountInteractor); @override - Future onReady() async { + void onReady() { super.onReady(); - NotificationService.initializeNotificationService( - onDidReceiveNotificationResponse); - NotificationService.onTokenRefresh.listen((token) { - _saveFirebaseCacheInteractor.execute(FirebaseDto(token)); - }); final arguments = Get.arguments; if (arguments != null && arguments is String) { _getSession(); diff --git a/lib/features/session/presentation/session_page_bindings.dart b/lib/features/session/presentation/session_page_bindings.dart index 1c0ea2b3f..7b58cbea5 100644 --- a/lib/features/session/presentation/session_page_bindings.dart +++ b/lib/features/session/presentation/session_page_bindings.dart @@ -24,7 +24,6 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_a import 'package:tmail_ui_user/features/login/domain/usecases/get_credential_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_stored_token_oidc_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; -import 'package:tmail_ui_user/features/push_notification/domain/usecases/save_firebase_cache_interactor.dart'; import 'package:tmail_ui_user/features/session/domain/usecases/get_session_interactor.dart'; import 'package:tmail_ui_user/features/session/presentation/session_controller.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; @@ -45,7 +44,6 @@ class SessionPageBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), )); } diff --git a/lib/main.dart b/lib/main.dart index dc3c97057..6eeb9b775 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,10 @@ import 'package:core/core.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; -import 'package:tmail_ui_user/features/push_notification/presentation/notification_service.dart'; -import 'package:tmail_ui_user/firebase_options.dart'; import 'package:tmail_ui_user/main/bindings/main_bindings.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations_delegate.dart'; @@ -26,13 +22,6 @@ void main() async { statusBarColor: Colors.black, statusBarIconBrightness: Brightness.light, )); - - try { - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); - } on FirebaseException catch (e) { - debugPrint(e.toString()); - } await MainBindings().dependencies(); await HiveCacheConfig().setUp(); await HiveCacheConfig.initializeEncryptionKey(); diff --git a/lib/main/bindings/main_bindings.dart b/lib/main/bindings/main_bindings.dart index 57f768c94..2035dc015 100644 --- a/lib/main/bindings/main_bindings.dart +++ b/lib/main/bindings/main_bindings.dart @@ -1,5 +1,4 @@ import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/push_notification/presentation/firebase_bindings.dart'; import 'package:tmail_ui_user/main/bindings/core/core_bindings.dart'; import 'package:tmail_ui_user/main/bindings/credential/credential_bindings.dart'; import 'package:tmail_ui_user/main/bindings/local/local_bindings.dart'; @@ -18,6 +17,5 @@ class MainBindings extends Bindings { CredentialBindings().dependencies(); NetWorkConnectionBindings().dependencies(); SessionBindings().dependencies(); - FireBaseBindings().dependencies(); } } \ No newline at end of file