fst 0.2.9 fst: ^0.2.9 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 CounterImpl extends Impl<int> implements IncrementFABApi, ResetButtonApi {
const CounterImpl(super.n);
@override
int init(BuildContext context, StateTreeNode n) => 0;
@override
void increment() {
final delta = switch (n.read($modifier)) {
true => 10,
false => 1,
};
value += delta;
}
@override
void reset() => value = 0;
}
class ModifierImpl extends Impl<bool> {
const ModifierImpl(super.n);
@override
bool init(BuildContext context, StateTreeNode n) => false;
void onKey(RawKeyEvent e) {
value = e.isShiftPressed;
}
}
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)..provide($modifier);
final focusNode = n.init(FocusNode.new);
return RawKeyboardListener(
focusNode: focusNode,
autofocus: true,
onKey: impl.onKey,
child: child,
);
},
child: StateTreeBuilder<int>(
(context, n, child) {
final api = n.impl(CounterImpl.new)
..provide($count)
..map((v) => v < 25, IncrementFAB.$enabled);
n.provide(IncrementFAB.$api, api);
n.provide(ResetButton.$api, api);
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> {
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(
IncrementFAB.$enabled,
(e) => e ? const IncrementFAB() : null,
),
);
}
}
abstract interface class IncrementFABApi {
void increment();
}
class IncrementFAB extends StateTreeWidget {
static const $api = Context<IncrementFABApi>(#increment_fab_api);
static const $enabled = Context<bool>(#increment_fab_enabled);
const IncrementFAB({super.key});
@override
Widget build(BuildContext context, StateTreeNode n) {
return FloatingActionButton(
onPressed: n.read($api).increment,
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),
);
}
}