Skip to content

Instantly share code, notes, and snippets.

@abarth
Last active April 27, 2016 22:41
Show Gist options
  • Save abarth/cad90f75fd892effdc2836cecfdf5647 to your computer and use it in GitHub Desktop.
Save abarth/cad90f75fd892effdc2836cecfdf5647 to your computer and use it in GitHub Desktop.
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/widgets.dart';
/// ```dart
/// class FooModel extends Listenable {
/// String get bar => _bar;
/// String _bar;
/// void set bar(String value) {
/// if (_bar == value)
/// return;
/// _bar = value;
/// notifyListeners();
/// }
/// }
/// ```
class Listenable {
final Set<VoidCallback> _listeners = new Set<VoidCallback>();
void addListener(VoidCallback listener) {
assert(!_listeners.contains(listener));
_listeners.add(listener);
}
void removeListener(VoidCallback listener) {
assert(_listeners.contains(listener));
_listeners.remove(listener);
}
void notifyListeners() {
if (_notificationScheduled)
return;
_notificationScheduled = true;
scheduleMicrotask(_dispatchNotifications);
}
bool _notificationScheduled = false;
void _dispatchNotifications() {
_notificationScheduled = false;
List<VoidCallback> localListeners = new List<VoidCallback>.from(_listeners);
for (VoidCallback listener in localListeners)
listener();
}
}
/// ```dart
/// Widget build(BuildContext context) {
/// FooModel foo = const ModelProvider<FooModel>().of(context);
/// return new Text(foo.bar);
/// }
/// ```
class ModelProvider<T extends Listenable> extends InheritedWidget {
const ModelProvider({ Key key, Widget child, this.model }) : super(key: key, child: child);
T of(BuildContext context) {
ModelProvider<T> found = context.inheritFromWidgetOfExactType(runtimeType);
return found?.model;
}
final T model;
@override
bool updateShouldNotify(ModelProvider<T> oldWidget) => model != oldWidget.model;
@override
_ModelProviderElement createElement() => new _ModelProviderElement(this);
}
class _ModelProviderElement<T extends Listenable> extends InheritedElement {
_ModelProviderElement(ModelProvider<T> widget) : super(widget);
@override
ModelProvider<T> get widget => super.widget;
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
widget.model.addListener(dispatchDependenciesChanged);
}
@override
void update(ModelProvider<T> newWidget) {
final ModelProvider<T> oldWidget = widget;
super.update(newWidget);
if (oldWidget.model != newWidget.model) {
oldWidget.model.removeListener(dispatchDependenciesChanged);
newWidget.model.addListener(dispatchDependenciesChanged);
}
}
@override
void unmount() {
widget.model.removeListener(dispatchDependenciesChanged);
super.unmount();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment