diff --git a/analysis_options.yaml b/analysis_options.yaml index 1d331a6..a69a437 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -14,6 +14,7 @@ analyzer: invalid_annotation_target: ignore use_build_context_synchronously: ignore deprecated_member_use: ignore + depend_on_referenced_packages: ignore exclude: - test/generated/** - "**/**.g.dart" diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index fd02140..a9884f6 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.apskel.apskel_owner" + namespace = "com.apskel.enaklo_owner" compileSdk = flutter.compileSdkVersion ndkVersion = "27.0.12077973" @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.apskel.apskel_owner" + applicationId = "com.apskel.enaklo_owner" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..4ba90e6 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,48 @@ +{ + "project_info": { + "project_number": "765730035527", + "project_id": "apskel-pos-v2", + "storage_bucket": "apskel-pos-v2.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:765730035527:android:beffb797b781e715241e62", + "android_client_info": { + "package_name": "com.apskel.enaklo_owner" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAOZwVSQwUeeM9BjcyTOK9GUh8AmTWucuc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:765730035527:android:498defd7071336dd241e62", + "android_client_info": { + "package_name": "com.apskel.pos" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAOZwVSQwUeeM9BjcyTOK9GUh8AmTWucuc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0a0b209..7a2c596 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,9 +5,11 @@ + + + + + + + + + UIBackgroundModes + + fetch + remote-notification + diff --git a/lib/common/di/di_firebase.dart b/lib/common/di/di_firebase.dart new file mode 100644 index 0000000..8ab3f0d --- /dev/null +++ b/lib/common/di/di_firebase.dart @@ -0,0 +1,8 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'package:injectable/injectable.dart'; + +@module +abstract class FirebaseDi { + @preResolve + Future get firebaseApp => Firebase.initializeApp(); +} diff --git a/lib/common/utils/fcm_service.dart b/lib/common/utils/fcm_service.dart new file mode 100644 index 0000000..2a1a17e --- /dev/null +++ b/lib/common/utils/fcm_service.dart @@ -0,0 +1,150 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:injectable/injectable.dart'; + +/// Background message handler — must be a top-level function. +@pragma('vm:entry-point') +Future firebaseMessagingBackgroundHandler(RemoteMessage message) async { + debugPrint('[FCM] Background message: ${message.messageId}'); +} + +@lazySingleton +class FcmService { + final FirebaseMessaging _messaging = FirebaseMessaging.instance; + + final FlutterLocalNotificationsPlugin _localNotifications = + FlutterLocalNotificationsPlugin(); + + static const _androidChannel = AndroidNotificationChannel( + 'high_importance_channel', + 'High Importance Notifications', + description: 'This channel is used for important notifications.', + importance: Importance.high, + ); + + /// Call this once during app startup (after Firebase.initializeApp). + Future initialize({ + void Function(RemoteMessage message)? onMessageTap, + }) async { + // 1. Request permission (iOS + Android 13+) + await _requestPermission(); + + // 2. Setup local notifications (needed to show heads-up on Android) + await _setupLocalNotifications(); + + // 3. Register background handler + FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); + + // 4. Foreground message handler + FirebaseMessaging.onMessage.listen((message) { + debugPrint('[FCM] Foreground message: ${message.messageId}'); + _showLocalNotification(message); + }); + + // 5. App opened from notification (background → foreground) + FirebaseMessaging.onMessageOpenedApp.listen((message) { + debugPrint('[FCM] Notification tapped (background): ${message.messageId}'); + onMessageTap?.call(message); + }); + + // 6. App launched from terminated state via notification + final initialMessage = await _messaging.getInitialMessage(); + if (initialMessage != null) { + debugPrint('[FCM] App launched from notification: ${initialMessage.messageId}'); + onMessageTap?.call(initialMessage); + } + + // 7. Print FCM token for debugging + final token = await getToken(); + debugPrint('[FCM] Token: $token'); + } + + Future _requestPermission() async { + final settings = await _messaging.requestPermission( + alert: true, + badge: true, + sound: true, + ); + debugPrint('[FCM] Permission status: ${settings.authorizationStatus}'); + } + + Future _setupLocalNotifications() async { + // Android init + const androidInit = AndroidInitializationSettings('@mipmap/launcher_icon'); + + // iOS init + const iosInit = DarwinInitializationSettings( + requestAlertPermission: false, + requestBadgePermission: false, + requestSoundPermission: false, + ); + + const initSettings = InitializationSettings( + android: androidInit, + iOS: iosInit, + ); + + await _localNotifications.initialize( + initSettings, + onDidReceiveNotificationResponse: (details) { + debugPrint('[FCM] Local notification tapped: ${details.payload}'); + }, + ); + + // Create Android notification channel + if (Platform.isAndroid) { + await _localNotifications + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(_androidChannel); + } + + // iOS: show notification even when app is in foreground + await _messaging.setForegroundNotificationPresentationOptions( + alert: true, + badge: true, + sound: true, + ); + } + + void _showLocalNotification(RemoteMessage message) { + final notification = message.notification; + if (notification == null) return; + + _localNotifications.show( + notification.hashCode, + notification.title, + notification.body, + NotificationDetails( + android: AndroidNotificationDetails( + _androidChannel.id, + _androidChannel.name, + channelDescription: _androidChannel.description, + icon: '@mipmap/launcher_icon', + importance: Importance.high, + priority: Priority.high, + ), + iOS: const DarwinNotificationDetails(), + ), + payload: jsonEncode(message.data), + ); + } + + /// Returns the FCM registration token for this device. + Future getToken() => _messaging.getToken(); + + /// Subscribe to a topic (e.g. 'all', 'promo'). + Future subscribeToTopic(String topic) => + _messaging.subscribeToTopic(topic); + + /// Unsubscribe from a topic. + Future unsubscribeFromTopic(String topic) => + _messaging.unsubscribeFromTopic(topic); + + /// Listen for token refresh. + Stream get onTokenRefresh => _messaging.onTokenRefresh; +} diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 046ae07..40b1d03 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -53,11 +53,13 @@ import 'package:apskel_owner_flutter/common/api/api_client.dart' as _i115; import 'package:apskel_owner_flutter/common/di/di_auto_route.dart' as _i311; import 'package:apskel_owner_flutter/common/di/di_connectivity.dart' as _i586; import 'package:apskel_owner_flutter/common/di/di_dio.dart' as _i103; +import 'package:apskel_owner_flutter/common/di/di_firebase.dart' as _i73; import 'package:apskel_owner_flutter/common/di/di_package_info.dart' as _i227; import 'package:apskel_owner_flutter/common/di/di_shared_preferences.dart' as _i402; import 'package:apskel_owner_flutter/common/network/network_client.dart' as _i543; +import 'package:apskel_owner_flutter/common/utils/fcm_service.dart' as _i179; import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_repository.dart' as _i477; import 'package:apskel_owner_flutter/domain/auth/auth.dart' as _i49; @@ -106,6 +108,7 @@ import 'package:apskel_owner_flutter/presentation/router/app_router.dart' as _i258; import 'package:connectivity_plus/connectivity_plus.dart' as _i895; import 'package:dio/dio.dart' as _i361; +import 'package:firebase_core/firebase_core.dart' as _i982; import 'package:get_it/get_it.dart' as _i174; import 'package:injectable/injectable.dart' as _i526; import 'package:package_info_plus/package_info_plus.dart' as _i655; @@ -121,22 +124,28 @@ extension GetItInjectableX on _i174.GetIt { _i526.EnvironmentFilter? environmentFilter, }) async { final gh = _i526.GetItHelper(this, environment, environmentFilter); + final firebaseDi = _$FirebaseDi(); final sharedPreferencesDi = _$SharedPreferencesDi(); - final dioDi = _$DioDi(); final autoRouteDi = _$AutoRouteDi(); final connectivityDi = _$ConnectivityDi(); + final dioDi = _$DioDi(); final packageInfoDi = _$PackageInfoDi(); + await gh.factoryAsync<_i982.FirebaseApp>( + () => firebaseDi.firebaseApp, + preResolve: true, + ); await gh.factoryAsync<_i460.SharedPreferences>( () => sharedPreferencesDi.prefs, preResolve: true, ); - gh.lazySingleton<_i361.Dio>(() => dioDi.dio); gh.lazySingleton<_i258.AppRouter>(() => autoRouteDi.appRouter); gh.lazySingleton<_i895.Connectivity>(() => connectivityDi.connectivity); + gh.lazySingleton<_i361.Dio>(() => dioDi.dio); await gh.lazySingletonAsync<_i655.PackageInfo>( () => packageInfoDi.packageInfo, preResolve: true, ); + gh.lazySingleton<_i179.FcmService>(() => _i179.FcmService()); gh.lazySingleton<_i543.NetworkClient>( () => _i543.NetworkClient(gh<_i895.Connectivity>()), ); @@ -151,29 +160,29 @@ extension GetItInjectableX on _i174.GetIt { () => _i115.ApiClient(gh<_i361.Dio>(), gh<_i6.Env>()), ); gh.factory<_i6.Env>(() => _i6.ProdEnv(), registerFor: {_prod}); - gh.factory<_i130.OrderRemoteDataProvider>( - () => _i130.OrderRemoteDataProvider(gh<_i115.ApiClient>()), - ); - gh.factory<_i333.CategoryRemoteDataProvider>( - () => _i333.CategoryRemoteDataProvider(gh<_i115.ApiClient>()), + gh.factory<_i866.AnalyticRemoteDataProvider>( + () => _i866.AnalyticRemoteDataProvider(gh<_i115.ApiClient>()), ); gh.factory<_i17.AuthRemoteDataProvider>( () => _i17.AuthRemoteDataProvider(gh<_i115.ApiClient>()), ); - gh.factory<_i785.UserRemoteDataProvider>( - () => _i785.UserRemoteDataProvider(gh<_i115.ApiClient>()), + gh.factory<_i333.CategoryRemoteDataProvider>( + () => _i333.CategoryRemoteDataProvider(gh<_i115.ApiClient>()), ); - gh.factory<_i823.ProductRemoteDataProvider>( - () => _i823.ProductRemoteDataProvider(gh<_i115.ApiClient>()), + gh.factory<_i1006.CustomerRemoteDataProvider>( + () => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()), + ); + gh.factory<_i130.OrderRemoteDataProvider>( + () => _i130.OrderRemoteDataProvider(gh<_i115.ApiClient>()), ); gh.factory<_i27.OutletRemoteDataProvider>( () => _i27.OutletRemoteDataProvider(gh<_i115.ApiClient>()), ); - gh.factory<_i866.AnalyticRemoteDataProvider>( - () => _i866.AnalyticRemoteDataProvider(gh<_i115.ApiClient>()), + gh.factory<_i823.ProductRemoteDataProvider>( + () => _i823.ProductRemoteDataProvider(gh<_i115.ApiClient>()), ); - gh.factory<_i1006.CustomerRemoteDataProvider>( - () => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()), + gh.factory<_i785.UserRemoteDataProvider>( + () => _i785.UserRemoteDataProvider(gh<_i115.ApiClient>()), ); gh.factory<_i48.ICustomerRepository>( () => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()), @@ -220,17 +229,20 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i183.CategoryLoaderBloc>( () => _i183.CategoryLoaderBloc(gh<_i1020.ICategoryRepository>()), ); - gh.factory<_i473.HomeBloc>( - () => _i473.HomeBloc(gh<_i477.IAnalyticRepository>()), - ); gh.factory<_i889.SalesLoaderBloc>( () => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()), ); + gh.factory<_i473.HomeBloc>( + () => _i473.HomeBloc(gh<_i477.IAnalyticRepository>()), + ); gh.factory<_i337.CurrentOutletLoaderBloc>( () => _i337.CurrentOutletLoaderBloc(gh<_i197.IOutletRepository>()), ); - gh.factory<_i221.ProductAnalyticLoaderBloc>( - () => _i221.ProductAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), + gh.factory<_i1038.CategoryAnalyticLoaderBloc>( + () => _i1038.CategoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), + ); + gh.factory<_i516.DashboardAnalyticLoaderBloc>( + () => _i516.DashboardAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), ); gh.factory<_i785.InventoryAnalyticLoaderBloc>( () => _i785.InventoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), @@ -240,41 +252,38 @@ extension GetItInjectableX on _i174.GetIt { gh<_i477.IAnalyticRepository>(), ), ); - gh.factory<_i1038.CategoryAnalyticLoaderBloc>( - () => _i1038.CategoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), + gh.factory<_i221.ProductAnalyticLoaderBloc>( + () => _i221.ProductAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), ); gh.factory<_i11.ProfitLossLoaderBloc>( () => _i11.ProfitLossLoaderBloc(gh<_i477.IAnalyticRepository>()), ); - gh.factory<_i516.DashboardAnalyticLoaderBloc>( - () => _i516.DashboardAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), + gh.factory<_i945.AuthBloc>( + () => _i945.AuthBloc(gh<_i49.IAuthRepository>()), ); gh.factory<_i775.LoginFormBloc>( () => _i775.LoginFormBloc(gh<_i49.IAuthRepository>()), ); - gh.factory<_i945.AuthBloc>( - () => _i945.AuthBloc(gh<_i49.IAuthRepository>()), - ); gh.factory<_i574.LogoutFormBloc>( () => _i574.LogoutFormBloc(gh<_i49.IAuthRepository>()), ); gh.factory<_i1058.OrderLoaderBloc>( () => _i1058.OrderLoaderBloc(gh<_i219.IOrderRepository>()), ); - gh.factory<_i147.UserEditFormBloc>( - () => _i147.UserEditFormBloc(gh<_i635.IUserRepository>()), - ); gh.factory<_i1030.ChangePasswordFormBloc>( () => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()), ); - gh.factory<_i605.TransactionReportBloc>( - () => _i605.TransactionReportBloc( + gh.factory<_i147.UserEditFormBloc>( + () => _i147.UserEditFormBloc(gh<_i635.IUserRepository>()), + ); + gh.factory<_i346.InventoryReportBloc>( + () => _i346.InventoryReportBloc( gh<_i477.IAnalyticRepository>(), gh<_i197.IOutletRepository>(), ), ); - gh.factory<_i346.InventoryReportBloc>( - () => _i346.InventoryReportBloc( + gh.factory<_i605.TransactionReportBloc>( + () => _i605.TransactionReportBloc( gh<_i477.IAnalyticRepository>(), gh<_i197.IOutletRepository>(), ), @@ -283,12 +292,14 @@ extension GetItInjectableX on _i174.GetIt { } } -class _$SharedPreferencesDi extends _i402.SharedPreferencesDi {} +class _$FirebaseDi extends _i73.FirebaseDi {} -class _$DioDi extends _i103.DioDi {} +class _$SharedPreferencesDi extends _i402.SharedPreferencesDi {} class _$AutoRouteDi extends _i311.AutoRouteDi {} class _$ConnectivityDi extends _i586.ConnectivityDi {} +class _$DioDi extends _i103.DioDi {} + class _$PackageInfoDi extends _i227.PackageInfoDi {} diff --git a/lib/main.dart b/lib/main.dart index 826ecd4..c9b2e97 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:injectable/injectable.dart'; +import 'common/utils/fcm_service.dart'; import 'injection.dart'; import 'presentation/app_widget.dart'; @@ -24,5 +25,13 @@ void main() async { kReleaseMode ? Environment.prod : Environment.dev, ); + // Initialize FCM after dependencies are ready + await getIt().initialize( + onMessageTap: (message) { + // TODO: handle navigation when notification is tapped + debugPrint('[FCM] Navigate based on: ${message.data}'); + }, + ); + runApp(const AppWidget()); } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 3779ef0..5643091 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "apskel_owner_flutter") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.apskel.apskel_owner") +set(APPLICATION_ID "com.apskel.enaklo_owner") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 00f5060..476a6ba 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,9 @@ import Foundation import connectivity_plus import device_info_plus import file_selector_macos +import firebase_core +import firebase_messaging +import flutter_local_notifications import open_file_mac import package_info_plus import path_provider_foundation @@ -19,6 +22,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/pubspec.lock b/pubspec.lock index daee97a..7a22179 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "85.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + url: "https://pub.dev" + source: hosted + version: "1.3.59" analyzer: dependency: transitive description: @@ -205,10 +213,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" checked_yaml: dependency: transitive description: @@ -449,6 +457,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+4" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + url: "https://pub.dev" + source: hosted + version: "3.15.2" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: "0ecda14c1bfc9ed8cac303dd0f8d04a320811b479362a9a4efb14fd331a473ce" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + url: "https://pub.dev" + source: hosted + version: "2.24.1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + url: "https://pub.dev" + source: hosted + version: "15.2.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + url: "https://pub.dev" + source: hosted + version: "4.6.10" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + url: "https://pub.dev" + source: hosted + version: "3.10.10" fixnum: dependency: transitive description: @@ -518,6 +574,30 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610 + url: "https://pub.dev" + source: hosted + version: "18.0.1" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52" + url: "https://pub.dev" + source: hosted + version: "8.0.0" flutter_localizations: dependency: "direct main" description: flutter @@ -777,26 +857,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" line_icons: dependency: "direct main" description: @@ -833,26 +913,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: @@ -1422,10 +1502,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.10" time: dependency: transitive description: @@ -1434,6 +1514,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.5" + timezone: + dependency: transitive + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.dev" + source: hosted + version: "0.10.1" timing: dependency: transitive description: @@ -1550,10 +1638,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1635,5 +1723,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0-0 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3bf55bd..ad8712e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,6 +48,9 @@ dependencies: pdf: ^3.11.3 open_file: ^3.5.10 permission_handler: ^12.0.1 + firebase_core: ^3.13.1 + firebase_messaging: ^15.2.5 + flutter_local_notifications: ^18.0.1 dev_dependencies: flutter_test: diff --git a/web/favicon.png b/web/favicon.png index 91b113e..c477ce0 100644 Binary files a/web/favicon.png and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png index 483f22e..ac5b619 100644 Binary files a/web/icons/Icon-192.png and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png index 3d0d42e..d1e12cc 100644 Binary files a/web/icons/Icon-512.png and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png index 483f22e..ac5b619 100644 Binary files a/web/icons/Icon-maskable-192.png and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png index 3d0d42e..d1e12cc 100644 Binary files a/web/icons/Icon-maskable-512.png and b/web/icons/Icon-maskable-512.png differ diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index dbf8289..281ed4c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -16,6 +17,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index c22844a..11c0100 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus file_selector_windows + firebase_core permission_handler_windows url_launcher_windows ) diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index eba7b0f..53ae5ae 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ