Skip to content

Instantly share code, notes, and snippets.

@brianegan
Created March 19, 2019 12:40
Show Gist options
  • Save brianegan/799c8390f50576137d5bd2e02129da9c to your computer and use it in GitHub Desktop.
Save brianegan/799c8390f50576137d5bd2e02129da9c to your computer and use it in GitHub Desktop.
Live Coded Scoped Model
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _counter = Counter();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ScopedCounter(
child: HomePageBody(counter: _counter),
counter: _counter,
),
floatingActionButton: FloatingActionButton(
onPressed: _counter.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class HomePageBody extends StatelessWidget {
const HomePageBody({
Key key,
@required Counter counter,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
ScopedCounterDescendant(
builder: (context, counter) {
return Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
);
},
),
],
),
);
}
}
class ScopedCounter extends StatelessWidget {
final Counter counter;
final Widget child;
const ScopedCounter({Key key, this.counter, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: counter,
builder: (context, _) {
return InheritedCounter(
counter: counter,
child: child,
);
},
);
}
static Counter of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(InheritedCounter)
as InheritedCounter)
.counter;
}
}
class InheritedCounter extends InheritedWidget {
final Counter counter;
const InheritedCounter({
Key key,
@required Widget child,
@required this.counter,
}) : assert(child != null),
super(key: key, child: child);
@override
bool updateShouldNotify(InheritedCounter old) {
return true;
}
}
class ScopedCounterDescendant extends StatelessWidget {
final Widget Function(BuildContext, Counter) builder;
const ScopedCounterDescendant({Key key, this.builder}) : super(key: key);
@override
Widget build(BuildContext context) {
final counter = ScopedCounter.of(context);
return builder(context, counter);
}
}
import 'package:flutter/foundation.dart';
class Model implements Listenable {
final _listeners = Set<void Function()>();
bool get hasListeners => _listeners.isNotEmpty;
void addListener(void Function() listener) => _listeners.add(listener);
void removeListener(void Function() listener) => _listeners.remove(listener);
void notifyListeners() => _listeners.forEach((listener) => listener());
}
import 'package:flutter_test/flutter_test.dart';
import 'package:live_scoped_model/model.dart';
void main() {
group('Model', () {
test('should add a listner', () {
final model = Model();
model.addListener(() {});
expect(model.hasListeners, isTrue);
});
test('should remove a listener', () {
final model = Model();
void listener() {}
model.addListener(listener);
model.removeListener(listener);
expect(model.hasListeners, isFalse);
});
test('should notify', () {
final model = Model();
int callCount = 0;
model.addListener(() {
callCount++;
});
model.notifyListeners();
expect(callCount, 1);
});
});
}
@Mawulijo
Copy link

Awesome concept

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment