Skip to content

Instantly share code, notes, and snippets.

@HansMuller
Created October 19, 2021 19:18
Show Gist options
  • Select an option

  • Save HansMuller/58ff48447f162e8948b3f805675ca6ab to your computer and use it in GitHub Desktop.

Select an option

Save HansMuller/58ff48447f162e8948b3f805675ca6ab to your computer and use it in GitHub Desktop.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// Enables sharing keyword value data with an entire app.
//
// AppModel.set(context, keyword, value) adds an entry to the shared data table.
//
// AppModel.get(context, keyword) returns the value for keyword or null.
//
// A widget whose build method uses AppModel.get(context, keyword)
// creates a dependency on the AppModel: when the value of keyword
// changes with AppModel.set(), the widget will be rebuilt.
//
// This Widget would be created above the WidgetApp, so that it's always available.
class AppModel extends StatefulWidget {
AppModel({ Key? key, required this.child }) : super(key: key);
final Widget child;
@override
_AppModelState createState() => _AppModelState();
static Object? get(BuildContext context, Object key) {
final _AppModelData model = InheritedModel.inheritFrom<_AppModelData>(context, aspect: key)!;
return model.appModelState.get(key);
}
static void set(BuildContext context, Object key, Object value) {
final _AppModelData model = context.findAncestorWidgetOfExactType<_AppModelData>()!;
model.appModelState.set(key, value);
}
}
class _AppModelState extends State<AppModel> {
late Map<Object, Object> data;
@override
void initState() {
super.initState();
data = Map<Object, Object>();
}
@override
Widget build(BuildContext context) {
return _AppModelData(appModelState: this, child: widget.child);
}
Object? get(Object key) => data[key];
void set(Object key, Object value) {
if (data[key] != value) {
setState(() {
data = Map.from(data);
data[key] = value;
});
}
}
}
class _AppModelData extends InheritedModel<Object> {
_AppModelData({
Key? key,
required this.appModelState,
required Widget child
}) : data = appModelState.data, super(key: key, child: child);
final _AppModelState appModelState;
final Map<Object, Object> data;
@override
bool updateShouldNotify(_AppModelData old) {
return data != old.data;
}
@override
bool updateShouldNotifyDependent(_AppModelData old, Set<Object> keys) {
for (Object key in keys) {
if (data[key] != old.data[key]) {
return true;
}
}
return false;
}
}
// Displays the value of AppModel.get(context, appModelKey) and the number of times
// that this widget has been built.
class ShowAppModelValue extends StatefulWidget {
const ShowAppModelValue(this.appModelKey);
final Object appModelKey;
@override
_ShowAppModelValueState createState() => _ShowAppModelValueState();
}
class _ShowAppModelValueState extends State<ShowAppModelValue> {
int _buildCount = 0;
@override
Widget build(BuildContext context) {
_buildCount += 1;
return Padding(
padding: EdgeInsets.only(bottom: 16),
child: Text('${widget.appModelKey}: ${AppModel.get(context, widget.appModelKey)} [$_buildCount]'),
);
}
}
// Demonstrates that changes to the AppModel _only_ cause the dependent widgets
// to be rebuilt.
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _fooCount = 0;
int _barCount = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShowAppModelValue('Home'), // Only built when the app is launched
ShowAppModelValue('foo'), // Built each time the foo button is pressed
ShowAppModelValue('bar'), // Built each time the bar button is pressed
ElevatedButton(
child: Text('foo = FOO'),
onPressed: () {
_fooCount += 1;
AppModel.set(context, 'foo', 'FOO $_fooCount'); // note: no setState()
},
),
SizedBox(height: 16),
ElevatedButton(
child: Text('bar = BAR'),
onPressed: () {
_barCount += 1;
AppModel.set(context, 'bar', 'BAR $_barCount'); // note: no setState()
},
),
],
),
),
);
}
}
void main() {
runApp(
AppModel(child: MaterialApp(home: Home())),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment