From 2752bebf913eb12436f1ba4c6b27a506d2efd8ed Mon Sep 17 00:00:00 2001 From: minikin Date: Mon, 22 Jan 2024 13:43:20 +0100 Subject: [PATCH] feat(frontend): add dependencies injection configurations --- catalyst_voices/ios/Podfile.lock | 6 ++ catalyst_voices/lib/app/view/app_content.dart | 31 ++++++--- catalyst_voices/lib/app/view/app_page.dart | 56 +++++++--------- .../lib/pages/login/login_page.dart | 16 +---- .../lib/src/catalyst_voices_blocs.dart | 1 + .../lib/src/dependency/dependency.dart | 46 +++++++++++++ .../src/dependency/dependency_provider.dart | 64 +++++++++++++++++++ .../catalyst_voices_blocs/pubspec.yaml | 3 + .../lib/src/authentication_repository.dart | 10 +-- 9 files changed, 171 insertions(+), 62 deletions(-) create mode 100644 catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency.dart create mode 100644 catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency_provider.dart diff --git a/catalyst_voices/ios/Podfile.lock b/catalyst_voices/ios/Podfile.lock index 6404e6eb675..21ca313d8b4 100644 --- a/catalyst_voices/ios/Podfile.lock +++ b/catalyst_voices/ios/Podfile.lock @@ -7,12 +7,15 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - url_launcher_ios (0.0.1): + - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - integration_test (from `.symlinks/plugins/integration_test/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) EXTERNAL SOURCES: Flutter: @@ -23,12 +26,15 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/integration_test/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be integration_test: 13825b8a9334a850581300559b8839134b124670 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b PODFILE CHECKSUM: ff9ae414ffbc80ad6f9d2058e299051a15f6eca7 diff --git a/catalyst_voices/lib/app/view/app_content.dart b/catalyst_voices/lib/app/view/app_content.dart index c8b23616ee7..e2874ecec21 100644 --- a/catalyst_voices/lib/app/view/app_content.dart +++ b/catalyst_voices/lib/app/view/app_content.dart @@ -4,28 +4,33 @@ import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localized_locales/flutter_localized_locales.dart'; +import 'package:go_router/go_router.dart'; + +const _restorationScopeId = 'rootVoices'; final class AppContent extends StatelessWidget { const AppContent({super.key}); + List> get _localizationsDelegates { + return const [ + ...VoicesLocalizations.localizationsDelegates, + LocaleNamesLocalizationsDelegate(), + ]; + } + @override Widget build(BuildContext context) { + final l10n = context.l10n; return BlocListener( listener: (context, state) {}, child: MaterialApp.router( - restorationScopeId: 'rootVoices', - localizationsDelegates: const [ - ...VoicesLocalizations.localizationsDelegates, - LocaleNamesLocalizationsDelegate(), - ], + restorationScopeId: _restorationScopeId, + localizationsDelegates: _localizationsDelegates, supportedLocales: VoicesLocalizations.supportedLocales, localeListResolutionCallback: basicLocaleListResolution, - routerConfig: AppRouter.init( - authenticationBloc: context.read(), - ), - title: 'Catalyst Voices', + routerConfig: _routeConfig(context), + title: l10n.homeScreenText, theme: ThemeData( - useMaterial3: true, brightness: Brightness.dark, bottomNavigationBarTheme: const BottomNavigationBarThemeData( type: BottomNavigationBarType.fixed, @@ -34,4 +39,10 @@ final class AppContent extends StatelessWidget { ), ); } + + GoRouter _routeConfig(BuildContext context) { + return AppRouter.init( + authenticationBloc: context.read(), + ); + } } diff --git a/catalyst_voices/lib/app/view/app_page.dart b/catalyst_voices/lib/app/view/app_page.dart index 71628b90fb1..8574fd75521 100644 --- a/catalyst_voices/lib/app/view/app_page.dart +++ b/catalyst_voices/lib/app/view/app_page.dart @@ -1,7 +1,7 @@ +// ignore_for_file: discarded_futures + import 'package:catalyst_voices/app/view/app_content.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; -import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_services/catalyst_voices_services.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -13,47 +13,39 @@ final class App extends StatefulWidget { } final class _AppState extends State { - late final AuthenticationRepository _authenticationRepository; - late final CredentialsStorageRepository _credentialsStorageRepository; + late final Future _initFuture; @override Widget build(BuildContext context) { - return MultiRepositoryProvider( - providers: [ - RepositoryProvider.value( - value: _authenticationRepository, - ), - ], - child: BlocProvider( - create: (_) => AuthenticationBloc( - authenticationRepository: _authenticationRepository, - ), - child: const AppContent(), - ), + return FutureBuilder( + future: _initFuture, + builder: (context, snapshot) { + return MultiBlocProvider( + providers: _multiBlocProviders(), + child: const AppContent(), + ); + }, ); } - @override - Future dispose() async { - await _authenticationRepository.dispose(); - - super.dispose(); - } - @override void initState() { super.initState(); - - _configureRepositories(); + _initFuture = _init(); } - void _configureRepositories() { - _credentialsStorageRepository = CredentialsStorageRepository( - secureStorageService: SecureStorageService(), - ); + Future _init() async { + await Dependency.instance.init(); + } - _authenticationRepository = AuthenticationRepository( - credentialsStorageRepository: _credentialsStorageRepository, - ); + List _multiBlocProviders() { + return [ + BlocProvider( + create: (_) => Dependency.instance.get(), + ), + BlocProvider( + create: (_) => Dependency.instance.get(), + ), + ]; } } diff --git a/catalyst_voices/lib/pages/login/login_page.dart b/catalyst_voices/lib/pages/login/login_page.dart index 19ed2e06b38..f86c97f9925 100644 --- a/catalyst_voices/lib/pages/login/login_page.dart +++ b/catalyst_voices/lib/pages/login/login_page.dart @@ -1,8 +1,5 @@ import 'package:catalyst_voices/pages/login/login.dart'; -import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; -import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; final class LoginPage extends StatelessWidget { static const loginPage = Key('LoginInPage'); @@ -11,17 +8,6 @@ final class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - key: loginPage, - create: (context) { - return LoginBloc( - authenticationRepository: - RepositoryProvider.of( - context, - ), - ); - }, - child: const LoginForm(), - ); + return const LoginForm(); } } diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/catalyst_voices_blocs.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/catalyst_voices_blocs.dart index d1042742844..2e94f47c7a1 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/catalyst_voices_blocs.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/catalyst_voices_blocs.dart @@ -1,2 +1,3 @@ export 'authentication/authentication.dart'; +export 'dependency/dependency.dart'; export 'login/login.dart'; diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency.dart new file mode 100644 index 00000000000..0c817b706e5 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency.dart @@ -0,0 +1,46 @@ +import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; +import 'package:catalyst_voices_blocs/src/dependency/dependency_provider.dart'; +import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; +import 'package:catalyst_voices_services/catalyst_voices_services.dart'; + +final class Dependency extends DependencyProvider { + static final Dependency instance = Dependency._(); + + Dependency._(); + + Future init() async { + _registerServices(); + _registerRepositories(); + _registerBlocsWithDependencies(); + } + + void _registerBlocsWithDependencies() { + this + ..registerSingleton( + AuthenticationBloc( + authenticationRepository: get(), + ), + ) + ..registerLazySingleton( + () => LoginBloc( + authenticationRepository: get(), + ), + ); + } + + void _registerRepositories() { + this + ..registerSingleton( + CredentialsStorageRepository(secureStorageService: get()), + ) + ..registerSingleton( + AuthenticationRepository(credentialsStorageRepository: get()), + ); + } + + void _registerServices() { + registerSingleton( + SecureStorageService(), + ); + } +} diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency_provider.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency_provider.dart new file mode 100644 index 00000000000..ac1df9dac7f --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/dependency/dependency_provider.dart @@ -0,0 +1,64 @@ +import 'package:flutter/foundation.dart'; +import 'package:get_it/get_it.dart'; + +abstract class DependencyProvider { + static final getIt = GetIt.instance; + + static Future get reset => getIt.reset(); + + @protected + Future allReady() { + return getIt.allReady(); + } + + T get() => getIt.get(); + + Future getAsync() => getIt.getAsync(); + + T getWithParam({P? param}) { + return getIt.get(param1: param); + } + + @protected + void registerFactory(ValueGetter factoryFunc) { + getIt.registerFactory(factoryFunc); + } + + @protected + void registerLazySingleton( + ValueGetter factoryFunc, { + DisposingFunc? dispose, + }) { + getIt.registerLazySingleton( + factoryFunc, + dispose: dispose, + ); + } + + @protected + void registerSingleton(T instance) { + getIt.registerSingleton(instance); + } + + @protected + void registerSingletonAsync( + ValueGetter> factoryFunc, { + Iterable? dependsOn, + }) { + getIt.registerSingletonAsync( + factoryFunc, + dependsOn: dependsOn, + ); + } + + @protected + void registerSingletonWithDependencies( + FactoryFunc factoryFunc, { + required List dependsOn, + }) { + getIt.registerSingletonWithDependencies( + factoryFunc, + dependsOn: dependsOn, + ); + } +} diff --git a/catalyst_voices/packages/catalyst_voices_blocs/pubspec.yaml b/catalyst_voices/packages/catalyst_voices_blocs/pubspec.yaml index 70de129a70f..b0026effdfd 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/pubspec.yaml +++ b/catalyst_voices/packages/catalyst_voices_blocs/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: path: ../catalyst_voices_models catalyst_voices_repositories: path: ../catalyst_voices_repositories + catalyst_voices_services: + path: ../catalyst_voices_services catalyst_voices_view_models: path: ../catalyst_voices_view_models collection: ^1.17.1 @@ -21,6 +23,7 @@ dependencies: flutter: sdk: flutter formz: ^0.6.1 + get_it: ^7.6.7 meta: ^1.10.0 result_type: ^0.2.0 diff --git a/catalyst_voices/packages/catalyst_voices_repositories/lib/src/authentication_repository.dart b/catalyst_voices/packages/catalyst_voices_repositories/lib/src/authentication_repository.dart index 496f0fc6508..b3b5afda62e 100644 --- a/catalyst_voices/packages/catalyst_voices_repositories/lib/src/authentication_repository.dart +++ b/catalyst_voices/packages/catalyst_voices_repositories/lib/src/authentication_repository.dart @@ -5,7 +5,7 @@ import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; final class AuthenticationRepository { final CredentialsStorageRepository credentialsStorageRepository; - final _controller = StreamController(); + final _streamController = StreamController(); AuthenticationRepository({required this.credentialsStorageRepository}); @@ -22,10 +22,10 @@ final class AuthenticationRepository { yield AuthenticationStatus.unknown; } - yield* _controller.stream; + yield* _streamController.stream; } - Future dispose() async => _controller.close(); + Future dispose() async => _streamController.close(); Future getSessionData() async { try { @@ -43,7 +43,7 @@ final class AuthenticationRepository { void logOut() { credentialsStorageRepository.clearSessionData; - _controller.add(AuthenticationStatus.unauthenticated); + _streamController.add(AuthenticationStatus.unauthenticated); } Future signIn({ @@ -60,7 +60,7 @@ final class AuthenticationRepository { // TODO(minikin): remove this delay after implementing real auth flow. await Future.delayed( const Duration(milliseconds: 300), - () => _controller.add(AuthenticationStatus.authenticated), + () => _streamController.add(AuthenticationStatus.authenticated), ); } }