diff --git a/cherrypick/example/bin/main.dart b/cherrypick/example/bin/main.dart index c57e00f..f9251c6 100644 --- a/cherrypick/example/bin/main.dart +++ b/cherrypick/example/bin/main.dart @@ -1,5 +1,4 @@ import 'dart:async'; - import 'package:cherrypick/cherrypick.dart'; import 'package:meta/meta.dart'; @@ -12,33 +11,34 @@ class AppModule extends Module { } class FeatureModule extends Module { - bool isMock; + final bool isMock; FeatureModule({required this.isMock}); @override void builder(Scope currentScope) { - bind() - .withName('networkRepo') - .toProvide( - () => NetworkDataRepository( - currentScope.resolve( - named: isMock ? 'apiClientMock' : 'apiClientImpl', - ), - ), - ) - .singleton(); + // DataRepository remains async for demonstration + bind().withName('networkRepo').toProvideAsync( + () async { + // Using synchronous resolve for ApiClient + final apiClient = currentScope.resolve( + named: isMock ? 'apiClientMock' : 'apiClientImpl', + ); + return NetworkDataRepository(apiClient); + }, + ).singleton(); - bind().toProvideWithParams( - (param) => DataBloc( - currentScope.resolve(named: 'networkRepo'), - param, - ), + bind().toProvideAsyncWithParams( + (param) async { + final dataRepository = await currentScope.resolveAsync( + named: 'networkRepo'); + return DataBloc(dataRepository, param); + }, ); } } -void main() async { +Future main() async { final scope = openRootScope().installModules([ AppModule(), ]); @@ -47,18 +47,22 @@ void main() async { .openSubScope('featureScope') .installModules([FeatureModule(isMock: true)]); - final dataBloc = subScope.resolve(params: 'PARAMETER'); - dataBloc.data.listen((d) => print('Received data: $d'), - onError: (e) => print('Error: $e'), onDone: () => print('DONE')); + try { + final dataBloc = await subScope.resolveAsync(params: 'PARAMETER'); + dataBloc.data.listen((d) => print('Received data: $d'), + onError: (e) => print('Error: $e'), onDone: () => print('DONE')); - await dataBloc.fetchData(); + await dataBloc.fetchData(); + } catch (e) { + print('Error resolving dependency: $e'); + } } class DataBloc { final DataRepository _dataRepository; - Stream get data => _dataController.stream; final StreamController _dataController = StreamController.broadcast(); + Stream get data => _dataController.stream; final String param; @@ -105,7 +109,6 @@ abstract class ApiClient { } class ApiClientMock implements ApiClient { - @override Future sendRequest({ @required String? url, String? token, @@ -117,7 +120,6 @@ class ApiClientMock implements ApiClient { } class ApiClientImpl implements ApiClient { - @override Future sendRequest({ @required String? url, String? token, diff --git a/cherrypick/lib/src/binding.dart b/cherrypick/lib/src/binding.dart index d2f27c0..be00592 100644 --- a/cherrypick/lib/src/binding.dart +++ b/cherrypick/lib/src/binding.dart @@ -15,6 +15,10 @@ enum Mode { simple, instance, providerInstance, providerInstanceWithParams } typedef ProviderWithParams = T Function(dynamic params); +typedef AsyncProvider = Future Function(); + +typedef AsyncProviderWithParams = Future Function(dynamic params); + /// RU: Класс Binding настраивает параметры экземпляра. /// ENG: The Binding class configures the settings for the instance. /// @@ -24,6 +28,9 @@ class Binding { late String _name; T? _instance; T? Function()? _provider; + AsyncProvider? asyncProvider; + AsyncProviderWithParams? asyncProviderWithParams; + ProviderWithParams? _providerWithParams; late bool _isSingleton = false; late bool _isNamed = false; @@ -94,6 +101,16 @@ class Binding { return this; } + /// RU: Инициализация экземляпяра  через провайдер [value]. + /// ENG: Initialization instance via provider [value]. + /// + /// return [Binding] + Binding toProvideAsync(AsyncProvider provider) { + _mode = Mode.providerInstance; + asyncProvider = provider; + return this; + } + /// RU: Инициализация экземляпяра  через провайдер [value] c динамическим параметром. /// ENG: Initialization instance via provider [value] with a dynamic param. /// @@ -104,6 +121,16 @@ class Binding { return this; } + /// RU: Инициализация экземляра через асинхронный провайдер [value] с динамическим параметром. + /// ENG: Initializes the instance via async provider [value] with a dynamic param. + /// + /// return [Binding] + Binding toProvideAsyncWithParams(AsyncProviderWithParams provider) { + _mode = Mode.providerInstanceWithParams; + asyncProviderWithParams = provider; + return this; + } + /// RU: Инициализация экземляпяра  как сингелтон [value]. /// ENG: Initialization instance as a singelton [value]. /// diff --git a/cherrypick/lib/src/scope.dart b/cherrypick/lib/src/scope.dart index 3f7bdc6..f0ac55d 100644 --- a/cherrypick/lib/src/scope.dart +++ b/cherrypick/lib/src/scope.dart @@ -132,4 +132,45 @@ class Scope { // 2 Поиск зависимостей в родительском скоупе return _parentScope?.tryResolve(named: named, params: params); } + + /// RU: Асинхронно возвращает найденную зависимость, определенную параметром типа [T]. + /// Выдает [StateError], если зависимость не может быть разрешена. + /// Если хотите получить [null], если зависимость не может быть найдена, используйте [tryResolveAsync]. + /// return - возвращает объект типа [T] or [StateError] + /// + /// ENG: Asynchronously returns the found dependency specified by the type parameter [T]. + /// Throws [StateError] if the dependency cannot be resolved. + /// If you want to get [null] if the dependency cannot be found, use [tryResolveAsync] instead. + /// return - returns an object of type [T] or [StateError] + /// + Future resolveAsync({String? named, dynamic params}) async { + var resolved = await tryResolveAsync(named: named, params: params); + if (resolved != null) { + return resolved; + } else { + throw StateError( + 'Can\'t resolve async dependency `$T`. Maybe you forget register it?'); + } + } + + Future tryResolveAsync({String? named, dynamic params}) async { + if (_modulesList.isNotEmpty) { + for (var module in _modulesList) { + for (var binding in module.bindingSet) { + if (binding.key == T && + ((!binding.isNamed && named == null) || + (binding.isNamed && named == binding.name))) { + if (binding.asyncProvider != null) { + return await binding.asyncProvider?.call(); + } + + if (binding.asyncProviderWithParams != null) { + return await binding.asyncProviderWithParams!(params); + } + } + } + } + } + return _parentScope?.tryResolveAsync(named: named, params: params); + } }