提交 4c353a65 编写于 作者: C Collin Jackson

Refactor stateful parts of Component into StatefulComponent

R=abarth@chromium.org, abarth@google.com

Review URL: https://codereview.chromium.org/1217093005.
上级 6f19816e
......@@ -185,7 +185,7 @@ class Game {
void handleBannerPointerDown(sky.PointerEvent event) {
initialize();
app.setState((){});
app.scheduleBuild();
}
// User action. The user uncovers the cell which can cause losing the game.
......@@ -203,7 +203,7 @@ class Game {
// No mine, uncover nearby if possible.
cull(x, y);
}
app.setState((){});
app.scheduleBuild();
}
// User action. The user is sure a mine is at this location.
......@@ -215,7 +215,7 @@ class Game {
uiState[y][x] = flaggedCell;
++detectedCount;
}
app.setState((){});
app.scheduleBuild();
}
// Recursively uncovers cells whose totalMineCount is zero.
......
......@@ -29,9 +29,9 @@ import 'stock_types.dart';
typedef void ModeUpdater(StockMode mode);
class StockHome extends Component {
class StockHome extends StatefulComponent {
StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater) : super(stateful: true) {
StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater) {
// if (debug)
// new Timer(new Duration(seconds: 1), dumpState);
_drawerController = new DrawerController(_handleDrawerStatusChanged);
......
......@@ -21,9 +21,9 @@ typedef void SettingsUpdater({
BackupMode backup
});
class StockSettings extends Component {
class StockSettings extends StatefulComponent {
StockSettings(this.navigator, this.optimism, this.backup, this.updater) : super(stateful: true);
StockSettings(this.navigator, this.optimism, this.backup, this.updater);
Navigator navigator;
StockMode optimism;
......
......@@ -15,14 +15,14 @@ const _kCursorGap = 1.0;
const _kCursorHeightOffset = 2.0;
const _kCursorWidth = 1.0;
class EditableText extends Component {
class EditableText extends StatefulComponent {
EditableText({
String key,
this.value,
this.focused: false,
this.style,
this.cursorColor}) : super(key: key, stateful: true);
this.cursorColor}) : super(key: key);
EditableString value;
bool focused;
......
......@@ -14,13 +14,13 @@ typedef void ValueChanged(value);
const double _kHintOpacity = 0.26;
const EdgeDims _kTextfieldPadding = const EdgeDims.symmetric(vertical: 8.0);
class Input extends Component {
class Input extends StatefulComponent {
Input({String key,
this.placeholder,
this.onChanged,
this.focused})
: super(key: key, stateful: true) {
: super(key: key) {
_editableValue = new EditableString(
text: _value,
onUpdated: _handleTextUpdated
......
......@@ -254,8 +254,8 @@ class MyCheckbox extends Component {
}
}
class MyDialog extends Component {
MyDialog({ this.onDismissed }) : super(stateful: true);
class MyDialog extends StatefulComponent {
MyDialog({ this.onDismissed });
Function onDismissed;
bool _checkboxValue = false;
......@@ -298,8 +298,7 @@ component persists for the lifetime of the application.
The `MyDialog` component is more complicated because it is a stateful component.
Let's walk through the differences in `MyDialog` caused by its being stateful:
* `MyDialog` passes `stateful: true` to the `Component` constructor, marking
the component stateful.
* `MyDialog` extends StatefulComponent instead of Component.
* `MyDialog` has non-`final` member variables. Over the lifetime of the dialog,
we'll need to modify the values of these member variables, which means we
......
......@@ -17,9 +17,9 @@ class _AnimationEntry {
StreamSubscription<double> subscription;
}
abstract class AnimatedComponent extends Component {
abstract class AnimatedComponent extends StatefulComponent {
AnimatedComponent({ String key }) : super(key: key, stateful: true);
AnimatedComponent({ String key }) : super(key: key);
void syncFields(AnimatedComponent source) { }
......
......@@ -22,7 +22,7 @@ import 'widget.dart';
export '../rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
export '../rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems;
export '../rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
export 'widget.dart' show Widget, Component, App, runApp, Listener, ParentDataNode;
export 'widget.dart' show Widget, Component, StatefulComponent, App, runApp, Listener, ParentDataNode;
// PAINTING NODES
......@@ -505,8 +505,8 @@ class Image extends LeafRenderObjectWrapper {
}
}
class FutureImage extends Component {
FutureImage({ this.image, this.size }) : super(stateful: true);
class FutureImage extends StatefulComponent {
FutureImage({ this.image, this.size });
Future<sky.Image> image;
Size size;
......
......@@ -4,9 +4,9 @@
import 'basic.dart';
abstract class ButtonBase extends Component {
abstract class ButtonBase extends StatefulComponent {
ButtonBase({ String key, this.highlight: false }) : super(key: key, stateful: true);
ButtonBase({ String key, this.highlight: false }) : super(key: key);
bool highlight;
......
......@@ -74,9 +74,9 @@ class NavigationState {
}
}
class Navigator extends Component {
class Navigator extends StatefulComponent {
Navigator(this.state, { String key }) : super(key: key, stateful: true);
Navigator(this.state, { String key }) : super(key: key);
NavigationState state;
......
......@@ -24,13 +24,13 @@ abstract class ScrollClient {
enum ScrollDirection { vertical, horizontal }
abstract class Scrollable extends Component {
abstract class Scrollable extends StatefulComponent {
Scrollable({
String key,
this.backgroundColor,
this.direction: ScrollDirection.vertical
}) : super(key: key, stateful: true);
}) : super(key: key);
Color backgroundColor;
ScrollDirection direction;
......
......@@ -137,9 +137,6 @@ abstract class Widget {
// Returns the child which should be retained as the child of this node.
Widget syncChild(Widget newNode, Widget oldNode, dynamic slot) {
assert(oldNode is! Component ||
(oldNode is Component && !oldNode._disqualifiedFromEverAppearingAgain)); // TODO(ianh): Simplify this once the analyzer is cleverer
if (newNode == oldNode) {
assert(newNode == null || newNode.mounted);
assert(newNode is! RenderObjectWrapper ||
......@@ -359,26 +356,18 @@ class Listener extends TagNode {
abstract class Component extends Widget {
Component({ String key, bool stateful })
: _stateful = stateful != null ? stateful : false,
_order = _currentOrder + 1,
Component({ String key })
: _order = _currentOrder + 1,
super._withKey(key);
static Component _currentlyBuilding;
bool get _isBuilding => _currentlyBuilding == this;
bool _stateful;
bool _dirty = true;
bool _disqualifiedFromEverAppearingAgain = false;
Widget _built;
dynamic _slot; // cached slot from the last time we were synced
void didMount() {
assert(!_disqualifiedFromEverAppearingAgain);
super.didMount();
}
void remove() {
assert(_built != null);
assert(root != null);
......@@ -408,38 +397,6 @@ abstract class Component extends Widget {
scheduleBuild();
}
bool _retainStatefulNodeIfPossible(Component old) {
assert(!_disqualifiedFromEverAppearingAgain);
if (old == null || !old._stateful)
return false;
assert(runtimeType == old.runtimeType);
assert(key == old.key);
// Make |this|, the newly-created object, into the "old" Component, and kill it
_stateful = false;
_built = old._built;
assert(_built != null);
_disqualifiedFromEverAppearingAgain = true;
// Make |old| the "new" component
old._built = null;
old._dirty = true;
old.syncFields(this);
return true;
}
// This is called by _retainStatefulNodeIfPossible(), during
// syncChild(), just before _sync() is called.
// This must be implemented on any subclass that can become stateful
// (but don't call super.syncFields() if you inherit directly from
// Component, since that'll fire an assert).
// If you don't ever become stateful, then don't override this.
void syncFields(Component source) {
assert(false);
}
// order corresponds to _build_ order, not depth in the tree.
// All the Components built by a particular other Component will have the
// same order, regardless of whether one is subsequently inserted
......@@ -457,7 +414,6 @@ abstract class Component extends Widget {
// assert(_built == null && old != null)
void _sync(Component old, dynamic slot) {
assert(_built == null || old == null);
assert(!_disqualifiedFromEverAppearingAgain);
_slot = slot;
......@@ -487,7 +443,6 @@ abstract class Component extends Widget {
}
void _buildIfDirty() {
assert(!_disqualifiedFromEverAppearingAgain);
if (!_dirty || !_mounted)
return;
......@@ -496,21 +451,76 @@ abstract class Component extends Widget {
}
void scheduleBuild() {
assert(!_disqualifiedFromEverAppearingAgain);
if (_isBuilding || _dirty || !_mounted)
return;
_dirty = true;
_scheduleComponentForRender(this);
}
Widget build();
}
abstract class StatefulComponent extends Component {
StatefulComponent({ String key }) : super(key: key);
bool _disqualifiedFromEverAppearingAgain = false;
void didMount() {
assert(!_disqualifiedFromEverAppearingAgain);
super.didMount();
}
void _buildIfDirty() {
assert(!_disqualifiedFromEverAppearingAgain);
super._buildIfDirty();
}
void _sync(Widget old, dynamic slot) {
assert(!_disqualifiedFromEverAppearingAgain);
super._sync(old, slot);
}
Widget syncChild(Widget node, Widget oldNode, dynamic slot) {
assert(!_disqualifiedFromEverAppearingAgain);
return super.syncChild(node, oldNode, slot);
}
bool _retainStatefulNodeIfPossible(StatefulComponent old) {
assert(!_disqualifiedFromEverAppearingAgain);
if (old == null)
return false;
assert(runtimeType == old.runtimeType);
assert(key == old.key);
// Make |this|, the newly-created object, into the "old" Component, and kill it
_built = old._built;
assert(_built != null);
_disqualifiedFromEverAppearingAgain = true;
// Make |old| the "new" component
old._built = null;
old._dirty = true;
old.syncFields(this);
return true;
}
// This is called by _retainStatefulNodeIfPossible(), during
// syncChild(), just before _sync() is called. Derived
// classes should override this method to update `this` to
// account for the new values the parent passed to `source`.
// Make sure to call super.syncFields(source) unless you are
// extending StatefulComponent directly.
void syncFields(Component source);
void setState(Function fn()) {
assert(_stateful);
assert(!_disqualifiedFromEverAppearingAgain);
fn();
scheduleBuild();
}
Widget build();
}
Set<Component> _dirtyComponents = new Set<Component>();
......@@ -930,10 +940,9 @@ class WidgetSkyBinding extends SkyBinding {
}
abstract class App extends Component {
abstract class App extends StatefulComponent {
// Apps are assumed to be stateful
App({ String key }) : super(key: key, stateful: true);
App({ String key }) : super(key: key);
void _handleEvent(sky.Event event) {
if (event.type == 'back')
......@@ -950,13 +959,15 @@ abstract class App extends Component {
SkyBinding.instance.removeEventListener(_handleEvent);
}
void syncFields(Component source) { }
// Override this to handle back button behavior in your app
void onBack() { }
}
abstract class AbstractWidgetRoot extends Component {
abstract class AbstractWidgetRoot extends StatefulComponent {
AbstractWidgetRoot() : super(stateful: true) {
AbstractWidgetRoot() {
_mounted = true;
_scheduleComponentForRender(this);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册