mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-23 21:13:35 +00:00
Compare commits
8 Commits
c483d8c9e2
...
cherrypick
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
009808975e | ||
|
|
e3eb0eef06 | ||
|
|
32bda69476 | ||
|
|
d24d6e3f2b | ||
|
|
1f08231402 | ||
|
|
09de8bca98 | ||
|
|
b3660eee93 | ||
|
|
62c8b2247b |
30
CHANGELOG.md
30
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
|
||||
|
||||
3
cherrypick/.gitignore
vendored
3
cherrypick/.gitignore
vendored
@@ -19,3 +19,6 @@ doc/api/
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
|
||||
# FVM Version Cache
|
||||
.fvm/
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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<String>().toInstance("hello world");
|
||||
|
||||
// Or use a provider for lazy initialization
|
||||
// Lazy initialization via provider
|
||||
Binding<String>().toProvide(() => "hello world");
|
||||
|
||||
// Named instance
|
||||
Binding<String>().withName("my_string").toInstance("hello world");
|
||||
// Asynchronous lazy initialization
|
||||
Binding<String>().toProvideAsync(() async => "hello async world");
|
||||
|
||||
/ Asynchronous lazy initialization with dynamic parameters
|
||||
Binding<String>().toProvideAsyncWithParams((params) async => "hello $params");
|
||||
|
||||
// Initialization with dynamic parameters
|
||||
Binding<String>().toProvideWithParams((params) => "hello $params");
|
||||
|
||||
// Named instance for resolution
|
||||
Binding<String>().toProvide(() => "hello world").withName("my_string").toInstance("hello world");
|
||||
|
||||
// Singleton instance
|
||||
Binding<String>().toProvide(() => "hello world").singleton();
|
||||
@@ -33,7 +45,7 @@ Binding<String>().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<T>()` method.
|
||||
A Scope manages your dependency tree, holding modules and instances. Use the scope to access dependencies with `resolve<T>()` or `resolveAsync<T>()` 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<String>();
|
||||
|
||||
// Asynchronously resolve an instance
|
||||
final asyncStr = await rootScope.resolveAsync<String>();
|
||||
|
||||
// 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<DataRepository>()
|
||||
.withName("networkRepo")
|
||||
.toProvide(
|
||||
() => NetworkDataRepository(
|
||||
currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl",
|
||||
),
|
||||
),
|
||||
)
|
||||
.toProvideAsync(() async {
|
||||
final client = await Future.delayed(
|
||||
Duration(milliseconds: 100),
|
||||
() => currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl"));
|
||||
return NetworkDataRepository(client);
|
||||
})
|
||||
.singleton();
|
||||
bind<DataBloc>().toProvide(
|
||||
() => DataBloc(
|
||||
currentScope.resolve<DataRepository>(named: "networkRepo"),
|
||||
),
|
||||
|
||||
// Asynchronous initialization of DataBloc
|
||||
bind<DataBloc>().toProvideAsync(
|
||||
() async {
|
||||
final repo = await currentScope.resolveAsync<DataRepository>(named: "networkRepo");
|
||||
return DataBloc(repo);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +136,8 @@ void main() async {
|
||||
.openSubScope("featureScope")
|
||||
.installModules([FeatureModule(isMock: true)]);
|
||||
|
||||
final dataBloc = subScope.resolve<DataBloc>();
|
||||
// Asynchronous instance resolution
|
||||
final dataBloc = await subScope.resolveAsync<DataBloc>();
|
||||
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<String> get data => _dataController.stream;
|
||||
StreamController<String> _dataController = new StreamController.broadcast();
|
||||
StreamController<String> _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
|
||||
|
||||
|
||||
@@ -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<ApiClient>().withName('apiClientMock').toInstance(ApiClientMock());
|
||||
bind<ApiClient>().withName('apiClientImpl').toInstance(ApiClientImpl());
|
||||
bind<ApiClient>().withName("apiClientMock").toInstance(ApiClientMock());
|
||||
bind<ApiClient>().withName("apiClientImpl").toInstance(ApiClientImpl());
|
||||
}
|
||||
}
|
||||
|
||||
class FeatureModule extends Module {
|
||||
bool isMock;
|
||||
final bool isMock;
|
||||
|
||||
FeatureModule({required this.isMock});
|
||||
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<DataRepository>()
|
||||
.withName('networkRepo')
|
||||
.toProvide(
|
||||
() => NetworkDataRepository(
|
||||
currentScope.resolve<ApiClient>(
|
||||
named: isMock ? 'apiClientMock' : 'apiClientImpl',
|
||||
),
|
||||
),
|
||||
)
|
||||
.singleton();
|
||||
// Using toProvideAsync for async initialization
|
||||
bind<DataRepository>().withName("networkRepo").toProvideAsync(() async {
|
||||
final client = await Future.delayed(
|
||||
Duration(milliseconds: 100),
|
||||
() => currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl"));
|
||||
return NetworkDataRepository(client);
|
||||
}).singleton();
|
||||
|
||||
bind<DataBloc>().toProvideWithParams(
|
||||
(param) => DataBloc(
|
||||
currentScope.resolve<DataRepository>(named: 'networkRepo'),
|
||||
param,
|
||||
),
|
||||
// Asynchronous initialization of DataBloc
|
||||
bind<DataBloc>().toProvideAsync(
|
||||
() async {
|
||||
final repo = await currentScope.resolveAsync<DataRepository>(
|
||||
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<DataBloc>(params: 'PARAMETER');
|
||||
// Asynchronous instance resolution
|
||||
final dataBloc = await subScope.resolveAsync<DataBloc>();
|
||||
dataBloc.data.listen((d) => print('Received data: $d'),
|
||||
onError: (e) => print('Error: $e'), onDone: () => print('DONE'));
|
||||
|
||||
@@ -60,13 +60,11 @@ class DataBloc {
|
||||
Stream<String> get data => _dataController.stream;
|
||||
final StreamController<String> _dataController = StreamController.broadcast();
|
||||
|
||||
final String param;
|
||||
|
||||
DataBloc(this._dataRepository, this.param);
|
||||
DataBloc(this._dataRepository);
|
||||
|
||||
Future<void> 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<String> getData(String param);
|
||||
Future<String> getData();
|
||||
}
|
||||
|
||||
class NetworkDataRepository implements DataRepository {
|
||||
@@ -88,42 +86,26 @@ class NetworkDataRepository implements DataRepository {
|
||||
NetworkDataRepository(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<String> getData(String param) async => await _apiClient.sendRequest(
|
||||
url: 'www.google.com',
|
||||
token: _token,
|
||||
requestBody: {'type': 'data'},
|
||||
param: param);
|
||||
Future<String> 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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library cherrypick;
|
||||
library;
|
||||
|
||||
//
|
||||
// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com)
|
||||
|
||||
@@ -15,6 +15,10 @@ enum Mode { simple, instance, providerInstance, providerInstanceWithParams }
|
||||
|
||||
typedef ProviderWithParams<T> = T Function(dynamic params);
|
||||
|
||||
typedef AsyncProvider<T> = Future<T> Function();
|
||||
|
||||
typedef AsyncProviderWithParams<T> = Future<T> Function(dynamic params);
|
||||
|
||||
/// RU: Класс Binding<T> настраивает параметры экземпляра.
|
||||
/// ENG: The Binding<T> class configures the settings for the instance.
|
||||
///
|
||||
@@ -24,6 +28,9 @@ class Binding<T> {
|
||||
late String _name;
|
||||
T? _instance;
|
||||
T? Function()? _provider;
|
||||
AsyncProvider<T>? asyncProvider;
|
||||
AsyncProviderWithParams<T>? asyncProviderWithParams;
|
||||
|
||||
ProviderWithParams<T>? _providerWithParams;
|
||||
late bool _isSingleton = false;
|
||||
late bool _isNamed = false;
|
||||
@@ -94,6 +101,16 @@ class Binding<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/// RU: Инициализация экземляпяра через провайдер [value].
|
||||
/// ENG: Initialization instance via provider [value].
|
||||
///
|
||||
/// return [Binding]
|
||||
Binding<T> toProvideAsync(AsyncProvider<T> 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<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/// RU: Инициализация экземляра через асинхронный провайдер [value] с динамическим параметром.
|
||||
/// ENG: Initializes the instance via async provider [value] with a dynamic param.
|
||||
///
|
||||
/// return [Binding]
|
||||
Binding<T> toProvideAsyncWithParams(AsyncProviderWithParams<T> provider) {
|
||||
_mode = Mode.providerInstanceWithParams;
|
||||
asyncProviderWithParams = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// RU: Инициализация экземляпяра как сингелтон [value].
|
||||
/// ENG: Initialization instance as a singelton [value].
|
||||
///
|
||||
|
||||
@@ -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<T> resolveAsync<T>({String? named, dynamic params}) async {
|
||||
var resolved = await tryResolveAsync<T>(named: named, params: params);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
} else {
|
||||
throw StateError(
|
||||
'Can\'t resolve async dependency `$T`. Maybe you forget register it?');
|
||||
}
|
||||
}
|
||||
|
||||
Future<T?> tryResolveAsync<T>({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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -188,6 +188,25 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('Check Async provider.', () {
|
||||
test('Binding resolves value asynchronously', () async {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().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<int>().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', () {
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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<AppRouter>().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.
|
||||
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).
|
||||
@@ -1,3 +1,5 @@
|
||||
library;
|
||||
|
||||
///
|
||||
/// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com)
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -10,6 +12,5 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
library cherrypick_flutter;
|
||||
|
||||
export 'src/cherrypick_provider.dart';
|
||||
|
||||
@@ -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
|
||||
|
||||
47
examples/client_app/.gitignore
vendored
Normal file
47
examples/client_app/.gitignore
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# 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
|
||||
|
||||
30
examples/client_app/.metadata
Normal file
30
examples/client_app/.metadata
Normal file
@@ -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'
|
||||
16
examples/client_app/README.md
Normal file
16
examples/client_app/README.md
Normal file
@@ -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.
|
||||
28
examples/client_app/analysis_options.yaml
Normal file
28
examples/client_app/analysis_options.yaml
Normal file
@@ -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
|
||||
41
examples/client_app/lib/main.dart
Normal file
41
examples/client_app/lib/main.dart
Normal file
@@ -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: MyHomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Модуль для настройки зависимостей
|
||||
class ModuleWithUseCase extends Module {
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
// Привязка UseCase как singleton
|
||||
bind<UseCase>().toInstance(UseCase());
|
||||
}
|
||||
}
|
||||
21
examples/client_app/lib/my_home_page.dart
Normal file
21
examples/client_app/lib/my_home_page.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cherrypick_flutter/cherrypick_flutter.dart';
|
||||
import 'use_case.dart';
|
||||
|
||||
class MyHomePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Разрешение зависимости UseCase из рутового скоупа
|
||||
final UseCase useCase =
|
||||
CherryPickProvider.of(context).openRootScope().resolve<UseCase>();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Example App'),
|
||||
),
|
||||
body: Center(
|
||||
child: Text(useCase.fetchData()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
3
examples/client_app/lib/use_case.dart
Normal file
3
examples/client_app/lib/use_case.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
class UseCase {
|
||||
String fetchData() => "Data fetched by UseCase";
|
||||
}
|
||||
229
examples/client_app/pubspec.lock
Normal file
229
examples/client_app/pubspec.lock
Normal file
@@ -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: "802427b777bc80e39216ec7070e452edd1a01eca84f824dfb57cc5e055797c4c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
cherrypick_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cherrypick_flutter
|
||||
sha256: "6fa2ee4ea06a8f9edfaab43e665199b378add34c52ca081f55ed82cded090257"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
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"
|
||||
65
examples/client_app/pubspec.yaml
Normal file
65
examples/client_app/pubspec.yaml
Normal file
@@ -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
|
||||
30
examples/client_app/test/widget_test.dart
Normal file
30
examples/client_app/test/widget_test.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 {
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
BIN
examples/client_app/web/favicon.png
Normal file
BIN
examples/client_app/web/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 917 B |
BIN
examples/client_app/web/icons/Icon-192.png
Normal file
BIN
examples/client_app/web/icons/Icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
examples/client_app/web/icons/Icon-512.png
Normal file
BIN
examples/client_app/web/icons/Icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
BIN
examples/client_app/web/icons/Icon-maskable-192.png
Normal file
BIN
examples/client_app/web/icons/Icon-maskable-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
BIN
examples/client_app/web/icons/Icon-maskable-512.png
Normal file
BIN
examples/client_app/web/icons/Icon-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
38
examples/client_app/web/index.html
Normal file
38
examples/client_app/web/index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
|
||||
For more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
|
||||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="A new Flutter project.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="client_app">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>client_app</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
</body>
|
||||
</html>
|
||||
35
examples/client_app/web/manifest.json
Normal file
35
examples/client_app/web/manifest.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
melos.yaml
10
melos.yaml
@@ -8,8 +8,10 @@ packages:
|
||||
|
||||
scripts:
|
||||
analyze:
|
||||
run: |
|
||||
flutter analyze
|
||||
exec: dart analyze
|
||||
|
||||
format:
|
||||
run: |
|
||||
flutter format
|
||||
exec: dart format
|
||||
|
||||
test:
|
||||
exec: flutter test
|
||||
Reference in New Issue
Block a user