Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ jobs:
with:
flutter-version: '3.27.3'
channel: 'stable'
- name: Setup LCOV
uses: hrishikesh-kadam/setup-lcov@v1
- name: Override dependencies
run: "echo 'dependency_overrides: { dart_style: ^2.0.1 }' > pubspec_overrides.yaml && cp pubspec_overrides.yaml example/"
- name: Install dependencies
run: dart pub get

- name: Verify formatting
run: dart format --output=none --set-exit-if-changed lib

Expand All @@ -27,6 +30,5 @@ jobs:

- name: Generate the mocks
run: flutter pub run build_runner build --delete-conflicting-outputs

- name: Run tests
run: flutter test
run: chmod +x run_tests.sh && ./run_tests.sh
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ migrate_working_dir/
build/
/coverage/
/test/*.mocks.dart
pubspec_overrides.yaml
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
## 2.0.0

### Breaking Changes

- `catalyst_builder: ^5.0.0` is required
- Check [UPGRADE.md](UPGRADE.md)

## 2.0.0-rc.1

### Breaking Changes

- `catalyst_builder: ^5.0.0-rc.1` is required

## 2.0.0-dev.1

### Breaking Changes

- `catalyst_builder: ^5.0.0-dev.1` is required
- Configuration has changed. Take a look in [UPGRADE.md](UPGRADE.md) for guidance.

## 1.2.0

Changes:
Expand Down
29 changes: 29 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Upgrade from v1 to v2

## catalyst_builder

Update catalyst_builder to ^5.0.0

## Service registration

Update your code:
```diff
void main() {
// Create an instance of the service provider
- var provider = DefaultServiceProvider();
- provider
+ var container = ServiceContainer();
+ container
// Extension method from the explorator package
..useExplorator(
- routeBuilder: MaterialRouteBuilder(),
)
+ ..setupExplorator(
+ routeBuilder: MaterialRouteBuilder(),
+ )
..boot();
// Run the app
- runApp(MyApp(provider));
+ runApp(MyApp(container));
}
```
5 changes: 5 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
targets:
$default:
sources:
exclude:
- example/**
50 changes: 17 additions & 33 deletions doc/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,29 @@
- Follow the setup steps for [catalyst_builder](https://pub.dev/packages/catalyst_builder).
- Follow the setup steps for [explorator](https://pub.dev/packages/explorator/install).

### Update the build.yaml

Make sure that you set includePackageDependencies to true in the build.yaml:

```yaml
# build.yaml
targets:
$default:
auto_apply_builders: true
builders:
catalyst_builder|buildServiceProvider:
options:
providerClassName: 'DefaultServiceProvider'
includePackageDependencies: true
```

### Register the RouteResolver

```dart
@GenerateServiceProvider()
void main() {
// Create an instance of the service provider
var provider = DefaultServiceProvider();
provider
// Create an instance of the service container
var container = ServiceContainer();
container
// Extension method from the explorator package
..useExplorator(
..useExplorator()
..setupExplorator(
routeBuilder: MaterialRouteBuilder(),
)
..boot();
// Run the app
runApp(MyApp(provider));
runApp(MyApp(container));
}

class MyApp extends StatelessWidget {

/// Inject the provider
final ServiceProvider _provider;
/// Inject the container
final AbstractServiceContainer _container;

const MyApp(this._provider, {super.key});
const MyApp(this._container, {super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -51,11 +35,11 @@ class MyApp extends StatelessWidget {
primarySwatch: Colors.blue,
),
// Use the navigator key
navigatorKey: _provider.resolve<GlobalKey<NavigatorState>>(),
navigatorKey: _container.resolve<GlobalKey<NavigatorState>>(),
// Set the initial route.
initialRoute: '/home/HelloFlutter',
// Use the RouteResolver for generating routes
onGenerateRoute: _provider
onGenerateRoute: _container
.resolve<RouteResolver>()
.resolveRoute,
);
Expand All @@ -78,10 +62,10 @@ class HomeRouteProvider implements RouteProvider {
// Return your routes
RegisteredRoute(
path: r'/home/{name}',
// The builder should return a function that accepts a provider (ServiceProvider from above)
// and returns a WidgetBuilder. Since we have the provider, we can use DI to get the instance
// The builder should return a function that accepts a container (ServiceContainer from above)
// and returns a WidgetBuilder. Since we have the container, we can use DI to get the instance
// of our widget 🙌.
builder: (provider) => (ctx) => provider.resolve<MyHomePage>(),
builder: (container) => (ctx) => container.resolve<MyHomePage>(),
)
];
}
Expand Down Expand Up @@ -167,16 +151,16 @@ You can access path variables and query parameters when injecting the `RouteArgu
## Dev / Prod

While you develop your app, you can use the following command to watch for changes and update the
routing / ServiceProvider automatically
routing / ServiceContainer automatically

```bash
flutter pub run build_runner watch --delete-conflicting-outputs
dart run build_runner watch --delete-conflicting-outputs
```

When building for production you can use this command before running `flutter build`:

```bash
flutter pub run build_runner build --delete-conflicting-outputs
dart run build_runner build --delete-conflicting-outputs
```

## How does it work?
Expand Down
18 changes: 9 additions & 9 deletions doc/under-the-hood.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,32 @@ The `builder` is just a method that accepts an instance of a catalyst `ServicePr
That means, we can use the given provider to resolve our `Screen/Widget n` without constructing it manually.
Since the `App Routes` class is not imported anywhere (ignore generated code 😉), the coupling is not worth mentioning.

As you noted, there is a connection between `DefaultServiceProvider` (DSP) and `App Routes`. That means, that the
As you noted, there is a connection between `ServiceContainer` and `App Routes`. That means, that the
`App Routes` class must be decorated with `@Service(tags: [RouteProvider.tag])`.

-----

Next step: take a look on the connection between `RouteResolver` and `RouteProvider` / `ServiceProvider`.
Next step: take a look on the connection between `RouteResolver` and `RouteProvider` / `ServiceContainer`.

The [`RouteResolver`](../lib/src/route_resolver.dart) expects in the constructor a `List<RouteProvider>`. If you take
a look in the code, you can see, that the constructor parameter is decorated with `@Inject(tag: RouteProvider.tag)`.

Now you can put two and two together. The `ServiceProvider` takes all services that are tagged with `RouteProvider.tag`,
Now you can put two and two together. The `ServiceContainer` takes all services that are tagged with `RouteProvider.tag`,
including our `App Routes` class, and inject it as a list to the `RouteResolver`.

-----

That's already most of the magic. Let's take a look how routes are resolved.

Since the `RouteResolver` is decorated with `@Service`, your `ServiceProvider` can construct this class.
Since the `RouteResolver` is decorated with `@Service`, the `ServiceContainer` can construct this class.

And that's exactly what happens in this piece of code.
```dart
Widget build(BuildContext context) {
return MaterialApp(
// 1. We resolve the `RouteResolver` from the DSP
// 1. We resolve the `RouteResolver` from the Container
// 2. Tell the Flutter router "use `resolveRoute` to generate routes"
onGenerateRoute: _provider.resolve<RouteResolver>().resolveRoute,
onGenerateRoute: _container.resolve<RouteResolver>().resolveRoute,
);
}
```
Expand All @@ -69,11 +69,11 @@ The `RouteResolver.resolveRoute` looks more complicated as it's.
2. The `name` is the `path` of our `RegisteredRoute`.
- The `RegisteredRoute` creates a Regex from this path.
3. Then it iterates over all `RegisteredRoute`s (passed in the constructor) and check if the `name` match against the regex.
4. If it's a match, the method extracts the path variables and creates a sub-`ServiceProvider`.
- The sub-`ServiceProvider` contains additional services:
4. If it's a match, the method extracts the path variables and creates a sub-`ServiceContainer`.
- The sub-`ServiceContainer` contains additional services:
- [`RouteArguments`](../lib/src/route_arguments.dart)
- `RouteSettings`
5. Using the builder from the `RegisteredRoute` to construct the widget. We pass the sub-`ServiceProvider` as the `ServiceProvider`.
5. Using the builder from the `RegisteredRoute` to construct the widget. We pass the sub-`ServiceContainer` as the `ServiceContainer`.
6. Using the `RouteBuilder` to construct and return a Flutter route.

Not that complicated, right? 😅
8 changes: 0 additions & 8 deletions example/build.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand Down
2 changes: 1 addition & 1 deletion example/lib/home/home_screen.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:flutter/material.dart';

Expand Down
2 changes: 1 addition & 1 deletion example/lib/home/routes.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:explorator_example/home/home_screen.dart';

Expand Down
32 changes: 17 additions & 15 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:flutter/material.dart';
import 'package:url_strategy/url_strategy.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

import 'main.catalyst_builder.g.dart';
import 'main.catalyst_builder.plugin.g.dart';

@GenerateServiceProvider(
providerClassName: 'DefaultServiceProvider',
includePackageDependencies: true
@GenerateServiceContainerPlugin(
pluginClassName: 'AppPlugin',
)
void main() {
setPathUrlStrategy();
usePathUrlStrategy();

// Create an instance of the service provider
var provider = DefaultServiceProvider();
provider
// Create an instance of the service container
var container = ServiceContainer();
container
..useAppPlugin()
// Extension method from the explorator package
..useExplorator(
..useExplorator()
..setupExplorator(
routeBuilder: MaterialRouteBuilder(),
)
..boot();

// Run the app
runApp(MyApp(provider));
runApp(MyApp(container));
}

class MyApp extends StatelessWidget {
/// Inject the provider
final ServiceProvider _provider;
final AbstractServiceContainer _container;

const MyApp(this._provider, {super.key});
const MyApp(this._container, {super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -39,11 +41,11 @@ class MyApp extends StatelessWidget {
primarySwatch: Colors.blue,
),
// Use the navigator key
navigatorKey: _provider.resolve<GlobalKey<NavigatorState>>(),
navigatorKey: _container.resolve<GlobalKey<NavigatorState>>(),
// Set the initial route.
initialRoute: '/',
// Use the RouteResolver for generating routes
onGenerateRoute: _provider.resolve<RouteResolver>().resolveRoute,
onGenerateRoute: _container.resolve<RouteResolver>().resolveRoute,
);
}
}
2 changes: 1 addition & 1 deletion example/lib/other/other_screen.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:flutter/material.dart';

@Service()
Expand Down
2 changes: 1 addition & 1 deletion example/lib/other/routes.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:explorator_example/other/variables_screen.dart';

Expand Down
2 changes: 1 addition & 1 deletion example/lib/other/variables_screen.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:flutter/material.dart';

Expand Down
2 changes: 1 addition & 1 deletion example/lib/splash/routes.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:explorator_example/splash/splash_screen.dart';

Expand Down
2 changes: 1 addition & 1 deletion example/lib/splash/splash_screen.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:catalyst_builder/catalyst_builder.dart';
import 'package:catalyst_builder_contracts/catalyst_builder_contracts.dart';
import 'package:explorator/explorator.dart';
import 'package:flutter/material.dart';

Expand Down
Loading