Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: sky/sdk/lib/widgets/widget.dart

Issue 1217093005: Refactor stateful parts of Component into StatefulComponent (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: rebase Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/lib/widgets/scrollable.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 import 'dart:mirrors'; 7 import 'dart:mirrors';
8 import 'dart:sky' as sky; 8 import 'dart:sky' as sky;
9 9
10 import '../base/hit_test.dart'; 10 import '../base/hit_test.dart';
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 // belonged to the old node, continue to live on in the replacement node. 130 // belonged to the old node, continue to live on in the replacement node.
131 node.remove(); 131 node.remove();
132 assert(node.parent == null); 132 assert(node.parent == null);
133 } 133 }
134 134
135 void detachRoot(); 135 void detachRoot();
136 136
137 // Returns the child which should be retained as the child of this node. 137 // Returns the child which should be retained as the child of this node.
138 Widget syncChild(Widget newNode, Widget oldNode, dynamic slot) { 138 Widget syncChild(Widget newNode, Widget oldNode, dynamic slot) {
139 139
140 assert(oldNode is! Component ||
141 (oldNode is Component && !oldNode._disqualifiedFromEverAppearingAgain )); // TODO(ianh): Simplify this once the analyzer is cleverer
142
143 if (newNode == oldNode) { 140 if (newNode == oldNode) {
144 assert(newNode == null || newNode.mounted); 141 assert(newNode == null || newNode.mounted);
145 assert(newNode is! RenderObjectWrapper || 142 assert(newNode is! RenderObjectWrapper ||
146 (newNode is RenderObjectWrapper && newNode._ancestor != null)); // TODO(ianh): Simplify this once the analyzer is cleverer 143 (newNode is RenderObjectWrapper && newNode._ancestor != null)); // TODO(ianh): Simplify this once the analyzer is cleverer
147 if (newNode != null) 144 if (newNode != null)
148 newNode.setParent(this); 145 newNode.setParent(this);
149 return newNode; // Nothing to do. Subtrees must be identical. 146 return newNode; // Nothing to do. Subtrees must be identical.
150 } 147 }
151 148
152 if (newNode == null) { 149 if (newNode == null) {
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 sky.EventListener listener = listeners[e.type]; 349 sky.EventListener listener = listeners[e.type];
353 if (listener != null) { 350 if (listener != null) {
354 listener(e); 351 listener(e);
355 } 352 }
356 } 353 }
357 354
358 } 355 }
359 356
360 abstract class Component extends Widget { 357 abstract class Component extends Widget {
361 358
362 Component({ String key, bool stateful }) 359 Component({ String key })
363 : _stateful = stateful != null ? stateful : false, 360 : _order = _currentOrder + 1,
364 _order = _currentOrder + 1,
365 super._withKey(key); 361 super._withKey(key);
366 362
367 static Component _currentlyBuilding; 363 static Component _currentlyBuilding;
368 bool get _isBuilding => _currentlyBuilding == this; 364 bool get _isBuilding => _currentlyBuilding == this;
369 365
370 bool _stateful;
371 bool _dirty = true; 366 bool _dirty = true;
372 bool _disqualifiedFromEverAppearingAgain = false;
373 367
374 Widget _built; 368 Widget _built;
375 dynamic _slot; // cached slot from the last time we were synced 369 dynamic _slot; // cached slot from the last time we were synced
376 370
377 void didMount() {
378 assert(!_disqualifiedFromEverAppearingAgain);
379 super.didMount();
380 }
381
382 void remove() { 371 void remove() {
383 assert(_built != null); 372 assert(_built != null);
384 assert(root != null); 373 assert(root != null);
385 removeChild(_built); 374 removeChild(_built);
386 _built = null; 375 _built = null;
387 super.remove(); 376 super.remove();
388 } 377 }
389 378
390 void detachRoot() { 379 void detachRoot() {
391 assert(_built != null); 380 assert(_built != null);
392 assert(root != null); 381 assert(root != null);
393 _built.detachRoot(); 382 _built.detachRoot();
394 } 383 }
395 384
396 Set<Type> _dependencies; 385 Set<Type> _dependencies;
397 Inherited inheritedOfType(Type targetType) { 386 Inherited inheritedOfType(Type targetType) {
398 if (_dependencies == null) 387 if (_dependencies == null)
399 _dependencies = new Set<Type>(); 388 _dependencies = new Set<Type>();
400 _dependencies.add(targetType); 389 _dependencies.add(targetType);
401 Widget ancestor = parent; 390 Widget ancestor = parent;
402 while (ancestor != null && ancestor.runtimeType != targetType) 391 while (ancestor != null && ancestor.runtimeType != targetType)
403 ancestor = ancestor.parent; 392 ancestor = ancestor.parent;
404 return ancestor; 393 return ancestor;
405 } 394 }
406 void _dependenciesChanged() { 395 void _dependenciesChanged() {
407 // called by Inherited.sync() 396 // called by Inherited.sync()
408 scheduleBuild(); 397 scheduleBuild();
409 } 398 }
410 399
411 bool _retainStatefulNodeIfPossible(Component old) {
412 assert(!_disqualifiedFromEverAppearingAgain);
413
414 if (old == null || !old._stateful)
415 return false;
416
417 assert(runtimeType == old.runtimeType);
418 assert(key == old.key);
419
420 // Make |this|, the newly-created object, into the "old" Component, and kill it
421 _stateful = false;
422 _built = old._built;
423 assert(_built != null);
424 _disqualifiedFromEverAppearingAgain = true;
425
426 // Make |old| the "new" component
427 old._built = null;
428 old._dirty = true;
429 old.syncFields(this);
430 return true;
431 }
432
433 // This is called by _retainStatefulNodeIfPossible(), during
434 // syncChild(), just before _sync() is called.
435 // This must be implemented on any subclass that can become stateful
436 // (but don't call super.syncFields() if you inherit directly from
437 // Component, since that'll fire an assert).
438 // If you don't ever become stateful, then don't override this.
439 void syncFields(Component source) {
440 assert(false);
441 }
442
443 // order corresponds to _build_ order, not depth in the tree. 400 // order corresponds to _build_ order, not depth in the tree.
444 // All the Components built by a particular other Component will have the 401 // All the Components built by a particular other Component will have the
445 // same order, regardless of whether one is subsequently inserted 402 // same order, regardless of whether one is subsequently inserted
446 // into another. The order is used to not tell a Component to 403 // into another. The order is used to not tell a Component to
447 // rebuild if the Component that it built has itself been rebuilt. 404 // rebuild if the Component that it built has itself been rebuilt.
448 final int _order; 405 final int _order;
449 static int _currentOrder = 0; 406 static int _currentOrder = 0;
450 407
451 // There are three cases here: 408 // There are three cases here:
452 // 1) Building for the first time: 409 // 1) Building for the first time:
453 // assert(_built == null && old == null) 410 // assert(_built == null && old == null)
454 // 2) Re-building (because a dirty flag got set): 411 // 2) Re-building (because a dirty flag got set):
455 // assert(_built != null && old == null) 412 // assert(_built != null && old == null)
456 // 3) Syncing against an old version 413 // 3) Syncing against an old version
457 // assert(_built == null && old != null) 414 // assert(_built == null && old != null)
458 void _sync(Component old, dynamic slot) { 415 void _sync(Component old, dynamic slot) {
459 assert(_built == null || old == null); 416 assert(_built == null || old == null);
460 assert(!_disqualifiedFromEverAppearingAgain);
461 417
462 _slot = slot; 418 _slot = slot;
463 419
464 var oldBuilt; 420 var oldBuilt;
465 if (old == null) { 421 if (old == null) {
466 oldBuilt = _built; 422 oldBuilt = _built;
467 } else { 423 } else {
468 assert(_built == null); 424 assert(_built == null);
469 oldBuilt = old._built; 425 oldBuilt = old._built;
470 } 426 }
471 427
472 int lastOrder = _currentOrder; 428 int lastOrder = _currentOrder;
473 _currentOrder = _order; 429 _currentOrder = _order;
474 _currentlyBuilding = this; 430 _currentlyBuilding = this;
475 _built = build(); 431 _built = build();
476 assert(_built != null); 432 assert(_built != null);
477 _currentlyBuilding = null; 433 _currentlyBuilding = null;
478 _currentOrder = lastOrder; 434 _currentOrder = lastOrder;
479 435
480 _built = syncChild(_built, oldBuilt, slot); 436 _built = syncChild(_built, oldBuilt, slot);
481 assert(_built != null); 437 assert(_built != null);
482 assert(_built.parent == this); 438 assert(_built.parent == this);
483 _dirty = false; 439 _dirty = false;
484 _root = _built.root; 440 _root = _built.root;
485 assert(_root == root); // in case a subclass reintroduces it 441 assert(_root == root); // in case a subclass reintroduces it
486 assert(root != null); 442 assert(root != null);
487 } 443 }
488 444
489 void _buildIfDirty() { 445 void _buildIfDirty() {
490 assert(!_disqualifiedFromEverAppearingAgain);
491 if (!_dirty || !_mounted) 446 if (!_dirty || !_mounted)
492 return; 447 return;
493 448
494 assert(root != null); 449 assert(root != null);
495 _sync(null, _slot); 450 _sync(null, _slot);
496 } 451 }
497 452
498 void scheduleBuild() { 453 void scheduleBuild() {
499 assert(!_disqualifiedFromEverAppearingAgain);
500 if (_isBuilding || _dirty || !_mounted) 454 if (_isBuilding || _dirty || !_mounted)
501 return; 455 return;
502 _dirty = true; 456 _dirty = true;
503 _scheduleComponentForRender(this); 457 _scheduleComponentForRender(this);
504 } 458 }
505 459
506 void setState(Function fn()) {
507 assert(_stateful);
508 fn();
509 scheduleBuild();
510 }
511
512 Widget build(); 460 Widget build();
513 461
514 } 462 }
515 463
464 abstract class StatefulComponent extends Component {
465
466 StatefulComponent({ String key }) : super(key: key);
467
468 bool _disqualifiedFromEverAppearingAgain = false;
469
470 void didMount() {
471 assert(!_disqualifiedFromEverAppearingAgain);
472 super.didMount();
473 }
474
475 void _buildIfDirty() {
476 assert(!_disqualifiedFromEverAppearingAgain);
477 super._buildIfDirty();
478 }
479
480 void _sync(Widget old, dynamic slot) {
481 assert(!_disqualifiedFromEverAppearingAgain);
482 super._sync(old, slot);
483 }
484
485 Widget syncChild(Widget node, Widget oldNode, dynamic slot) {
486 assert(!_disqualifiedFromEverAppearingAgain);
487 return super.syncChild(node, oldNode, slot);
488 }
489
490 bool _retainStatefulNodeIfPossible(StatefulComponent old) {
491 assert(!_disqualifiedFromEverAppearingAgain);
492
493 if (old == null)
494 return false;
495
496 assert(runtimeType == old.runtimeType);
497 assert(key == old.key);
498
499 // Make |this|, the newly-created object, into the "old" Component, and kill it
500 _built = old._built;
501 assert(_built != null);
502 _disqualifiedFromEverAppearingAgain = true;
503
504 // Make |old| the "new" component
505 old._built = null;
506 old._dirty = true;
507 old.syncFields(this);
508 return true;
509 }
510
511 // This is called by _retainStatefulNodeIfPossible(), during
512 // syncChild(), just before _sync() is called. Derived
513 // classes should override this method to update `this` to
514 // account for the new values the parent passed to `source`.
515 // Make sure to call super.syncFields(source) unless you are
516 // extending StatefulComponent directly.
517 void syncFields(Component source);
518
519 void setState(Function fn()) {
520 assert(!_disqualifiedFromEverAppearingAgain);
521 fn();
522 scheduleBuild();
523 }
524 }
525
516 Set<Component> _dirtyComponents = new Set<Component>(); 526 Set<Component> _dirtyComponents = new Set<Component>();
517 bool _buildScheduled = false; 527 bool _buildScheduled = false;
518 bool _inRenderDirtyComponents = false; 528 bool _inRenderDirtyComponents = false;
519 529
520 List<int> _debugFrameTimes = <int>[]; 530 List<int> _debugFrameTimes = <int>[];
521 531
522 void _absorbDirtyComponents(List<Component> list) { 532 void _absorbDirtyComponents(List<Component> list) {
523 list.addAll(_dirtyComponents); 533 list.addAll(_dirtyComponents);
524 _dirtyComponents.clear(); 534 _dirtyComponents.clear();
525 list.sort((Component a, Component b) => a._order - b._order); 535 list.sort((Component a, Component b) => a._order - b._order);
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 while (target != null && target.root == targetRoot) { 933 while (target != null && target.root == targetRoot) {
924 if (target is Listener) 934 if (target is Listener)
925 target._handleEvent(event); 935 target._handleEvent(event);
926 target = target._parent; 936 target = target._parent;
927 } 937 }
928 } 938 }
929 } 939 }
930 940
931 } 941 }
932 942
933 abstract class App extends Component { 943 abstract class App extends StatefulComponent {
934 944
935 // Apps are assumed to be stateful 945 App({ String key }) : super(key: key);
936 App({ String key }) : super(key: key, stateful: true);
937 946
938 void _handleEvent(sky.Event event) { 947 void _handleEvent(sky.Event event) {
939 if (event.type == 'back') 948 if (event.type == 'back')
940 onBack(); 949 onBack();
941 } 950 }
942 951
943 void didMount() { 952 void didMount() {
944 super.didMount(); 953 super.didMount();
945 SkyBinding.instance.addEventListener(_handleEvent); 954 SkyBinding.instance.addEventListener(_handleEvent);
946 } 955 }
947 956
948 void didUnmount() { 957 void didUnmount() {
949 super.didUnmount(); 958 super.didUnmount();
950 SkyBinding.instance.removeEventListener(_handleEvent); 959 SkyBinding.instance.removeEventListener(_handleEvent);
951 } 960 }
952 961
962 void syncFields(Component source) { }
963
953 // Override this to handle back button behavior in your app 964 // Override this to handle back button behavior in your app
954 void onBack() { } 965 void onBack() { }
955 } 966 }
956 967
957 abstract class AbstractWidgetRoot extends Component { 968 abstract class AbstractWidgetRoot extends StatefulComponent {
958 969
959 AbstractWidgetRoot() : super(stateful: true) { 970 AbstractWidgetRoot() {
960 _mounted = true; 971 _mounted = true;
961 _scheduleComponentForRender(this); 972 _scheduleComponentForRender(this);
962 } 973 }
963 974
964 void syncFields(AbstractWidgetRoot source) { 975 void syncFields(AbstractWidgetRoot source) {
965 assert(false); 976 assert(false);
966 // if we get here, it implies that we have a parent 977 // if we get here, it implies that we have a parent
967 } 978 }
968 979
969 void _buildIfDirty() { 980 void _buildIfDirty() {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1034 if (root.parent == null) { 1045 if (root.parent == null) {
1035 // we haven't attached it yet 1046 // we haven't attached it yet
1036 assert(_container.child == null); 1047 assert(_container.child == null);
1037 _container.child = root; 1048 _container.child = root;
1038 } 1049 }
1039 assert(root.parent == _container); 1050 assert(root.parent == _container);
1040 } 1051 }
1041 1052
1042 Widget build() => builder(); 1053 Widget build() => builder();
1043 } 1054 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/widgets/scrollable.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698