Skip to content

Instantly share code, notes, and snippets.

@rrousselGit
Last active May 3, 2026 15:08
Show Gist options
  • Select an option

  • Save rrousselGit/d7acc6b5852421f2a848756ec13b6f17 to your computer and use it in GitHub Desktop.

Select an option

Save rrousselGit/d7acc6b5852421f2a848756ec13b6f17 to your computer and use it in GitHub Desktop.
Experimental Riverpod dartpad
// ignore_for_file: prefer_relative_imports, public_member_api_docs, invalid_use_of_internal_member
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod/misc.dart';
import 'package:flutter_riverpod/mutation.dart';
import 'package:flutter/material.dart';
class Counter extends Notifier<int> {
@override
int build() => 0;
void increment() => state++;
}
void main() {
runApp(
// Adding ProviderScope enables Riverpod for the entire project
const ProviderScope(child: MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(home: Home());
}
class Home extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text('Counter example')),
body: Center(child: Text('${Counter.new.watch(ref)}')),
floatingActionButton: FloatingActionButton(
// The read method is a utility to read a provider without listening to it
onPressed: () => ref.read(Counter.new.notifier).increment(),
child: const Icon(Icons.add),
),
);
}
}
/* Source for the experiment */
final _fam = Family(
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
T _watch<T>(MutationTarget target, ProviderBase<T> provider) {
switch (target) {
case Ref():
return target.watch(provider);
case WidgetRef():
return target.watch(provider);
case ProviderContainer():
throw UnsupportedError(
'Watching a provider from a ProviderContainer is not supported.',
);
case _:
throw UnsupportedError(
'Watching a provider from a ${target.runtimeType} is not supported.',
);
}
}
void _listen<T>(
MutationTarget target,
ProviderBase<T> provider,
void Function(T? previous, T next) listener,
) {
switch (target) {
case Ref():
target.listen(provider, listener);
case WidgetRef():
target.listen(provider, listener);
case ProviderContainer():
target.listen(provider, listener);
case _:
throw UnsupportedError(
'Listening to a provider from a ${target.runtimeType} is not supported.',
);
}
}
T _read<T>(MutationTarget target, ProviderBase<T> provider) {
switch (target) {
case Ref():
return target.read(provider);
case WidgetRef():
return target.read(provider);
case ProviderContainer():
return target.read(provider);
case _:
throw UnsupportedError(
'Reading a provider from a ${target.runtimeType} is not supported.',
);
}
}
extension FunctionalProvider<T> on T Function(Ref ref) {
Provider<T> get provider => Provider<T>.internal(
this,
from: _fam,
argument: (this,),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
T watch(MutationTarget target) => _watch(target, provider);
void listen(
MutationTarget target,
void Function(T? previous, T next) listener,
) => _listen(target, provider, listener);
T read(MutationTarget target) => _read(target, provider);
}
extension FunctionalFamily<T, Arg> on T Function(Ref ref, Arg arg) {
Provider<T> provider(Arg arg) => Provider<T>.internal(
(ref) => this(ref, arg),
from: _fam,
argument: (this, arg),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
T watch(MutationTarget target, Arg arg) => _watch(target, provider(arg));
void listen(
MutationTarget target,
Arg arg,
void Function(T? previous, T next) listener,
) => _listen(target, provider(arg), listener);
T read(MutationTarget target, Arg arg) => _read(target, provider(arg));
}
extension FunctionalFutureProvider<T> on Future<T> Function(Ref ref) {
FutureProvider<T> get provider => FutureProvider<T>.internal(
this,
from: _fam,
argument: (this,),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
AsyncValue<T> watch(MutationTarget target) => _watch(target, provider);
void listen(
MutationTarget target,
void Function(AsyncValue<T>? previous, AsyncValue<T> next) listener,
) => _listen(target, provider, listener);
AsyncValue<T> read(MutationTarget target) => _read(target, provider);
}
extension FunctionalFutureFamily<T, Arg> on T Function(Ref ref, Arg arg) {
FutureProvider<T> provider(Arg arg) => FutureProvider<T>.internal(
(ref) => this(ref, arg),
from: _fam,
argument: (this, arg),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
AsyncValue<T> watch(MutationTarget target, Arg arg) =>
_watch(target, provider(arg));
void listen(
MutationTarget target,
Arg arg,
void Function(AsyncValue<T>? previous, AsyncValue<T> next) listener,
) => _listen(target, provider(arg), listener);
AsyncValue<T> read(MutationTarget target, Arg arg) =>
_read(target, provider(arg));
}
extension ClassBasedProvider<NotifierT extends Notifier<StateT>, StateT>
on NotifierT Function() {
NotifierProvider<NotifierT, StateT> get provider =>
NotifierProvider<NotifierT, StateT>.internal(
this,
from: _fam,
argument: (this,),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
ProviderListenable<NotifierT> get notifier => provider.notifier;
StateT watch(MutationTarget target) => _watch(target, provider);
void listen(
MutationTarget target,
void Function(StateT? previous, StateT next) listener,
) => _listen(target, provider, listener);
StateT read(MutationTarget target) => _read(target, provider);
}
extension ClassBasedFamily<NotifierT extends Notifier<StateT>, StateT, ArgT>
on NotifierT Function(ArgT arg) {
NotifierProvider<NotifierT, StateT> provider(ArgT arg) =>
NotifierProvider<NotifierT, StateT>.internal(
() => this(arg),
from: _fam,
argument: (this, arg),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
ProviderListenable<NotifierT> notifier(ArgT arg) => provider(arg).notifier;
StateT watch(MutationTarget target, ArgT arg) => _watch(target, provider(arg));
void listen(
MutationTarget target,
ArgT arg,
void Function(StateT? previous, StateT next) listener,
) => _listen(target, provider(arg), listener);
StateT read(MutationTarget target, ArgT arg) => _read(target, provider(arg));
}
extension ClassBasedFutureProvider<NotifierT extends AsyncNotifier<StateT>, StateT>
on NotifierT Function() {
AsyncNotifierProvider<NotifierT, StateT> get provider =>
AsyncNotifierProvider<NotifierT, StateT>.internal(
this,
from: _fam,
argument: (this,),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
ProviderListenable<NotifierT> get notifier => provider.notifier;
AsyncValue<StateT> watch(MutationTarget target) => _watch(target, provider);
void listen(
MutationTarget target,
void Function(AsyncValue<StateT>? previous, AsyncValue<StateT> next) listener,
) => _listen(target, provider, listener);
AsyncValue<StateT> read(MutationTarget target) => _read(target, provider);
}
extension ClassBasedFutureFamily<NotifierT extends AsyncNotifier<StateT>, StateT, ArgT>
on NotifierT Function(ArgT arg) {
AsyncNotifierProvider<NotifierT, StateT> provider(ArgT arg) =>
AsyncNotifierProvider<NotifierT, StateT>.internal(
() => this(arg),
from: _fam,
argument: (this, arg),
name: null,
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
retry: null,
);
ProviderListenable<NotifierT> notifier(ArgT arg) => provider(arg).notifier;
AsyncValue<StateT> watch(MutationTarget target, ArgT arg) => _watch(target, provider(arg));
void listen(
MutationTarget target,
ArgT arg,
void Function(AsyncValue<StateT>? previous, AsyncValue<StateT> next) listener,
) => _listen(target, provider(arg), listener);
AsyncValue<StateT> read(MutationTarget target, ArgT arg) => _read(target, provider(arg));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment