Demos
Every demo is a screen in one small Flutter web app, built from docs/demo and running on this site. The code samples in the guides are imported from the same files, so what you read is what's running.
The basics
A root-scoped CounterService keeps its count in a stream. A ViewModel observes the stream, and DependenciesBuilder rebuilds when it changes.
Show the code
dart
/// App-wide counter. Root scope (the default), so every screen shares one.
class CounterService implements InjectableWithDisposeInterface {
static final Factory = InjectableFactory.withoutDependencies<CounterService>(
() => CounterService(),
);
static final DefaultProvider = Provider(CounterService);
// State lives in a stream, not in plain fields.
final _count = BehaviorSubject<int>.seeded(0);
Stream<int> get count => _count.stream;
void increment() => _count.add(_count.value + 1);
@override
Future<void> dispose() => _count.close();
}dart
class CounterViewModel extends DependencyBuilderViewModelBase {
CounterViewModel()
: super(dependencyDataList: DependencyDataBuilder.list([CounterService]));
late CounterService _counter;
int count = 0;
@override
void setPropertiesOnDependencyResolution(Dependencies deps) {
_counter = deps<CounterService>();
}
@override
Iterable<Stream> getListOfStreamsToObserve() => [_counter.count];
@override
void updateViewModelPropertiesOnStreamEmission(List snapshots) {
count = snapshots[0] as int;
}
void increment() => _counter.increment();
}dart
class BasicsDemo extends StatelessWidget {
const BasicsDemo({super.key});
@override
Widget build(BuildContext context) {
return DependenciesBuilder<CounterViewModel>(
cleanViewModelInstance: CounterViewModel(),
builder: (context, vm) => dependencyBuilderViewModelSimpleStateHandlingBuildUtilityFn(
context: context,
viewModel: vm,
loadingWidget: const Center(child: CircularProgressIndicator()),
build: (context, vm) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('${vm.count}', key: const Key('count'), style: Theme.of(context).textTheme.displayMedium),
const SizedBox(height: 16),
FilledButton.icon(
onPressed: vm.increment,
icon: const Icon(Icons.add),
label: const Text('Increment'),
),
],
),
),
),
);
}
}Async services
A service that takes two seconds to open, and a screen that shows a loading state until it's ready. Read the guide.
Scoped services
Two tables, each with its own TableManager, sharing one ProductRepository. Read the guide.