Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Integration of flame_riverpod #2367

Merged
merged 49 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
98861eb
Committing flame_riverpod project files
markvideon Feb 1, 2023
855749f
Added widget test for the example.
markvideon Feb 25, 2023
c2e93b5
Ran `dart format . --set-exit-if-changed`
markvideon Feb 25, 2023
1eb5b84
Removed platform folders from the example.
markvideon Feb 26, 2023
185482f
Added visibleForTesting annotation to the lifecycle field of [Compone…
markvideon Feb 26, 2023
127810b
Update packages/flame_riverpod/README.md
markvideon Feb 27, 2023
e0672cf
Removed visibleForTesting annotation - no longer calling lifecycle ma…
markvideon Feb 27, 2023
d295958
Merge branch 'main' of github.com:markvideon/flame
markvideon Feb 27, 2023
461aba3
Changed LICENSE to MIT
markvideon Feb 27, 2023
dad9a27
Updated pubspec for flame_riverpod and the example project as per cha…
markvideon Feb 27, 2023
7b09c50
Removed example project .gitignore and .metadata files
markvideon Feb 27, 2023
1194a80
Made the list of subscriptions final as per comment
markvideon Feb 27, 2023
5a66380
Refactor of unitialisedGame -> unitializedGame that should have been …
markvideon Feb 27, 2023
bbd0de9
Changes to widgetTest to remove need to manually trigger lifecycle ev…
markvideon Feb 27, 2023
44b0174
Added suggested self-credit copy to package README
markvideon Feb 27, 2023
eb3242a
Removed access of hasPendingLifecycleEvents inside the example widget…
markvideon Feb 27, 2023
a3c48aa
Americanised name: RiverpodGameWidget constructor (initialiseWithGame…
markvideon Feb 27, 2023
26c1a0a
Updated description of flame_riverpod to provide context.
markvideon Feb 27, 2023
da49352
More Americanisation of the word initialise
markvideon Feb 27, 2023
9ff8c05
Updated READMEs
markvideon Feb 27, 2023
f3f241d
Adjustments based on feedback in Markdown, Format github actions
markvideon Feb 27, 2023
80da27c
Addressed feedback from markdown lint github action
markvideon Feb 27, 2023
f385afa
Merge branch 'main' into main
markvideon Feb 28, 2023
f8d7270
Update packages/flame_riverpod/example/README.md
markvideon Feb 28, 2023
dc1176c
Update packages/flame_riverpod/example/pubspec.yaml
markvideon Feb 28, 2023
8fa32d5
Update packages/flame_riverpod/example/pubspec.yaml
markvideon Feb 28, 2023
b29dac7
chore: Added newlines to EOF for pubspec and analysis_options files.
markvideon Feb 28, 2023
8c2d5db
doc: Added dartdoc comments to HasComponentRef.
markvideon Feb 28, 2023
8965e51
fix: Only reference in scope identifiers in doc comments, as per inve…
markvideon Feb 28, 2023
bde27e7
Update packages/flame_riverpod/example/pubspec.yaml
markvideon Mar 1, 2023
2950ad7
Update packages/flame_riverpod/pubspec.yaml
markvideon Mar 1, 2023
64849a9
Update packages/flame_riverpod/example/pubspec.yaml
markvideon Mar 1, 2023
d6027fd
Merge branch 'flame-engine:main' into main
markvideon Nov 30, 2023
7e0de63
flame_riverpod v5
markvideon Nov 30, 2023
7bb44b1
Added link to flutter_riverpod within README
markvideon Nov 30, 2023
1aec2d1
Chore: adjusted end of line spacing in README, renamed test/test.dart…
markvideon Nov 30, 2023
7931d5d
Chore: Addressed markdown lint warnings.
markvideon Nov 30, 2023
838bd23
Chore: Added words to cspell
markvideon Nov 30, 2023
76e6e7c
Chore: Moved name to people_usernames.txt from words_dictionary.txt
markvideon Nov 30, 2023
189a001
Removed example gitignore
markvideon Nov 30, 2023
83b7457
Chore: Modified flame_riverpod example to use a version rather than r…
markvideon Nov 30, 2023
7d4783d
Docs: Dartdoc for RiverpodAwareGameWidget
markvideon Nov 30, 2023
fdf8273
Update packages/flame_riverpod/example/lib/main.dart
markvideon Nov 30, 2023
b1bcc27
docs: Bridge packages documentation for flame_riverpod
markvideon Dec 1, 2023
b78ed9c
fix: Trailing space deteced by markdownlint
markvideon Dec 1, 2023
3bd0534
Merge branch 'main' of github.com:markvideon/flame
markvideon Dec 1, 2023
52d2a6d
Update doc/bridge_packages/flame_riverpod/flame_riverpod.md
markvideon Dec 1, 2023
4074151
Update doc/bridge_packages/flame_riverpod/riverpod.md
markvideon Dec 1, 2023
d77a620
Merge branch 'main' into main
spydon Dec 1, 2023
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
1 change: 1 addition & 0 deletions .github/.cspell/people_usernames.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ subosito # github.com/subosito
spydon # github.com/spydon
stpasha # github.com/stpasha
tavian # tavianator.com
videon # github.com/markvideon
wolfenrain # github.com/wolfenrain
xaha # github.com/xvrh
1 change: 1 addition & 0 deletions .github/.cspell/words_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ proxying
ptero # short for pterodactyl
rebalance
redeclaration
refreshable
renderable
rescan
tappable
Expand Down
7 changes: 7 additions & 0 deletions doc/bridge_packages/bridge_packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ Replace FCS with the Oxygen Entity Component System.
Create interactive animations (bridge package for [Rive]).
:::

:::{package} flame_riverpod

A reactive caching and data-binding framework (bridge package for [Riverpod]).
:::

:::{package} flame_spine

Use Spine skeletal animations (bridge package for [Spine]).
Expand All @@ -71,6 +76,7 @@ Draw SVG files in Flutter (bridge package for [flutter_svg]).
[Forge2D]: https://github.com/flame-engine/forge2d
[Lottie]: https://pub.dev/packages/lottie
[Rive]: https://rive.app/
[Riverpod]: https://github.com/rrousselGit/riverpod
[Spine]: https://pub.dev/packages/spine_flutter
[Tiled]: https://www.mapeditor.org/
[flutter_svg]: https://github.com/dnfield/flutter_svg
Expand All @@ -88,6 +94,7 @@ flame_lottie <flame_lottie/flame_lottie.md>
flame_network_assets <flame_network_assets/flame_network_assets.md>
flame_oxygen <flame_oxygen/flame_oxygen.md>
flame_rive <flame_rive/flame_rive.md>
flame_riverpod <flame_riverpod/flame_riverpod.md>
flame_splash_screen <flame_splash_screen/flame_splash_screen.md>
flame_spine <flame_spine/flame_spine.md>
flame_svg <flame_svg/flame_svg.md>
Expand Down
46 changes: 46 additions & 0 deletions doc/bridge_packages/flame_riverpod/component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Component


## ComponentRef

`ComponentRef` exposes Riverpod functionality to individual `Component`s, and is comparable to
`flutter_riverpod`'s `WidgetRef`.


## RiverpodComponentMixin

`RiverpodComponentMixin` manages the lifecycle of listeners on behalf of individual `Component`s.

`Component`s using this mixin must use `addToGameWidgetBuild` in their `onMount` method to add
listeners (e.g. `ref.watch` or `ref.listen`) *prior to* calling `super.onMount`, which manages the
staged listeners and disposes of them on the user's behalf inside `onRemove`.

```dart

class RiverpodAwareTextComponent extends PositionComponent
with RiverpodComponentMixin {
late TextComponent textComponent;
int currentValue = 0;

@override
void onMount() {
addToGameWidgetBuild(() {
ref.listen(countingStreamProvider, (p0, p1) {
if (p1.hasValue) {
currentValue = p1.value!;
textComponent.text = '$currentValue';
}
});
});
super.onMount();
add(textComponent = TextComponent(position: position + Vector2(0, 27)));
}
}

```


## RiverpodGameMixin

`RiverpodGameMixin` provides listeners from all components to the build method of the
`RiverpodAwareGameWidget`.
8 changes: 8 additions & 0 deletions doc/bridge_packages/flame_riverpod/flame_riverpod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# flame_riverpod

```{toctree}
Overview <riverpod.md>
Component <component.md>
Widget <widget.md>
```

67 changes: 67 additions & 0 deletions doc/bridge_packages/flame_riverpod/riverpod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# flame_riverpod


## Riverpod

[Riverpod](https://riverpod.dev/) is a reactive caching and data-binding
framework for Dart & Flutter.

In `flutter_riverpod`, widgets can be configured to rebuild when the state
of a provider changes.

When using Flame, we are interacting with components, which are *not* Widgets.

`flame_riverpod` provides the `RiverpodAwareGameWidget`, `RiverpodGameMixin`, and
`RiverpodComponentMixin` to facilitate managing state from `Provider`s in your Flame Game.


## Usage

You should use the `RiverpodAwareGameWidget` as your Flame `GameWidget`, the `RiverpodGameMixin`
mixin on your game that extends `FlameGame`, and the `RiverpodComponentMixin` on any components
interacting with Riverpod providers.

Subscriptions to a provider are managed in accordance with the lifecycle
of a Flame Component: initialization occurs when a Component is mounted, and disposal
occurs when a Component is removed.

By default, the `RiverpodAwareGameWidget` is rebuilt when
Riverpod-aware (i.e. using the `RiverpodComponentMixin`) components are mounted and when they are
removed.

```dart
/// An excerpt from the Example. Check it out!
class RefExampleGame extends FlameGame with RiverpodGameMixin {
@override
Future<void> onLoad() async {
await super.onLoad();
add(TextComponent(text: 'Flame'));
add(RiverpodAwareTextComponent());
}
}

class RiverpodAwareTextComponent extends PositionComponent
with RiverpodComponentMixin {
late TextComponent textComponent;
int currentValue = 0;

@override
void onMount() {
addToGameWidgetBuild(() {
ref.listen(countingStreamProvider, (p0, p1) {
if (p1.hasValue) {
currentValue = p1.value!;
textComponent.text = '$currentValue';
}
});
});
super.onMount();
add(textComponent = TextComponent(position: position + Vector2(0, 27)));
}
}

```

The order of operations in `Component.onMount` is important. The `RiverpodComponentMixin`
interacts with `RiverpodGameMixin` (inside of `RiverpodComponentMixin.onMount`) to co-ordinate
adding and removing listeners as the corresponding component is mounted and removed, respectively.
16 changes: 16 additions & 0 deletions doc/bridge_packages/flame_riverpod/widget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Widget


## RiverpodAwareGameWidget

`RiverpodAwareGameWidget` is a GameWidget with a `State` object of type
`RiverpodAwareGameWidgetState`.

The required `GlobalKey` argument is used to provide `Component`s using `RiverpodComponentMixin`
access to `Provider`s via `RiverpodAwareGameWidgetState`.


## RiverpodAwareGameWidgetState

`RiverpodAwareGameWidgetState` performs the duties associated with the
`ConsumerStatefulElement` in `flutter_riverpod` and `GameWidgetState` in `flame`.
62 changes: 62 additions & 0 deletions packages/flame_riverpod/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
## 5.0.0

* New API with breaking changes. Added [RiverpodAwareGameWidget], [RiverpodGameMixin], [RiverpodComponentMixin]. See the example for details.

## 4.0.0+2

* Miscellaneous format post-processing on the files.

## 4.0.0+1

* Miscellaneous tidy-up of package internals.

## 4.0.0

* Made [WidgetRef] property on [ComponentRef] private. It should not be accessed directly.
* Removed the [riverpodAwar`eGameProvider]. If required, this is better handled at the application-level.

## 3.0.0

* Changes to focus on [FlameGame].
* [riverpodAwareGameProvider] now expects a [FlameGame].
* Removed the [HasComponentRef] on Game.
* Renamed [RiverpodComponentMixin] to [HasComponentRef]
* [HasComponentRef] now has a static setter for a WidgetRef. Components that use the new [HasComponentRef] mixin no
longer need to explicitly provide a [ComponentRef].
* Renamed the [WidgetRef] property on the [ComponentRef] to [widgetRef].
* Updated Example to reflect changes.
* Updated README to reflect changes.

## 2.0.0

* Pruned the public API, removing custom widget definitions (these have now been defined inside the example for
reference)
* Renamed [RiverpodAwareGameMixin] -> [HasComponentRef] to bring closer to the Flame 'house-style' for mixins.

## 1.1.0+2

* Another correction to README and example code. onMount should not call super.onLoad.

## 1.1.0+1

* Correction to README to reflect API change.

## 1.1.0

* Added [RiverpodComponentMixin] to handle disposing of [ProviderSubscription]s.
* Correction to the [RiverpodGameWidget] initializeGame constructor - param is now
[RiverpodAwareGameMixin Function (ref)] as originally intended.

## 1.0.0+1

* Reduced package description length.
* Ran dart format.

## 1.0.0

* Initial release.
* ComponentRef
* riverpodAwareGameProvider
* RiverpodAwareFlameGame
* RiverpodAwareGame
* RiverpodGameWidget
21 changes: 21 additions & 0 deletions packages/flame_riverpod/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Blue Fire

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
78 changes: 78 additions & 0 deletions packages/flame_riverpod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# flame_riverpod

[Riverpod](https://pub.dev/packages/flutter_riverpod) is a reactive caching and data-binding
framework for Dart & Flutter.

In `flutter_riverpod`, widgets can be configured to rebuild when the state
of a provider changes.

When using Flame, we are interacting with components, which are *not* Widgets.

`flame_riverpod` provides the `RiverpodAwareGameWidget`, `RiverpodGameMixin`, and
`RiverpodComponentMixin` to facilitate managing state from Providers in your Flame Game.


## Usage

You should use the `RiverpodAwareGameWidget` as your Flame `GameWidget`, the `RiverpodGameMixin`
mixin on your game that extends `FlameGame`, and the `RiverpodComponentMixin` on any components
interacting with Riverpod providers.

The full range of operations defined in Riverpod's `WidgetRef` definition are accessible from
components.

Subscriptions to a provider are managed in accordance with the lifecycle
of a Flame Component: initialization occurs when a Component is mounted, and disposal
occurs when a Component is removed. By default, the `RiverpodAwareGameWidget` is rebuilt when
Riverpod-aware (i.e. using the `RiverpodComponentMixin`) components are mounted and when they are
removed.

```dart

/// An excerpt from the Example. Check it out!
class RefExampleGame extends FlameGame with RiverpodGameMixin {
@override
Future<void> onLoad() async {
await super.onLoad();
add(TextComponent(text: 'Flame'));
add(RiverpodAwareTextComponent());
}
}

class RiverpodAwareTextComponent extends PositionComponent
with RiverpodComponentMixin {
late TextComponent textComponent;
int currentValue = 0;

/// [onMount] should be used over [onLoad] to initialize subscriptions,
/// cancellation is handled for the user inside [onRemove],
/// which is only called if the [Component] was mounted.
///
/// [RiverpodComponentMixin.addToGameWidgetBuild] **must** be invoked in
/// your Component **before** [RiverpodComponentMixin.onMount] in order to
/// have the provided function invoked on
/// [RiverpodAwareGameWidgetState.build].
///
/// From `flame_riverpod` 5.0.0, [WidgetRef.watch], is also accessible from
/// components.
@override
void onMount() {
addToGameWidgetBuild(() {
ref.listen(countingStreamProvider, (p0, p1) {
if (p1.hasValue) {
currentValue = p1.value!;
textComponent.text = '$currentValue';
}
});
});
super.onMount();
add(textComponent = TextComponent(position: position + Vector2(0, 27)));
}
}

```
spydon marked this conversation as resolved.
Show resolved Hide resolved


## Credits

[Mark Videon](https://markvideon.dev) for the initial groundwork and implementation.
1 change: 1 addition & 0 deletions packages/flame_riverpod/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:flame_lint/analysis_options.yaml
30 changes: 30 additions & 0 deletions packages/flame_riverpod/example/.metadata
Original file line number Diff line number Diff line change
@@ -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: "efbf63d9c66b9f6ec30e9ad4611189aa80003d31"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
- platform: macos
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31

# 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'
markvideon marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 10 additions & 0 deletions packages/flame_riverpod/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# flame_riverpod_example

The example consists of a very simple FlameGame with a custom
Component, updated alongside a comparable Flutter widget.

Both the Component and the Widget depend on a `StreamProvider`
that counts upwards indefinitely.

Both a Flame Component and a Flutter Text Widget update in real-time from
the same data source.
1 change: 1 addition & 0 deletions packages/flame_riverpod/example/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:flame_lint/analysis_options.yaml
Loading