diff --git a/.gitignore b/.gitignore index d118433..bd4de7c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,13 @@ app.*.map.json *.g.dart *.gr.dart *.freezed.dart + +# environment variables +/env + +# firebase +**/google-services.json +**/GoogleService-Info.plist +**/firebase_app_id_file.json +**/firebase_options.dart + diff --git a/analysis_options.yaml b/analysis_options.yaml index e0e35ac..b27cf50 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -6,6 +6,7 @@ analyzer: exclude: - "**.g.dart" - "**.freezed.dart" + - "/**firebase_options.dart" linter: rules: file_names: false diff --git a/android/app/build.gradle b/android/app/build.gradle index 102552d..ee3a862 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -2,6 +2,8 @@ plugins { id "com.android.application" id "kotlin-android" id "dev.flutter.flutter-gradle-plugin" + id "com.google.gms.google-services" + id "com.google.firebase.crashlytics" } def localProperties = new Properties() diff --git a/android/settings.gradle b/android/settings.gradle index ef9e4af..9c40733 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -20,6 +20,8 @@ plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "7.4.2" apply false id "org.jetbrains.kotlin.android" version "1.9.22" apply false + id "com.google.gms.google-services" version "4.4.0" apply false + id "com.google.firebase.crashlytics" version "2.9.9" apply false } include ":app" diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 88359b2..279576f 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index bcc2866..5b71fee 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,20 +1,87 @@ PODS: + - Firebase/CoreOnly (10.22.0): + - FirebaseCore (= 10.22.0) + - Firebase/Crashlytics (10.22.0): + - Firebase/CoreOnly + - FirebaseCrashlytics (~> 10.22.0) + - firebase_core (2.27.1): + - Firebase/CoreOnly (= 10.22.0) + - Flutter + - firebase_crashlytics (3.4.19): + - Firebase/Crashlytics (= 10.22.0) + - firebase_core + - Flutter + - FirebaseCore (10.22.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.12) + - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.22.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.22.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseCrashlytics (10.22.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - nanopb (< 2.30911.0, >= 2.30908.0) + - PromisesObjC (~> 2.1) + - FirebaseInstallations (10.22.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebaseSessions (10.23.0): + - FirebaseCore (~> 10.5) + - FirebaseCoreExtension (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.10) + - nanopb (< 2.30911.0, >= 2.30908.0) + - PromisesSwift (~> 2.1) - Flutter (1.0.0) - flutter_native_splash (0.0.1): - Flutter + - GoogleDataTransport (9.4.1): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30911.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Environment (7.13.0): + - GoogleUtilities/Privacy + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.13.0): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - "GoogleUtilities/NSData+zlib (7.13.0)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (7.13.0) + - GoogleUtilities/UserDefaults (7.13.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy - in_app_review (0.2.0): - Flutter + - nanopb (2.30910.0): + - nanopb/decode (= 2.30910.0) + - nanopb/encode (= 2.30910.0) + - nanopb/decode (2.30910.0) + - nanopb/encode (2.30910.0) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - PromisesObjC (2.4.0) + - PromisesSwift (2.4.0): + - PromisesObjC (= 2.4.0) - share_plus (0.0.1): - Flutter - url_launcher_ios (0.0.1): - Flutter DEPENDENCIES: + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) - Flutter (from `Flutter`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - in_app_review (from `.symlinks/plugins/in_app_review/ios`) @@ -23,7 +90,26 @@ DEPENDENCIES: - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) +SPEC REPOS: + trunk: + - Firebase + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - FirebaseCrashlytics + - FirebaseInstallations + - FirebaseSessions + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + - PromisesSwift + EXTERNAL SOURCES: + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_crashlytics: + :path: ".symlinks/plugins/firebase_crashlytics/ios" Flutter: :path: Flutter flutter_native_splash: @@ -40,14 +126,28 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef + Firebase: 797fd7297b7e1be954432743a0b3f90038e45a71 + firebase_core: d6dfb4cb86a9ebd92464bb8736075fe967211c97 + firebase_crashlytics: 0be8c89a6b91fd964a7a8fe574109fd528d310bb + FirebaseCore: 0326ec9b05fbed8f8716cddbf0e36894a13837f7 + FirebaseCoreExtension: 6394c00b887d0bebadbc7049c464aa0cbddc5d41 + FirebaseCoreInternal: bca337352024b18424a61e478460547d46c4c753 + FirebaseCrashlytics: e568d68ce89117c80cddb04073ab9018725fbb8c + FirebaseInstallations: 763814908793c0da14c18b3dcffdec71e29ed55e + FirebaseSessions: f06853e30f99fe42aa511014d7ee6c8c319f08a3 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778 + GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a + GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152 in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d - package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + nanopb: 438bc412db1928dac798aa6fd75726007be04262 + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 - url_launcher_ios: 68d46cc9766d0c41dbdc884310529557e3cd7a86 + url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586 -PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 +PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011 -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 5fc4cde..9d4e078 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + CE2C8C38E2953B6831D3AC9D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6F110F54F1D9780F415898DB /* GoogleService-Info.plist */; }; FE36318640B1BA534A57B353 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C72D3776DF8835C5ED10945 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ @@ -36,6 +37,7 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 454D6FDBAD08AA9AAB10944C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 6651C203B376476D69DB3086 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 6F110F54F1D9780F415898DB /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -80,6 +82,7 @@ 97C146EF1CF9000F007C117D /* Products */, D46A21369FDB488674476679 /* Pods */, D41E5151D67274DCF9CCD160 /* Frameworks */, + 6F110F54F1D9780F415898DB /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -140,6 +143,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 8144507F31782B87B24B5159 /* [CP] Embed Pods Frameworks */, + ADF5B00798207F89CAF29939 /* [firebase_crashlytics] Crashlytics Upload Symbols */, ); buildRules = ( ); @@ -156,7 +160,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -192,6 +196,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + CE2C8C38E2953B6831D3AC9D /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -268,6 +273,29 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + ADF5B00798207F89CAF29939 /* [firebase_crashlytics] Crashlytics Upload Symbols */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"", + "\"$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)\"", + "\"$(PROJECT_DIR)/firebase_app_id_file.json\"", + ); + name = "[firebase_crashlytics] Crashlytics Upload Symbols"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" "; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -343,7 +371,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -420,7 +448,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -469,7 +497,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826d..5e31d3d 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ get supportedLocales => [ diff --git a/lib/app/theme/constants/theme_constants.dart b/lib/app/theme/constants/theme_constants.dart index e6e67b6..21b7a1f 100644 --- a/lib/app/theme/constants/theme_constants.dart +++ b/lib/app/theme/constants/theme_constants.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; abstract final class ThemeConstants { + ThemeConstants._(); + static BorderRadius borderRadiusCircular = BorderRadius.circular(12); static Radius radiusCircular = const Radius.circular(12); } diff --git a/lib/app/theme/cubit/theme_cubit.freezed.dart b/lib/app/theme/cubit/theme_cubit.freezed.dart index 6b48118..eb734cc 100644 --- a/lib/app/theme/cubit/theme_cubit.freezed.dart +++ b/lib/app/theme/cubit/theme_cubit.freezed.dart @@ -12,7 +12,7 @@ part of 'theme_cubit.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$ThemeState { @@ -103,7 +103,7 @@ class _$ThemeStateImpl extends _ThemeState { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ThemeStateImpl && diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart new file mode 100644 index 0000000..a6eac38 --- /dev/null +++ b/lib/app/view/app.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localized_locales/flutter_localized_locales.dart'; +import 'package:password_generator/app/constants/string_constants.dart'; +import 'package:password_generator/app/l10n/cubit/l10n_cubit.dart'; +import 'package:password_generator/app/l10n/extensions/app_l10n_extensions.dart'; +import 'package:password_generator/app/router/app_router.dart'; +import 'package:password_generator/app/theme/cubit/theme_cubit.dart'; +import 'package:password_generator/app/theme/dark/app_theme_dark.dart'; +import 'package:password_generator/app/theme/light/app_theme_light.dart'; +import 'package:password_generator/core/extensions/context_extensions.dart'; +import 'package:password_generator/features/generate_password/data/repository/generate_password_repository.dart'; +import 'package:password_generator/features/generate_password/presentation/cubit/generate_password_cubit.dart'; +import 'package:password_generator/features/password_history/cubit/password_history_cubit.dart'; + +class App extends StatelessWidget { + App({super.key}); + + final _appRouter = AppRouter(); + + @override + Widget build(BuildContext context) { + // Injecting Blocs to the widget tree + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (_) => L10nCubit(), + ), + BlocProvider( + create: (_) => ThemeCubit(), + ), + BlocProvider( + create: (_) => PasswordHistoryCubit(), + ), + BlocProvider( + create: (_) => GeneratePasswordCubit( + generatePasswordRepository: GeneratePasswordRepositoryImpl(), + )..generatePassword(), + ), + ], + child: BlocBuilder( + builder: (context, l10nState) { + return BlocBuilder( + builder: (context, themeState) { + return MaterialApp.router( + debugShowCheckedModeBanner: false, + title: StringConstants.appName, + + // Theme + theme: AppThemeLight().theme, + darkTheme: AppThemeDark().theme, + themeMode: themeState.themeMode, + + // Localization + locale: l10nState.locale, + supportedLocales: AppLocalizations.supportedLocales, + localizationsDelegates: const [ + ...AppLocalizations.localizationsDelegates, + LocaleNamesLocalizationsDelegate(), + ], + + // Routing + routerDelegate: _appRouter.delegate(), + routeInformationParser: _appRouter.defaultRouteParser(), + + builder: (context, child) => MediaQuery( + // Disables font scaling and bold text + data: context.mediaQuery.copyWith(boldText: false, textScaler: TextScaler.noScaling), + child: child!, + ), + ); + }, + ); + }, + ), + ); + } +} diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart new file mode 100644 index 0000000..737cf25 --- /dev/null +++ b/lib/bootstrap.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; +import 'package:password_generator/app/env/env.dart'; +import 'package:password_generator/core/clients/cache/cache_migration_client.dart'; +import 'package:password_generator/core/utils/encryption/encryption_utils.dart'; +import 'package:password_generator/core/utils/logger/logger_utils.dart'; +import 'package:password_generator/core/utils/package_info/package_info_utils.dart'; +import 'package:password_generator/firebase_options.dart'; +import 'package:path_provider/path_provider.dart'; + +Future bootstrap({required FutureOr Function() builder}) async { + WidgetsFlutterBinding.ensureInitialized(); + FlutterNativeSplash(); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(kReleaseMode); + // Register error handlers. For more info, see: + // https://docs.flutter.dev/testing/errors + // Pass all uncaught Flutter framework exceptions to Crashlytics + FlutterError.onError = (FlutterErrorDetails details) { + FirebaseCrashlytics.instance.recordFlutterError(details); + LoggerUtils.instance.logFatalError(details.exceptionAsString(), details.stack); + }; + // Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics + PlatformDispatcher.instance.onError = (error, stack) { + FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); + LoggerUtils.instance.logFatalError(error.toString(), stack); + return true; + }; + + await Future.wait([ + Hive.initFlutter(), + PackageInfoUtils.init(), + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp], + ), + ]); + + final encryptionKey = EncryptionUtils.generateEncryptionKeyFromSecretKey(Env.secretKey); + final cacheMigrationClient = CacheMigrationClient(); + await cacheMigrationClient.migrate(encryptionKey: encryptionKey); + + // Initialize Hydrated Bloc + HydratedBloc.storage = await HydratedStorage.build( + storageDirectory: await getApplicationDocumentsDirectory(), + encryptionCipher: HydratedAesCipher(encryptionKey), + ); + + runApp(await builder()); +} diff --git a/lib/core/clients/cache/cache_migration_client.dart b/lib/core/clients/cache/cache_migration_client.dart new file mode 100644 index 0000000..0350d02 --- /dev/null +++ b/lib/core/clients/cache/cache_migration_client.dart @@ -0,0 +1,86 @@ +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:password_generator/app/constants/cache_constants.dart'; +import 'package:password_generator/core/utils/logger/logger_utils.dart'; + +enum MigrationStatus { + completed(true), + notCompleted(false); + + const MigrationStatus(this.value); + + final bool value; +} + +class CacheMigrationClient { + Future migrate({required List encryptionKey}) async { + try { + final hasHydratedBox = await _boxExists(CacheConstants.hydratedBox); + final migrationStatus = await _getMigrationStatus(); + + if (hasHydratedBox && migrationStatus == MigrationStatus.notCompleted) { + await _migrateToEncryptedBox( + hydratedBoxName: CacheConstants.hydratedBox, + tempBoxName: CacheConstants.tempBox, + encryptionKey: encryptionKey, + ); + } else { + await _setMigrationStatus(MigrationStatus.completed); + } + } catch (e) { + LoggerUtils.instance.logError('Error during migration: $e'); + } + } + + Future _boxExists(String boxName) async { + return Hive.boxExists(boxName); + } + + Future _setMigrationStatus(MigrationStatus status) async { + final migrationBox = await Hive.openBox(CacheConstants.migrationBox); + await migrationBox.put(CacheConstants.migrationCompleted, status.value); + } + + Future _getMigrationStatus() async { + final migrationBox = await Hive.openBox(CacheConstants.migrationBox); + final migrationCompleted = migrationBox.get(CacheConstants.migrationCompleted); + return migrationCompleted == true ? MigrationStatus.completed : MigrationStatus.notCompleted; + } + + Future _migrateToEncryptedBox({ + required String hydratedBoxName, + required String tempBoxName, + required List encryptionKey, + }) async { + // Open the existing hydrated box. + final oldHydratedBox = await Hive.openBox(hydratedBoxName); + // Create a new temporary box to hold the data from the hydrated box + final tempBox = await Hive.openBox(tempBoxName); + + // Migrate data from the existing box to the temporary box + for (final key in oldHydratedBox.keys) { + final value = oldHydratedBox.get(key); + await tempBox.put(key, value); + } + // Delete the old hydrated box from the disk + await oldHydratedBox.deleteFromDisk(); + + // Open a new hydrated box with the given encryption key + final newHydratedBox = await Hive.openBox( + hydratedBoxName, + encryptionCipher: HiveAesCipher(encryptionKey), + ); + // Migrate the data from the temporary box to the new encrypted box + for (final key in tempBox.keys) { + final value = tempBox.get(key); + await newHydratedBox.put(key, value); + } + // Complete the migration by closing the new box, deleting the temp box, and updating the migration status + await Future.wait( + [ + newHydratedBox.close(), + tempBox.deleteFromDisk(), + _setMigrationStatus(MigrationStatus.completed), + ], + ); + } +} diff --git a/lib/core/utils/encryption/encryption_utils.dart b/lib/core/utils/encryption/encryption_utils.dart new file mode 100644 index 0000000..def1b01 --- /dev/null +++ b/lib/core/utils/encryption/encryption_utils.dart @@ -0,0 +1,10 @@ +import 'dart:convert'; +import 'package:crypto/crypto.dart'; + +abstract final class EncryptionUtils { + EncryptionUtils._(); + + static List generateEncryptionKeyFromSecretKey(String password) { + return sha256.convert(utf8.encode(password)).bytes; + } +} diff --git a/lib/core/utils/logger/logger_utils.dart b/lib/core/utils/logger/logger_utils.dart new file mode 100644 index 0000000..7133dd9 --- /dev/null +++ b/lib/core/utils/logger/logger_utils.dart @@ -0,0 +1,32 @@ +// ignore_for_file: prefer_constructors_over_static_methods + +import 'package:logger/logger.dart'; + +class LoggerUtils { + LoggerUtils._(); + + static LoggerUtils? _instance; + + static LoggerUtils get instance { + _instance ??= LoggerUtils._(); + return _instance!; + } + + final Logger _logger = Logger(printer: PrettyPrinter(stackTraceBeginIndex: 2)); + + void logInfo(String message) { + _logger.i(message); + } + + void logWarning(String message) { + _logger.w(message); + } + + void logError(String message) { + _logger.e(message); + } + + void logFatalError(String message, StackTrace? stackTrace) { + _logger.f(message, stackTrace: stackTrace); + } +} diff --git a/lib/core/utils/package_info/package_info_utils.dart b/lib/core/utils/package_info/package_info_utils.dart index 40b4da2..35d7db0 100644 --- a/lib/core/utils/package_info/package_info_utils.dart +++ b/lib/core/utils/package_info/package_info_utils.dart @@ -1,6 +1,8 @@ import 'package:package_info_plus/package_info_plus.dart'; abstract final class PackageInfoUtils { + PackageInfoUtils._(); + static late final PackageInfo _packageInfo; static Future init() async { diff --git a/lib/core/utils/rate_app/rate_app_utils.dart b/lib/core/utils/rate_app/rate_app_utils.dart index e1a8018..3ab72c1 100644 --- a/lib/core/utils/rate_app/rate_app_utils.dart +++ b/lib/core/utils/rate_app/rate_app_utils.dart @@ -1,6 +1,8 @@ import 'package:in_app_review/in_app_review.dart'; abstract final class RateAppUtils { + RateAppUtils._(); + static Future rateApp() async { final inAppReview = InAppReview.instance; diff --git a/lib/core/utils/share_app/share_app_utils.dart b/lib/core/utils/share_app/share_app_utils.dart index 525ada8..2cbc4bc 100644 --- a/lib/core/utils/share_app/share_app_utils.dart +++ b/lib/core/utils/share_app/share_app_utils.dart @@ -2,6 +2,8 @@ import 'package:password_generator/app/constants/string_constants.dart'; import 'package:share_plus/share_plus.dart'; abstract final class ShareAppUtils { + ShareAppUtils._(); + static Future shareApp() async { await Share.share(StringConstants.googlePlayUrl); } diff --git a/lib/core/utils/snackbar/snackbar_utils.dart b/lib/core/utils/snackbar/snackbar_utils.dart index 56ccc4c..cd158c4 100644 --- a/lib/core/utils/snackbar/snackbar_utils.dart +++ b/lib/core/utils/snackbar/snackbar_utils.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:password_generator/core/extensions/context_extensions.dart'; abstract final class SnackbarUtils { + SnackbarUtils._(); + static void showSnackbar({required BuildContext context, required String message}) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() diff --git a/lib/core/utils/url_launcher/url_launcher_utils.dart b/lib/core/utils/url_launcher/url_launcher_utils.dart index ccef5c6..f9ed579 100644 --- a/lib/core/utils/url_launcher/url_launcher_utils.dart +++ b/lib/core/utils/url_launcher/url_launcher_utils.dart @@ -1,6 +1,8 @@ import 'package:url_launcher/url_launcher_string.dart'; abstract final class UrlLauncherUtils { + UrlLauncherUtils._(); + static Future launchUrlFromString({required String url}) async { final isLaunched = await launchUrlString(url); return isLaunched; diff --git a/lib/features/generate_password/data/model/password_settings.freezed.dart b/lib/features/generate_password/data/model/password_settings.freezed.dart index 43185e4..85b4026 100644 --- a/lib/features/generate_password/data/model/password_settings.freezed.dart +++ b/lib/features/generate_password/data/model/password_settings.freezed.dart @@ -12,7 +12,7 @@ part of 'password_settings.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$PasswordSettings { @@ -171,7 +171,7 @@ class _$PasswordSettingsImpl extends _PasswordSettings { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$PasswordSettingsImpl && diff --git a/lib/features/generate_password/presentation/cubit/generate_password_cubit.freezed.dart b/lib/features/generate_password/presentation/cubit/generate_password_cubit.freezed.dart index 0e21670..a3746d6 100644 --- a/lib/features/generate_password/presentation/cubit/generate_password_cubit.freezed.dart +++ b/lib/features/generate_password/presentation/cubit/generate_password_cubit.freezed.dart @@ -12,7 +12,7 @@ part of 'generate_password_cubit.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$GeneratePasswordState { @@ -150,7 +150,7 @@ class _$GeneratePasswordStateImpl implements _GeneratePasswordState { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$GeneratePasswordStateImpl && diff --git a/lib/main.dart b/lib/main.dart index 467709c..b2de0d9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,101 +1,6 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_localized_locales/flutter_localized_locales.dart'; -import 'package:flutter_native_splash/flutter_native_splash.dart'; -import 'package:hydrated_bloc/hydrated_bloc.dart'; -import 'package:password_generator/app/constants/string_constants.dart'; -import 'package:password_generator/app/l10n/cubit/l10n_cubit.dart'; -import 'package:password_generator/app/l10n/extensions/app_l10n_extensions.dart'; -import 'package:password_generator/app/router/app_router.dart'; -import 'package:password_generator/app/theme/cubit/theme_cubit.dart'; -import 'package:password_generator/app/theme/dark/app_theme_dark.dart'; -import 'package:password_generator/app/theme/light/app_theme_light.dart'; -import 'package:password_generator/core/extensions/context_extensions.dart'; -import 'package:password_generator/core/utils/package_info/package_info_utils.dart'; -import 'package:password_generator/features/generate_password/data/repository/generate_password_repository.dart'; -import 'package:password_generator/features/generate_password/presentation/cubit/generate_password_cubit.dart'; -import 'package:password_generator/features/password_history/cubit/password_history_cubit.dart'; -import 'package:path_provider/path_provider.dart'; +import 'package:password_generator/app/view/app.dart'; +import 'package:password_generator/bootstrap.dart'; Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - // Initialize Flutter Native Splash - FlutterNativeSplash(); - // Initialize Hydrated Bloc - HydratedBloc.storage = await HydratedStorage.build( - storageDirectory: await getApplicationDocumentsDirectory(), - ); - // Initialize PackageInfoPlus - await PackageInfoUtils.init(); - // Set Screen Orientation - await SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp], - ); - - runApp(PasswordGenerator()); -} - -class PasswordGenerator extends StatelessWidget { - PasswordGenerator({super.key}); - - final _appRouter = AppRouter(); - - @override - Widget build(BuildContext context) { - // Injecting Blocs to the widget tree - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (_) => L10nCubit(), - ), - BlocProvider( - create: (_) => ThemeCubit(), - ), - BlocProvider( - create: (_) => PasswordHistoryCubit(), - ), - BlocProvider( - create: (_) => GeneratePasswordCubit( - generatePasswordRepository: GeneratePasswordRepositoryImpl(), - )..generatePassword(), - ), - ], - child: BlocBuilder( - builder: (context, l10nState) { - return BlocBuilder( - builder: (context, themeState) { - return MaterialApp.router( - debugShowCheckedModeBanner: false, - title: StringConstants.appName, - - // Theme - theme: AppThemeLight().theme, - darkTheme: AppThemeDark().theme, - themeMode: themeState.themeMode, - - // Localization - locale: l10nState.locale, - supportedLocales: AppLocalizations.supportedLocales, - localizationsDelegates: const [ - ...AppLocalizations.localizationsDelegates, - LocaleNamesLocalizationsDelegate(), - ], - - // Routing - routerDelegate: _appRouter.delegate(), - routeInformationParser: _appRouter.defaultRouteParser(), - - builder: (context, child) => MediaQuery( - // Disables font scaling and bold text - data: context.mediaQuery.copyWith(boldText: false, textScaler: TextScaler.noScaling), - child: child!, - ), - ); - }, - ); - }, - ), - ); - } + await bootstrap(builder: App.new); } diff --git a/pubspec.lock b/pubspec.lock index b6cf10a..8801773 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "67.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "554f148e71e9e016d9c04d4af6b103ca3f74a1ceed7d7307b70a0f41e991eb77" + url: "https://pub.dev" + source: hosted + version: "1.3.26" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.4.1" ansicolor: dependency: transitive description: @@ -29,10 +37,10 @@ packages: dependency: transitive description: name: archive - sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03" + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" url: "https://pub.dev" source: hosted - version: "3.4.6" + version: "3.4.10" args: dependency: transitive description: @@ -53,10 +61,10 @@ packages: dependency: "direct main" description: name: auto_route - sha256: "82f8df1d177416bc6b7a449127d0270ff1f0f633a91f2ceb7a85d4f07c3affa1" + sha256: eb33554581a0a4aa7e6da0f13a44291a55bf71359012f1d9feb41634ff908ff8 url: "https://pub.dev" source: hosted - version: "7.8.4" + version: "7.9.2" auto_route_generator: dependency: "direct dev" description: @@ -69,10 +77,10 @@ packages: dependency: transitive description: name: bloc - sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e url: "https://pub.dev" source: hosted - version: "8.1.2" + version: "8.1.3" boolean_selector: dependency: transitive description: @@ -101,34 +109,34 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b" + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.4.8" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.0" built_collection: dependency: transitive description: @@ -141,10 +149,10 @@ packages: dependency: transitive description: name: built_value - sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" + sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e url: "https://pub.dev" source: hosted - version: "8.7.0" + version: "8.9.1" characters: dependency: transitive description: @@ -165,10 +173,10 @@ packages: dependency: transitive description: name: cli_util - sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" clock: dependency: transitive description: @@ -181,10 +189,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.10.0" collection: dependency: transitive description: @@ -205,12 +213,12 @@ packages: dependency: transitive description: name: cross_file - sha256: "445db18de832dba8d851e287aff8ccf169bed30d2e94243cb54c7d2f1ed2142c" + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+6" + version: "0.3.4+1" crypto: - dependency: transitive + dependency: "direct main" description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab @@ -229,10 +237,26 @@ packages: dependency: transitive description: name: dart_style - sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334 + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.6" + envied: + dependency: "direct main" + description: + name: envied + sha256: dab29e21452c3d57ec10889d96b06b4a006b01375d4df10b33c9704800c208c4 + url: "https://pub.dev" + source: hosted + version: "0.5.3" + envied_generator: + dependency: "direct dev" + description: + name: envied_generator + sha256: b8655d5cb39b4d1d449a79ff6f1367b252c23955ff17ec7c03aacdff938598bd + url: "https://pub.dev" + source: hosted + version: "0.5.3" fake_async: dependency: transitive description: @@ -245,10 +269,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -257,6 +281,46 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "67bf0d5fd78f12f51c6b54a72f6141314136a1a90e98b1b7c45e7fac883254ed" + url: "https://pub.dev" + source: hosted + version: "2.27.1" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 + url: "https://pub.dev" + source: hosted + version: "5.0.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "5377eaac3b9fe8aaf22638d87f92b62784f23572e132dfc029195e84d6cb37de" + url: "https://pub.dev" + source: hosted + version: "2.12.0" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: cf120df5b473f5f8cd24f9de663edc8aed3a1888d29d805076be0448bdee249e + url: "https://pub.dev" + source: hosted + version: "3.4.19" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: "99656cc39228e8f2b845cddb4d43307bb44294a03e7d00b4d8e35536889bc65c" + url: "https://pub.dev" + source: hosted + version: "3.6.26" fixnum: dependency: transitive description: @@ -274,10 +338,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.4" flutter_launcher_icons: dependency: "direct main" description: @@ -303,10 +367,10 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: "141b20f15a2c4fe6e33c49257ca1bc114fc5c500b04fcbc8d75016bb86af672f" + sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0 url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.4.0" flutter_test: dependency: "direct dev" description: flutter @@ -329,10 +393,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a" + sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.7" freezed_annotation: dependency: "direct main" description: @@ -373,6 +437,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.3" + hive_flutter: + dependency: "direct main" + description: + name: hive_flutter + sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc + url: "https://pub.dev" + source: hosted + version: "1.1.0" html: dependency: transitive description: @@ -385,10 +457,10 @@ packages: dependency: transitive description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" http_multi_server: dependency: transitive description: @@ -409,26 +481,26 @@ packages: dependency: "direct main" description: name: hydrated_bloc - sha256: "24994e61f64904d911683cce1a31dc4ef611619da5253f1de2b7b8fc6f79a118" + sha256: "00a2099680162e74b5a836b8a7f446e478520a9cae9f6032e028ad8129f4432d" url: "https://pub.dev" source: hosted - version: "9.1.2" + version: "9.1.4" image: dependency: transitive description: name: image - sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.7" in_app_review: dependency: "direct main" description: name: in_app_review - sha256: "41ec6f30427ab09eb6ae1c85c4a2a624a145fc5d726f023de4d97170ec9e5466" + sha256: "99869244d09adc76af16bf8fd731dd13cef58ecafd5917847589c49f378cbb30" url: "https://pub.dev" source: hosted - version: "2.0.8" + version: "2.0.9" in_app_review_platform_interface: dependency: transitive description: @@ -493,6 +565,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + logger: + dependency: "direct main" + description: + name: logger + sha256: "8c94b8c219e7e50194efc8771cd0e9f10807d8d3e219af473d89b06cc2ee4e04" + url: "https://pub.dev" + source: hosted + version: "2.2.0" logging: dependency: transitive description: @@ -529,10 +609,10 @@ packages: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" nested: dependency: transitive description: @@ -553,10 +633,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + sha256: cb44f49b6e690fa766f023d5b22cac6b9affe741dd792b6ac7ad4fabe0d7b097 url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "6.0.0" package_info_plus_platform_interface: dependency: transitive description: @@ -577,26 +657,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -609,10 +689,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -633,26 +713,26 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" pool: dependency: transitive description: @@ -665,10 +745,10 @@ packages: dependency: transitive description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.2" pub_semver: dependency: transitive description: @@ -685,22 +765,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.3" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" share_plus: dependency: "direct main" description: name: share_plus - sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd + sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.0" shelf: dependency: transitive description: @@ -726,10 +814,10 @@ packages: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_span: dependency: transitive description: @@ -782,10 +870,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -830,34 +918,34 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 + sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" + sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.3.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "4ac97281cf60e2e8c5cc703b2b28528f9b50c8f7cebc71df6bdf0845f647268a" + sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.2.5" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd" + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" url_launcher_macos: dependency: transitive description: @@ -870,34 +958,34 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc" + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" uuid: dependency: transitive description: name: uuid - sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7 + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.3.3" vector_math: dependency: transitive description: @@ -934,34 +1022,34 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.4" win32: dependency: transitive description: name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" + sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" url: "https://pub.dev" source: hosted - version: "5.0.9" + version: "5.3.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -979,5 +1067,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.13.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 25ab654..75e295b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,14 +10,24 @@ dependencies: #state management flutter_bloc: ^8.1.3 - hydrated_bloc: ^9.1.2 + hydrated_bloc: ^9.1.4 + + # caching + hive_flutter: ^1.1.0 + + # firebase + firebase_core: ^2.27.1 + firebase_crashlytics: ^3.4.19 #utility + crypto: ^3.0.3 + envied: ^0.5.3 + logger: ^2.2.0 share_plus: ^7.2.1 in_app_review: ^2.0.8 url_launcher: ^6.2.2 path_provider: ^2.1.1 - package_info_plus: ^5.0.1 + package_info_plus: ^6.0.0 #localization flutter_localizations: @@ -47,6 +57,7 @@ dev_dependencies: #code gen freezed: ^2.4.5 build_runner: ^2.4.7 + envied_generator: ^0.5.3 auto_route_generator: ^7.3.2 flutter_launcher_icons: