fst 0.3.0 fst: ^0.3.0 copied to clipboard
State tree interface implementation for Flutter + Flutter specific APIs
import 'package:flutter/material.dart';
import 'package:fst/fst.dart';
void main() {
runApp(const CounterApp());
}
const $modifier = Context<bool>(#modifier);
const $count = Context<int>(#count);
class IntCounter extends Impl<int> {
final int initialValue;
const IntCounter(super.n, [this.initialValue = 0]);
@override
int init(StateTreeNode n) => initialValue;
void increment([covariant int delta = 1]) => value += delta;
void decrement([covariant int delta = 1]) => value -= delta;
void reset() => value = 0;
}
class ModifierImpl extends Impl<bool> {
const ModifierImpl(super.n);
@override
bool init(StateTreeNode n) => false;
void onKey(RawKeyEvent e) {
value = e.isShiftPressed;
}
}
class AppCounter extends IntCounter implements IncrementFABApi, ResetButtonApi {
const AppCounter(super.n);
}
class CounterApp extends StatelessWidget {
const CounterApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: StateTreeBuilder<bool>(
(context, n, child) {
final impl = n.impl(ModifierImpl.new);
$modifier.of(n).provide(impl.value);
final focusNode = n.init(FocusNode.new);
return RawKeyboardListener(
focusNode: focusNode,
autofocus: true,
onKey: impl.onKey,
child: child,
);
},
child: StateTreeBuilder<int>(
(context, n, child) {
final impl = n.impl(AppCounter.new);
$count.of(n)
..provide(impl.value)
..map((v) => v < 25, Home.$incrementEnabled);
IncrementFAB.$api.of(n).provide(impl);
ResetButton.$api.of(n).provide(impl);
return child;
},
child: StateTreeBuilder(
(context, n, child) {
final c = n.watch($count);
n.call(
(count) {
if (c % 10 != 0 || c == 0) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Count is multiple of 10')),
);
},
c,
mode: InvocationMode.postFrame,
);
return child;
},
child: const Home(),
),
),
),
);
}
}
class Home extends StateTreeWidget<void> {
static const $incrementEnabled = Context<bool>(#increment_fab_enabled);
const Home({super.key});
@override
Widget build(BuildContext context, StateTreeNode n) {
return Scaffold(
appBar: AppBar(
title: const Text('State Tree Example'),
actions: const [
ResetButton(),
],
),
body: Center(
child: StateTreeBuilder((context, n, _) {
final count = n.watch($count);
return Text('Count: $count');
}),
),
floatingActionButton: n.query(
$incrementEnabled,
(e) => e ? const IncrementFAB() : null,
),
);
}
}
abstract interface class IncrementFABApi {
void increment([int delta = 1]);
}
class IncrementFAB extends StateTreeWidget {
static const $api = Context<IncrementFABApi>(#increment_fab_api);
const IncrementFAB({super.key});
@override
Widget build(BuildContext context, StateTreeNode n) {
final api = n.read($api);
return FloatingActionButton(
onPressed: () {
final incrementBy10 = n.read($modifier);
api.increment(incrementBy10 ? 10 : 1);
},
child: const Icon(Icons.add),
);
}
}
abstract interface class ResetButtonApi {
void reset();
}
class ResetButton extends StateTreeWidget {
static const $api = Context<ResetButtonApi>(#reset_button_api);
const ResetButton({super.key});
@override
Widget build(BuildContext context, StateTreeNode n) {
return IconButton(
onPressed: n.read($api).reset,
icon: const Icon(Icons.refresh),
);
}
}