Created
November 25, 2025 13:20
-
-
Save saltyJeff/4130d05955e791d2c08d791937fdf25e to your computer and use it in GitHub Desktop.
Gemini wrote me this update to flame_riverpod to riverpod v3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flame/components.dart'; | |
| import 'package:flame/game.dart'; | |
| import 'package:flutter/widgets.dart'; | |
| import 'package:riverpod/riverpod.dart'; | |
| import 'package:riverpod/misc.dart'; | |
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | |
| /// A custom [Ref] object for Flame components. | |
| /// | |
| /// It provides [watch], [listen], and [read] methods that are | |
| /// adapted for the [Component] lifecycle. | |
| class ComponentRef { | |
| ComponentRef(this._container); | |
| final ProviderContainer _container; | |
| final _subscriptions = <ProviderSubscription>[]; | |
| /// Reads the current value of a provider *without* subscribing. | |
| /// | |
| /// This is for one-time reads, often in `onLoad` or in response to an event. | |
| T read<T>(ProviderListenable<T> provider) { | |
| return _container.read(provider); | |
| } | |
| /// Subscribes to a provider and calls a [listener] callback on change. | |
| /// | |
| /// The subscription is automatically disposed when the component is removed. | |
| void listen<T>( | |
| ProviderListenable<T> provider, | |
| void Function(T? previous, T next) listener, { | |
| bool fireImmediately = false, | |
| }) { | |
| final sub = _container.listen( | |
| provider, | |
| listener, | |
| fireImmediately: fireImmediately, | |
| ); | |
| _subscriptions.add(sub); | |
| } | |
| /// Gets the current value of a provider AND subscribes to future changes. | |
| /// | |
| /// This is the primary method you'll use in `onLoad`. | |
| /// It returns the *current* value, and sets up a [listener] to | |
| /// react to *future* values (e.g., to update component state). | |
| /// | |
| /// The subscription is automatically disposed when the component is removed. | |
| T watch<T>( | |
| ProviderListenable<T> provider, | |
| void Function(T? previous, T next) listener, | |
| ) { | |
| listen(provider, listener, fireImmediately: false); | |
| return read(provider); | |
| } | |
| /// Disposes all subscriptions created by this ref. | |
| /// Called automatically by the [RiverpodComponentMixin]. | |
| void dispose() { | |
| for (final sub in _subscriptions) { | |
| sub.close(); | |
| } | |
| _subscriptions.clear(); | |
| } | |
| } | |
| /// A mixin for [FlameGame] to make it aware of the Riverpod [ProviderContainer]. | |
| /// | |
| /// Your game class must use this mixin to use [RiverpodComponentMixin] on its | |
| /// components. | |
| mixin RiverpodGameMixin on FlameGame { | |
| ProviderContainer? _container; | |
| /// The [ProviderContainer] for this game. | |
| ProviderContainer get container { | |
| assert( | |
| _container != null, | |
| 'ProviderContainer not set. Did you forget to use RiverpodGameWidget?', | |
| ); | |
| return _container!; | |
| } | |
| /// Called by [RiverpodGameWidget] to set the container. | |
| void setProviderContainer(ProviderContainer container) { | |
| _container = container; | |
| } | |
| } | |
| /// The widget that bridges Flutter (Riverpod) and Flame. | |
| /// | |
| /// Use this widget to render your [RiverpodGameMixin] game. | |
| /// It finds the [ProviderContainer] from the [ProviderScope] and passes | |
| /// it to your game instance. | |
| class RiverpodGameWidget<T extends RiverpodGameMixin> | |
| extends ConsumerStatefulWidget { | |
| const RiverpodGameWidget({ | |
| super.key, | |
| required this.game, | |
| }); | |
| final T game; | |
| @override | |
| ConsumerState<RiverpodGameWidget<T>> createState() => | |
| _RiverpodGameWidgetState<T>(); | |
| } | |
| class _RiverpodGameWidgetState<T extends RiverpodGameMixin> | |
| extends ConsumerState<RiverpodGameWidget<T>> { | |
| late final T _game; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| _game = widget.game; | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| // Get the container from the context... | |
| final container = ProviderScope.containerOf(context); | |
| // ...and pass it to the game. | |
| _game.setProviderContainer(container); | |
| // GameWidget is the standard widget from Flame to render a game. | |
| return GameWidget(game: _game); | |
| } | |
| } | |
| /// The mixin you requested. | |
| /// | |
| /// Add this mixin to any [Component] to get access to `ref.watch`, | |
| /// `ref.listen`, and `ref.read`. | |
| /// | |
| /// The component MUST be added to a game that uses [RiverpodGameMixin]. | |
| mixin RiverpodComponentMixin on Component { | |
| late final ComponentRef ref; | |
| ProviderContainer? _container; | |
| /// Helper to get the game's [ProviderContainer]. | |
| ProviderContainer get _gameContainer { | |
| if (_container != null) return _container!; | |
| final game = findRootGame(); | |
| if (game is! RiverpodGameMixin) { | |
| throw StateError( | |
| 'RiverpodComponentMixin can only be used on components added to a ' | |
| 'game that uses RiverpodGameMixin. Please add RiverpodGameMixin to ' | |
| '${game.runtimeType}.', | |
| ); | |
| } | |
| _container = game.container; | |
| return _container!; | |
| } | |
| @override | |
| @mustCallSuper | |
| void onLoad() { | |
| super.onLoad(); | |
| // Create the ref and link it to the game's container. | |
| ref = ComponentRef(_gameContainer); | |
| } | |
| @override | |
| @mustCallSuper | |
| void onRemove() { | |
| super.onRemove(); | |
| // Clean up all subscriptions when the component is removed. | |
| ref.dispose(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment