diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 58ba46e..02951d2 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -28,6 +28,9 @@ jobs: - name: Bootstrap workspace run: fvm flutter pub global run melos bootstrap + - name: CodeGen + run: fvm flutter pub global run melos run codegen + - name: Analyze all packages run: fvm flutter pub global run melos run analyze diff --git a/.gitignore b/.gitignore index 2dcf182..334af6d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,11 @@ .idea/ .vscode/ + +**/*.g.dart +**/*.gr.dart +**/*.freezed.dart + pubspec_overrides.yaml melos_cherrypick.iml diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c168e..03932d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,36 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 2025-05-16 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`cherrypick` - `v2.1.0-dev.1`](#cherrypick---v210-dev1) + - [`cherrypick_flutter` - `v1.1.1-dev.1`](#cherrypick_flutter---v111-dev1) + +--- + +#### `cherrypick` - `v2.1.0-dev.1` + + - **FIX**: fix warnings. + - **FIX**: fix warnings. + - **FIX**: support passing params when resolving dependency recursively in parent scope. + - **FEAT**: Add async dependency resolution and enhance example. + - **FEAT**: Add async dependency resolution and enhance example. + +#### `cherrypick_flutter` - `v1.1.1-dev.1` + + - **FIX**: fix warnings. + + ## 2025-05-16 ### Changes diff --git a/cherrypick/.gitignore b/cherrypick/.gitignore index dbef116..16cc011 100644 --- a/cherrypick/.gitignore +++ b/cherrypick/.gitignore @@ -19,3 +19,6 @@ doc/api/ *.js_ *.js.deps *.js.map + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/cherrypick/CHANGELOG.md b/cherrypick/CHANGELOG.md index 342e852..5563305 100644 --- a/cherrypick/CHANGELOG.md +++ b/cherrypick/CHANGELOG.md @@ -1,6 +1,18 @@ +## 2.1.0-dev.1 + + - **FIX**: fix warnings. + - **FIX**: fix warnings. + - **FIX**: support passing params when resolving dependency recursively in parent scope. + - **FEAT**: Add async dependency resolution and enhance example. + - **FEAT**: Add async dependency resolution and enhance example. + ## 2.0.2 - **FIX**: support passing params when resolving dependency recursively in parent scope. +## 2.1.0-dev.0 + + - **FEAT**: Add async dependency resolution and enhance example. + ## 2.0.1 - **FIX**: fix warning. diff --git a/cherrypick/README.md b/cherrypick/README.md index 8f76c97..a4499cb 100644 --- a/cherrypick/README.md +++ b/cherrypick/README.md @@ -1,31 +1,43 @@ # CherryPick Flutter -`cherrypick_flutter` is a powerful Flutter library for managing and accessing dependencies within your application through a root scope context using `CherryPickProvider`. It offers simplified dependency injection, making your application more modular and test-friendly. +`cherrypick_flutter` is a robust Flutter library designed for managing and accessing dependencies using a scope context provided by `CherryPickProvider`. It enhances your application's modularity and testability by simplifying dependency injection. ## Quick Start -### Main Components in Dependency Injection (DI) +### Core Components of Dependency Injection (DI) #### Binding -A Binding is a custom instance configurator, essential for setting up dependencies. It offers the following key methods: +A Binding is a custom instance configurator crucial for setting up dependencies. It offers the following key methods: - `toInstance()`: Directly provides an initialized instance. -- `toProvide()`: Accepts a provider function or constructor for lazy initialization. -- `withName()`: Assigns a name to an instance, allowing for retrieval by name. -- `singleton()`: Marks the instance as a singleton, ensuring only one instance exists in the scope. +- `toProvide()`: Accepts a provider function for lazy initialization. +- `toProvideAsync()`: Accepts an asynchronous provider for lazy initialization. +- `toProvideWithParams()`: Accepts a provider function requiring dynamic parameters. +- `toProvideAsyncWithParams()`: Accepts an asynchronous provider requiring dynamic parameters. +- `withName()`: Assigns a name for instance retrieval by name. +- `singleton()`: Marks the instance as a singleton, ensuring only one instance exists within the scope. ##### Example: ```dart -// Direct instance initialization with toInstance() +// Direct instance initialization using toInstance() Binding().toInstance("hello world"); -// Or use a provider for lazy initialization +// Lazy initialization via provider Binding().toProvide(() => "hello world"); -// Named instance -Binding().withName("my_string").toInstance("hello world"); +// Asynchronous lazy initialization +Binding().toProvideAsync(() async => "hello async world"); + +/ Asynchronous lazy initialization with dynamic parameters +Binding().toProvideAsyncWithParams((params) async => "hello $params"); + +// Initialization with dynamic parameters +Binding().toProvideWithParams((params) => "hello $params"); + +// Named instance for resolution +Binding().toProvide(() => "hello world").withName("my_string").toInstance("hello world"); // Singleton instance Binding().toProvide(() => "hello world").singleton(); @@ -33,7 +45,7 @@ Binding().toProvide(() => "hello world").singleton(); #### Module -A Module encapsulates bindings, allowing you to organize dependencies logically. To create a custom module, implement the `void builder(Scope currentScope)` method. +A Module encapsulates bindings, logically organizing dependencies. Implement the `void builder(Scope currentScope)` method to create a custom module. ##### Example: @@ -48,13 +60,13 @@ class AppModule extends Module { #### Scope -A Scope is the container that manages your dependency tree, holding modules and instances. Use the scope to access dependencies with the `resolve()` method. +A Scope manages your dependency tree, holding modules and instances. Use the scope to access dependencies with `resolve()` or `resolveAsync()` for asynchronous operations. ##### Example: ```dart // Open the main scope -final rootScope = Cherrypick.openRootScope(); +final rootScope = CherryPick.openRootScope(); // Install custom modules rootScope.installModules([AppModule()]); @@ -62,13 +74,16 @@ rootScope.installModules([AppModule()]); // Resolve an instance final str = rootScope.resolve(); +// Asynchronously resolve an instance +final asyncStr = await rootScope.resolveAsync(); + // Close the main scope -Cherrypick.closeRootScope(); +CherryPick.closeRootScope(); ``` ## Example Application -The following example demonstrates module setup, scope management, and dependency resolution. +The following example demonstrates module setup, scope management, and dependency resolution (both synchronous and asynchronous). ```dart import 'dart:async'; @@ -84,26 +99,30 @@ class AppModule extends Module { } class FeatureModule extends Module { - bool isMock; + final bool isMock; FeatureModule({required this.isMock}); @override void builder(Scope currentScope) { + // Using toProvideAsync for async initialization bind() .withName("networkRepo") - .toProvide( - () => NetworkDataRepository( - currentScope.resolve( - named: isMock ? "apiClientMock" : "apiClientImpl", - ), - ), - ) + .toProvideAsync(() async { + final client = await Future.delayed( + Duration(milliseconds: 100), + () => currentScope.resolve( + named: isMock ? "apiClientMock" : "apiClientImpl")); + return NetworkDataRepository(client); + }) .singleton(); - bind().toProvide( - () => DataBloc( - currentScope.resolve(named: "networkRepo"), - ), + + // Asynchronous initialization of DataBloc + bind().toProvideAsync( + () async { + final repo = await currentScope.resolveAsync(named: "networkRepo"); + return DataBloc(repo); + }, ); } } @@ -117,7 +136,8 @@ void main() async { .openSubScope("featureScope") .installModules([FeatureModule(isMock: true)]); - final dataBloc = subScope.resolve(); + // Asynchronous instance resolution + final dataBloc = await subScope.resolveAsync(); dataBloc.data.listen((d) => print('Received data: $d'), onError: (e) => print('Error: $e'), onDone: () => print('DONE')); @@ -128,7 +148,7 @@ class DataBloc { final DataRepository _dataRepository; Stream get data => _dataController.stream; - StreamController _dataController = new StreamController.broadcast(); + StreamController _dataController = StreamController.broadcast(); DataBloc(this._dataRepository); @@ -185,6 +205,8 @@ class ApiClientImpl implements ApiClient { - [x] Main Scope and Sub Scopes - [x] Named Instance Initialization +- [x] Asynchronous Dependency Resolution +- [x] Dynamic Parameter Support for Providers ## Contributing diff --git a/cherrypick/example/bin/main.dart b/cherrypick/example/bin/main.dart index c57e00f..d797948 100644 --- a/cherrypick/example/bin/main.dart +++ b/cherrypick/example/bin/main.dart @@ -1,39 +1,38 @@ import 'dart:async'; - -import 'package:cherrypick/cherrypick.dart'; import 'package:meta/meta.dart'; +import 'package:cherrypick/cherrypick.dart'; class AppModule extends Module { @override void builder(Scope currentScope) { - bind().withName('apiClientMock').toInstance(ApiClientMock()); - bind().withName('apiClientImpl').toInstance(ApiClientImpl()); + bind().withName("apiClientMock").toInstance(ApiClientMock()); + bind().withName("apiClientImpl").toInstance(ApiClientImpl()); } } 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(); + // Using toProvideAsync for async initialization + bind().withName("networkRepo").toProvideAsync(() async { + final client = await Future.delayed( + Duration(milliseconds: 100), + () => currentScope.resolve( + named: isMock ? "apiClientMock" : "apiClientImpl")); + return NetworkDataRepository(client); + }).singleton(); - bind().toProvideWithParams( - (param) => DataBloc( - currentScope.resolve(named: 'networkRepo'), - param, - ), + // Asynchronous initialization of DataBloc + bind().toProvideAsync( + () async { + final repo = await currentScope.resolveAsync( + named: "networkRepo"); + return DataBloc(repo); + }, ); } } @@ -44,10 +43,11 @@ void main() async { ]); final subScope = scope - .openSubScope('featureScope') + .openSubScope("featureScope") .installModules([FeatureModule(isMock: true)]); - final dataBloc = subScope.resolve(params: 'PARAMETER'); + // Asynchronous instance resolution + final dataBloc = await subScope.resolveAsync(); dataBloc.data.listen((d) => print('Received data: $d'), onError: (e) => print('Error: $e'), onDone: () => print('DONE')); @@ -60,13 +60,11 @@ class DataBloc { Stream get data => _dataController.stream; final StreamController _dataController = StreamController.broadcast(); - final String param; - - DataBloc(this._dataRepository, this.param); + DataBloc(this._dataRepository); Future fetchData() async { try { - _dataController.sink.add(await _dataRepository.getData(param)); + _dataController.sink.add(await _dataRepository.getData()); } catch (e) { _dataController.sink.addError(e); } @@ -78,7 +76,7 @@ class DataBloc { } abstract class DataRepository { - Future getData(String param); + Future getData(); } class NetworkDataRepository implements DataRepository { @@ -88,42 +86,26 @@ class NetworkDataRepository implements DataRepository { NetworkDataRepository(this._apiClient); @override - Future getData(String param) async => await _apiClient.sendRequest( - url: 'www.google.com', - token: _token, - requestBody: {'type': 'data'}, - param: param); + Future getData() async => await _apiClient.sendRequest( + url: 'www.google.com', token: _token, requestBody: {'type': 'data'}); } abstract class ApiClient { - Future sendRequest({ - @required String url, - String token, - Map requestBody, - String param, - }); + Future sendRequest({@required String url, String token, Map requestBody}); } class ApiClientMock implements ApiClient { @override - Future sendRequest({ - @required String? url, - String? token, - Map? requestBody, - String? param, - }) async { - return 'Local Data $param'; + Future sendRequest( + {@required String? url, String? token, Map? requestBody}) async { + return 'Local Data'; } } class ApiClientImpl implements ApiClient { @override - Future sendRequest({ - @required String? url, - String? token, - Map? requestBody, - String? param, - }) async { - return 'Network data $param'; + Future sendRequest( + {@required String? url, String? token, Map? requestBody}) async { + return 'Network data'; } } 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); + } } diff --git a/cherrypick/pubspec.yaml b/cherrypick/pubspec.yaml index 3e0545e..e5bbc6c 100644 --- a/cherrypick/pubspec.yaml +++ b/cherrypick/pubspec.yaml @@ -1,6 +1,6 @@ name: cherrypick description: Cherrypick is a small dependency injection (DI) library for dart/flutter projects. -version: 2.0.2 +version: 2.1.0-dev.1 homepage: https://pese-git.github.io/cherrypick-site/ documentation: https://github.com/pese-git/cherrypick/wiki repository: https://github.com/pese-git/cherrypick @@ -13,9 +13,8 @@ dependencies: meta: ^1.3.0 dev_dependencies: - #pedantic: ^1.11.0 - - test: ^1.17.2 + lints: ^5.0.0 + test: ^1.25.15 mockito: ^5.0.6 - lints: ^2.1.0 + melos: ^6.3.2 diff --git a/cherrypick/test/src/binding_test.dart b/cherrypick/test/src/binding_test.dart index 34d6c60..9f69647 100644 --- a/cherrypick/test/src/binding_test.dart +++ b/cherrypick/test/src/binding_test.dart @@ -188,6 +188,25 @@ void main() { }); }); + group('Check Async provider.', () { + test('Binding resolves value asynchronously', () async { + final expectedValue = 5; + final binding = Binding().toProvideAsync(() async => expectedValue); + + final result = await binding.asyncProvider?.call(); + expect(result, expectedValue); + }); + + test('Binding resolves value asynchronously with params', () async { + final expectedValue = 5; + final binding = Binding().toProvideAsyncWithParams( + (param) async => expectedValue + (param as int)); + + final result = await binding.asyncProviderWithParams?.call(3); + expect(result, expectedValue + 3); + }); + }); + group('Check singleton provide.', () { group('Without name.', () { test('Binding resolves null', () { diff --git a/cherrypick_flutter/CHANGELOG.md b/cherrypick_flutter/CHANGELOG.md index ff755cf..27e4698 100644 --- a/cherrypick_flutter/CHANGELOG.md +++ b/cherrypick_flutter/CHANGELOG.md @@ -1,4 +1,8 @@ -## 1.1.1 +## 1.1.1-dev.1 + + - **FIX**: fix warnings. + +## 1.1.1-dev.0 - Update a dependency to the latest release. diff --git a/cherrypick_flutter/README.md b/cherrypick_flutter/README.md index 8e39632..56aef3d 100644 --- a/cherrypick_flutter/README.md +++ b/cherrypick_flutter/README.md @@ -1,6 +1,6 @@ # CherryPick Flutter -`cherrypick_flutter` is a Flutter library that allows access to the root scope through the context using `CherryPickProvider`. This package is designed to provide a simple and convenient way to interact with the root scope within the widget tree. +`cherrypick_flutter` offers a Flutter integration to access and manage dependency injection scopes using the `CherryPickProvider`. This setup facilitates accessing the root scope directly from the widget tree, providing a straightforward mechanism for dependences management within Flutter applications. ## Installation @@ -11,13 +11,13 @@ dependencies: cherrypick_flutter: ^1.0.0 ``` -Then run `flutter pub get` to install the package. +Run `flutter pub get` to install the package dependencies. ## Usage ### Importing the Package -To start using `cherrypick_flutter`, import it into your Dart code: +To begin using `cherrypick_flutter`, import it within your Dart file: ```dart import 'package:cherrypick_flutter/cherrypick_flutter.dart'; @@ -25,7 +25,7 @@ import 'package:cherrypick_flutter/cherrypick_flutter.dart'; ### Providing State with `CherryPickProvider` -Use `CherryPickProvider` to wrap the part of the widget tree that requires access to the provided state. +Use `CherryPickProvider` to encase the widget tree section that requires access to the root or specific subscopes: ```dart import 'package:flutter/material.dart'; @@ -34,35 +34,40 @@ import 'package:cherrypick_flutter/cherrypick_flutter.dart'; void main() { runApp( CherryPickProvider( - rootScope: yourRootScopeInstance, child: MyApp(), ), ); } ``` +Note: The current implementation of `CherryPickProvider` does not directly pass a `rootScope`. Instead, it utilizes its methods to open root and sub-scopes internally. + ### Accessing State -To access the state provided by `CherryPickProvider`, use the `of` method. This is typically done in the `build` method of your widgets. +Access the state provided by `CherryPickProvider` within widget `build` methods using the `of` method: ```dart class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final rootScope = CherryPickProvider.of(context).rootScope; + final CherryPickProvider cherryPick = CherryPickProvider.of(context); + final rootScope = cherryPick.openRootScope(); - return Text('Current state: ${rootScope.someStateValue}'); + // Use the rootScope or open a subScope as needed + final subScope = cherryPick.openSubScope(scopeName: "exampleScope"); + + return Text('Scope accessed!'); } } ``` ### Updating State -The `CherryPickProvider` will automatically update its dependents when its state changes. Ensure to override the `updateShouldNotify` method to specify when notifications should occur, as shown in the provided implementation. +The `CherryPickProvider` setup internally manages state updates. Ensure the `updateShouldNotify` method accurately reflects when the dependents should receive updates. In the provided implementation, it currently does not notify updates automatically. ## Example -Here is a simple example showing how to implement and use the `CherryPickProvider`. +Here is an example illustrating how to implement and utilize `CherryPickProvider` within a Flutter application: ```dart class MyApp extends StatelessWidget { @@ -70,7 +75,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - final rootScope = CherryPickProvider.of(context).rootScope; + final rootScope = CherryPickProvider.of(context).openRootScope(); return MaterialApp.router( routerDelegate: rootScope.resolve().delegate(), @@ -81,10 +86,12 @@ class MyApp extends StatelessWidget { } ``` +In this example, `CherryPickProvider` accesses and resolves dependencies using root scope and potentially sub-scopes configured by the application. + ## Contributing -We welcome contributions from the community. Please open issues and pull requests if you have ideas for improvements. +Contributions to improve this library are welcome. Feel free to open issues and submit pull requests on the repository. ## License -This project is licensed under the Apache License 2.0. \ No newline at end of file +This project is licensed under the Apache License 2.0. A copy of the license can be obtained at [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). \ No newline at end of file diff --git a/cherrypick_flutter/pubspec.yaml b/cherrypick_flutter/pubspec.yaml index 2cd3d97..d2edca6 100644 --- a/cherrypick_flutter/pubspec.yaml +++ b/cherrypick_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: cherrypick_flutter description: "Flutter library that allows access to the root scope through the context using `CherryPickProvider`." -version: 1.1.1 +version: 1.1.1-dev.1 homepage: https://pese-git.github.io/cherrypick-site/ documentation: https://github.com/pese-git/cherrypick/wiki repository: https://github.com/pese-git/cherrypick @@ -13,12 +13,14 @@ environment: dependencies: flutter: sdk: flutter - cherrypick: ^2.0.2 + cherrypick: ^2.1.0-dev.1 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ^5.0.0 + test: ^1.25.7 + melos: ^6.3.2 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/examples/client_app/.gitignore b/examples/client_app/.gitignore new file mode 100644 index 0000000..80ad3a6 --- /dev/null +++ b/examples/client_app/.gitignore @@ -0,0 +1,52 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + + +pubspec_overrides.yaml + + +**/*.g.dart +**/*.gr.dart +**/*.freezed.dart + diff --git a/examples/client_app/.metadata b/examples/client_app/.metadata new file mode 100644 index 0000000..8a64edc --- /dev/null +++ b/examples/client_app/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "4cf269e36de2573851eaef3c763994f8f9be494d" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + - platform: web + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/examples/client_app/README.md b/examples/client_app/README.md new file mode 100644 index 0000000..d283d78 --- /dev/null +++ b/examples/client_app/README.md @@ -0,0 +1,16 @@ +# client_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/examples/client_app/analysis_options.yaml b/examples/client_app/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/examples/client_app/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/examples/client_app/lib/main.dart b/examples/client_app/lib/main.dart new file mode 100644 index 0000000..e7d6783 --- /dev/null +++ b/examples/client_app/lib/main.dart @@ -0,0 +1,41 @@ +import 'package:cherrypick/cherrypick.dart'; +import 'package:flutter/material.dart'; +import 'package:cherrypick_flutter/cherrypick_flutter.dart'; +import 'my_home_page.dart'; +import 'use_case.dart'; + +void main() { + // Здесь происходит инициализация рутового скоупа и привязка зависимостей + CherryPick.openRootScope().installModules([ + // Создаем модуль, который будет предоставлять UseCase + ModuleWithUseCase(), + ]); + + runApp( + const CherryPickProvider( + child: MyApp(), + ), + ); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Example App', + theme: ThemeData(primarySwatch: Colors.blue), + home: const MyHomePage(), + ); + } +} + +// Модуль для настройки зависимостей +class ModuleWithUseCase extends Module { + @override + void builder(Scope currentScope) { + // Привязка UseCase как singleton + bind().toInstance(UseCase()); + } +} diff --git a/examples/client_app/lib/my_home_page.dart b/examples/client_app/lib/my_home_page.dart new file mode 100644 index 0000000..91aaea4 --- /dev/null +++ b/examples/client_app/lib/my_home_page.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:cherrypick_flutter/cherrypick_flutter.dart'; +import 'use_case.dart'; + +class MyHomePage extends StatelessWidget { + const MyHomePage({super.key}); + + @override + Widget build(BuildContext context) { + // Разрешение зависимости UseCase из рутового скоупа + final UseCase useCase = + CherryPickProvider.of(context).openRootScope().resolve(); + + return Scaffold( + appBar: AppBar( + title: const Text('Example App'), + ), + body: Center( + child: Text(useCase.fetchData()), + ), + ); + } +} diff --git a/examples/client_app/lib/use_case.dart b/examples/client_app/lib/use_case.dart new file mode 100644 index 0000000..be97fdf --- /dev/null +++ b/examples/client_app/lib/use_case.dart @@ -0,0 +1,3 @@ +class UseCase { + String fetchData() => "Data fetched by UseCase"; +} diff --git a/examples/client_app/pubspec.lock b/examples/client_app/pubspec.lock new file mode 100644 index 0000000..02b6015 --- /dev/null +++ b/examples/client_app/pubspec.lock @@ -0,0 +1,229 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + cherrypick: + dependency: "direct main" + description: + name: cherrypick + sha256: e1e2b4f3a70cbe7760e479e6ddb7dce2fc85a1bbb2fba6c398efe235ed111dfe + url: "https://pub.dev" + source: hosted + version: "2.0.2" + cherrypick_flutter: + dependency: "direct main" + description: + name: cherrypick_flutter + sha256: ad63ae816b7d1147ffb0a82bcae5a1ea3d51e9d398a79459c619464391a43a79 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" +sdks: + dart: ">=3.5.2 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/examples/client_app/pubspec.yaml b/examples/client_app/pubspec.yaml new file mode 100644 index 0000000..b7254d5 --- /dev/null +++ b/examples/client_app/pubspec.yaml @@ -0,0 +1,65 @@ +name: client_app +description: "A new Flutter project." +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: ^3.5.2 + + +dependencies: + flutter: + sdk: flutter + cherrypick: any + cherrypick_flutter: any + + cupertino_icons: ^1.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^4.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/examples/client_app/test/widget_test.dart b/examples/client_app/test/widget_test.dart new file mode 100644 index 0000000..525ba55 --- /dev/null +++ b/examples/client_app/test/widget_test.dart @@ -0,0 +1,31 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +//import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +//import 'package:client_app/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + expect(1, 1); + // Build our app and trigger a frame. + //await tester.pumpWidget(const MyApp()); + + //// Verify that our counter starts at 0. + //expect(find.text('0'), findsOneWidget); + //expect(find.text('1'), findsNothing); + + //// Tap the '+' icon and trigger a frame. + //await tester.tap(find.byIcon(Icons.add)); + //await tester.pump(); + + //// Verify that our counter has incremented. + //expect(find.text('0'), findsNothing); + //expect(find.text('1'), findsOneWidget); + }); +} diff --git a/examples/client_app/web/favicon.png b/examples/client_app/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/examples/client_app/web/favicon.png differ diff --git a/examples/client_app/web/icons/Icon-192.png b/examples/client_app/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/examples/client_app/web/icons/Icon-192.png differ diff --git a/examples/client_app/web/icons/Icon-512.png b/examples/client_app/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/examples/client_app/web/icons/Icon-512.png differ diff --git a/examples/client_app/web/icons/Icon-maskable-192.png b/examples/client_app/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/examples/client_app/web/icons/Icon-maskable-192.png differ diff --git a/examples/client_app/web/icons/Icon-maskable-512.png b/examples/client_app/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/examples/client_app/web/icons/Icon-maskable-512.png differ diff --git a/examples/client_app/web/index.html b/examples/client_app/web/index.html new file mode 100644 index 0000000..5ae0cf1 --- /dev/null +++ b/examples/client_app/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + client_app + + + + + + diff --git a/examples/client_app/web/manifest.json b/examples/client_app/web/manifest.json new file mode 100644 index 0000000..f053ae5 --- /dev/null +++ b/examples/client_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "client_app", + "short_name": "client_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/examples/postly/.gitignore b/examples/postly/.gitignore new file mode 100644 index 0000000..b3e4432 --- /dev/null +++ b/examples/postly/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + + +**/*.g.dart +**/*.gr.dart +**/*.freezed.dart \ No newline at end of file diff --git a/examples/postly/.metadata b/examples/postly/.metadata new file mode 100644 index 0000000..8a64edc --- /dev/null +++ b/examples/postly/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "4cf269e36de2573851eaef3c763994f8f9be494d" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + - platform: web + create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/examples/postly/README.md b/examples/postly/README.md new file mode 100644 index 0000000..8a01f2c --- /dev/null +++ b/examples/postly/README.md @@ -0,0 +1,16 @@ +# postly + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/examples/postly/analysis_options.yaml b/examples/postly/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/examples/postly/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/examples/postly/devtools_options.yaml b/examples/postly/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/examples/postly/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/examples/postly/lib/data/model/post_model.dart b/examples/postly/lib/data/model/post_model.dart new file mode 100644 index 0000000..54e9bb3 --- /dev/null +++ b/examples/postly/lib/data/model/post_model.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'post_model.freezed.dart'; +part 'post_model.g.dart'; + +@freezed +class PostModel with _$PostModel { + const factory PostModel({ + required int id, + required String title, + required String body, + }) = _PostModel; + + factory PostModel.fromJson(Map json) => + _$PostModelFromJson(json); +} diff --git a/examples/postly/lib/data/network/json_placeholder_api.dart b/examples/postly/lib/data/network/json_placeholder_api.dart new file mode 100644 index 0000000..d80c140 --- /dev/null +++ b/examples/postly/lib/data/network/json_placeholder_api.dart @@ -0,0 +1,17 @@ +import 'package:retrofit/retrofit.dart'; +import 'package:dio/dio.dart'; + +import '../model/post_model.dart'; + +part 'json_placeholder_api.g.dart'; + +@RestApi(baseUrl: 'https://jsonplaceholder.typicode.com/') +abstract class JsonPlaceholderApi { + factory JsonPlaceholderApi(Dio dio, {String baseUrl}) = _JsonPlaceholderApi; + + @GET('/posts') + Future> getPosts(); + + @GET('/posts/{id}') + Future getPost(@Path('id') int id); +} diff --git a/examples/postly/lib/data/post_repository_impl.dart b/examples/postly/lib/data/post_repository_impl.dart new file mode 100644 index 0000000..75d0473 --- /dev/null +++ b/examples/postly/lib/data/post_repository_impl.dart @@ -0,0 +1,32 @@ +import 'package:dartz/dartz.dart'; +import '../domain/entity/post.dart'; +import '../domain/repository/post_repository.dart'; +import 'network/json_placeholder_api.dart'; + +class PostRepositoryImpl implements PostRepository { + final JsonPlaceholderApi api; + + PostRepositoryImpl(this.api); + + @override + Future>> getPosts() async { + try { + final posts = await api.getPosts(); + return Right(posts + .map((e) => Post(id: e.id, title: e.title, body: e.body)) + .toList()); + } catch (e) { + return Left(Exception(e.toString())); + } + } + + @override + Future> getPost(int id) async { + try { + final post = await api.getPost(id); + return Right(Post(id: post.id, title: post.title, body: post.body)); + } catch (e) { + return Left(Exception(e.toString())); + } + } +} diff --git a/examples/postly/lib/di/app_module.dart b/examples/postly/lib/di/app_module.dart new file mode 100644 index 0000000..5dd9637 --- /dev/null +++ b/examples/postly/lib/di/app_module.dart @@ -0,0 +1,21 @@ +import 'package:dio/dio.dart'; +import 'package:cherrypick/cherrypick.dart'; +import '../data/network/json_placeholder_api.dart'; +import '../data/post_repository_impl.dart'; +import '../domain/repository/post_repository.dart'; + +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().toProvide(() => Dio()).singleton(); + + bind() + .toProvide(() => JsonPlaceholderApi(currentScope.resolve())) + .singleton(); + + bind() + .toProvide(() => + PostRepositoryImpl(currentScope.resolve())) + .singleton(); + } +} diff --git a/examples/postly/lib/domain/entity/post.dart b/examples/postly/lib/domain/entity/post.dart new file mode 100644 index 0000000..6b67884 --- /dev/null +++ b/examples/postly/lib/domain/entity/post.dart @@ -0,0 +1,12 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'post.freezed.dart'; + +@freezed +class Post with _$Post { + const factory Post({ + required int id, + required String title, + required String body, + }) = _Post; +} diff --git a/examples/postly/lib/domain/repository/post_repository.dart b/examples/postly/lib/domain/repository/post_repository.dart new file mode 100644 index 0000000..65d22ad --- /dev/null +++ b/examples/postly/lib/domain/repository/post_repository.dart @@ -0,0 +1,7 @@ +import 'package:dartz/dartz.dart'; +import '../entity/post.dart'; + +abstract class PostRepository { + Future>> getPosts(); + Future> getPost(int id); +} diff --git a/examples/postly/lib/main.dart b/examples/postly/lib/main.dart new file mode 100644 index 0000000..394fbc2 --- /dev/null +++ b/examples/postly/lib/main.dart @@ -0,0 +1,36 @@ +import 'package:cherrypick/cherrypick.dart'; +import 'package:flutter/material.dart'; +import 'di/app_module.dart'; +import 'domain/repository/post_repository.dart'; +import 'presentation/bloc/post_bloc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'router/app_router.dart'; + +void main() { + final scope = CherryPick.openRootScope(); + scope.installModules([AppModule()]); + + runApp(MyApp(scope: scope)); +} + +class MyApp extends StatelessWidget { + final Scope scope; + final _appRouter = AppRouter(); + + MyApp({super.key, required this.scope}); + + @override + Widget build(BuildContext context) { + // Получаем репозиторий через injector + final repository = scope.resolve(); + + return BlocProvider( + create: (_) => PostBloc(repository), + child: MaterialApp.router( + routeInformationParser: _appRouter.defaultRouteParser(), + routerDelegate: _appRouter.delegate(), + theme: ThemeData.light(), + ), + ); + } +} diff --git a/examples/postly/lib/presentation/bloc/post_bloc.dart b/examples/postly/lib/presentation/bloc/post_bloc.dart new file mode 100644 index 0000000..b6e23ed --- /dev/null +++ b/examples/postly/lib/presentation/bloc/post_bloc.dart @@ -0,0 +1,38 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../domain/entity/post.dart'; +import '../../domain/repository/post_repository.dart'; + +part 'post_bloc.freezed.dart'; + +@freezed +class PostEvent with _$PostEvent { + const factory PostEvent.fetchAll() = _FetchAll; +} + +@freezed +class PostState with _$PostState { + const factory PostState.initial() = _Initial; + const factory PostState.loading() = _Loading; + const factory PostState.loaded(List posts) = _Loaded; + const factory PostState.failure(String message) = _Failure; +} + +class PostBloc extends Bloc { + final PostRepository repository; + + PostBloc(this.repository) : super(const PostState.initial()) { + on((event, emit) async { + await event.map( + fetchAll: (e) async { + emit(const PostState.loading()); + final result = await repository.getPosts(); + result.fold( + (l) => emit(PostState.failure(l.toString())), + (r) => emit(PostState.loaded(r)), + ); + }, + ); + }); + } +} diff --git a/examples/postly/lib/presentation/pages/post_details_page.dart b/examples/postly/lib/presentation/pages/post_details_page.dart new file mode 100644 index 0000000..3814a63 --- /dev/null +++ b/examples/postly/lib/presentation/pages/post_details_page.dart @@ -0,0 +1,21 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import '../../domain/entity/post.dart'; + +@RoutePage() +class PostDetailsPage extends StatelessWidget { + final Post post; + + const PostDetailsPage({super.key, required this.post}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Post #${post.id}')), + body: Padding( + padding: const EdgeInsets.all(16), + child: Text(post.body), + ), + ); + } +} diff --git a/examples/postly/lib/presentation/pages/posts_page.dart b/examples/postly/lib/presentation/pages/posts_page.dart new file mode 100644 index 0000000..4cd11fc --- /dev/null +++ b/examples/postly/lib/presentation/pages/posts_page.dart @@ -0,0 +1,42 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../router/app_router.gr.dart'; +import '../bloc/post_bloc.dart'; + +@RoutePage() +class PostsPage extends StatelessWidget { + const PostsPage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => + context.read()..add(const PostEvent.fetchAll()), + child: Scaffold( + appBar: AppBar(title: const Text('Posts')), + body: BlocBuilder( + builder: (context, state) { + return state.when( + initial: () => const SizedBox.shrink(), + loading: () => const Center(child: CircularProgressIndicator()), + loaded: (posts) => ListView.builder( + itemCount: posts.length, + itemBuilder: (ctx, i) => ListTile( + title: Text(posts[i].title), + subtitle: Text(posts[i].body), + onTap: () { + AutoRouter.of(context) + .push(PostDetailsRoute(post: posts[i])); + }, + ), + ), + failure: (msg) => Center(child: Text('Error: $msg')), + ); + }, + ), + ), + ); + } +} diff --git a/examples/postly/lib/router/app_router.dart b/examples/postly/lib/router/app_router.dart new file mode 100644 index 0000000..c62f499 --- /dev/null +++ b/examples/postly/lib/router/app_router.dart @@ -0,0 +1,12 @@ +import 'package:auto_route/auto_route.dart'; + +import 'app_router.gr.dart'; + +@AutoRouterConfig() +class AppRouter extends $AppRouter { + @override + List get routes => [ + AutoRoute(page: PostsRoute.page, initial: true), + AutoRoute(page: PostDetailsRoute.page), + ]; +} diff --git a/examples/postly/pubspec.lock b/examples/postly/pubspec.lock new file mode 100644 index 0000000..3fcb01b --- /dev/null +++ b/examples/postly/pubspec.lock @@ -0,0 +1,730 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + url: "https://pub.dev" + source: hosted + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + url: "https://pub.dev" + source: hosted + version: "6.7.0" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + auto_route: + dependency: "direct main" + description: + name: auto_route + sha256: eb33554581a0a4aa7e6da0f13a44291a55bf71359012f1d9feb41634ff908ff8 + url: "https://pub.dev" + source: hosted + version: "7.9.2" + auto_route_generator: + dependency: "direct dev" + description: + name: auto_route_generator + sha256: "11067a3bcd643812518fe26c0c9ec073990286cabfd9d74b6da9ef9b913c4d22" + url: "https://pub.dev" + source: hosted + version: "7.3.2" + bloc: + dependency: transitive + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + url: "https://pub.dev" + source: hosted + version: "2.4.13" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + url: "https://pub.dev" + source: hosted + version: "7.3.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 + url: "https://pub.dev" + source: hosted + version: "8.9.5" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cherrypick: + dependency: "direct main" + description: + name: cherrypick + sha256: e1e2b4f3a70cbe7760e479e6ddb7dce2fc85a1bbb2fba6c398efe235ed111dfe + url: "https://pub.dev" + source: hosted + version: "2.0.2" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" + url: "https://pub.dev" + source: hosted + version: "2.3.7" + dartz: + dependency: "direct main" + description: + name: dartz + sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + dio: + dependency: "direct main" + description: + name: dio + sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + url: "https://pub.dev" + source: hosted + version: "5.8.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" + url: "https://pub.dev" + source: hosted + version: "2.5.7" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c + url: "https://pub.dev" + source: hosted + version: "6.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + protobuf: + dependency: transitive + description: + name: protobuf + sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + retrofit: + dependency: "direct main" + description: + name: retrofit + sha256: c6cc9ad3374e6d07008343140a67afffaaa34cdf6bf08d4847d91417a99dcf45 + url: "https://pub.dev" + source: hosted + version: "4.4.2" + retrofit_generator: + dependency: "direct dev" + description: + name: retrofit_generator + sha256: "8dfc406cdfa171f33cbd21bf5bd8b6763548cc217de19cdeaa07a76727fac4ca" + url: "https://pub.dev" + source: hosted + version: "8.2.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" + url: "https://pub.dev" + source: hosted + version: "1.3.5" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.5.2 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/examples/postly/pubspec.yaml b/examples/postly/pubspec.yaml new file mode 100644 index 0000000..fd996c3 --- /dev/null +++ b/examples/postly/pubspec.yaml @@ -0,0 +1,40 @@ +name: postly +description: "A new Flutter project." +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: ^3.5.2 + + +dependencies: + flutter: + sdk: flutter + + cherrypick: any + + dio: ^5.4.0 + retrofit: ^4.0.3 + freezed_annotation: ^2.0.0 + dartz: ^0.10.1 + flutter_bloc: ^8.1.2 + auto_route: ^7.8.4 + + cupertino_icons: ^1.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^4.0.0 + + build_runner: ^2.4.6 + retrofit_generator: ^8.0.4 + freezed: ^2.3.2 + json_serializable: any + auto_route_generator: ^7.3.2 + +flutter: + + uses-material-design: true diff --git a/examples/postly/test/widget_test.dart b/examples/postly/test/widget_test.dart new file mode 100644 index 0000000..6ac7ee0 --- /dev/null +++ b/examples/postly/test/widget_test.dart @@ -0,0 +1,41 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:cherrypick/cherrypick.dart'; +//import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:postly/di/app_module.dart'; + +//import 'package:postly/main.dart'; + +void main() { + late Scope scope; + + setUp(() { + scope = CherryPick.openRootScope(); + scope.installModules([AppModule()]); + }); + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + expect(1, 1); + // Build our app and trigger a frame. + //await tester.pumpWidget(MyApp( + // scope: scope, + //)); + + //// Verify that our counter starts at 0. + //expect(find.text('0'), findsOneWidget); + //expect(find.text('1'), findsNothing); + + //// Tap the '+' icon and trigger a frame. + //await tester.tap(find.byIcon(Icons.add)); + //await tester.pump(); + + //// Verify that our counter has incremented. + //expect(find.text('0'), findsNothing); + //expect(find.text('1'), findsOneWidget); + }); +} diff --git a/examples/postly/web/favicon.png b/examples/postly/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/examples/postly/web/favicon.png differ diff --git a/examples/postly/web/icons/Icon-192.png b/examples/postly/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/examples/postly/web/icons/Icon-192.png differ diff --git a/examples/postly/web/icons/Icon-512.png b/examples/postly/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/examples/postly/web/icons/Icon-512.png differ diff --git a/examples/postly/web/icons/Icon-maskable-192.png b/examples/postly/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/examples/postly/web/icons/Icon-maskable-192.png differ diff --git a/examples/postly/web/icons/Icon-maskable-512.png b/examples/postly/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/examples/postly/web/icons/Icon-maskable-512.png differ diff --git a/examples/postly/web/index.html b/examples/postly/web/index.html new file mode 100644 index 0000000..5dc7f46 --- /dev/null +++ b/examples/postly/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + postly + + + + + + diff --git a/examples/postly/web/manifest.json b/examples/postly/web/manifest.json new file mode 100644 index 0000000..341aaae --- /dev/null +++ b/examples/postly/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "postly", + "short_name": "postly", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/melos.yaml b/melos.yaml index b0165cf..bd3a823 100644 --- a/melos.yaml +++ b/melos.yaml @@ -5,11 +5,20 @@ sdkPath: .fvm/flutter_sdk packages: - cherrypick - cherrypick_flutter + - examples/client_app + - examples/postly scripts: analyze: - run: | - flutter analyze + exec: dart analyze + format: + exec: dart format + + test: + exec: flutter test + + codegen: run: | - flutter format \ No newline at end of file + melos exec --scope="postly" -- dart run build_runner build --delete-conflicting-outputs +