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

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

Issue 1232673003: Delete drawerController and make drawer handle back behavior natively (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: fix settings page of fitness app 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/example/stocks/lib/stock_home.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:sky' as sky; 5 import 'dart:sky' as sky;
6 6
7 import 'package:sky/animation/animation_performance.dart'; 7 import 'package:sky/animation/animation_performance.dart';
8 import 'package:sky/animation/curves.dart'; 8 import 'package:sky/animation/curves.dart';
9 import 'package:sky/theme/shadows.dart'; 9 import 'package:sky/theme/shadows.dart';
10 import 'package:sky/widgets/animated_component.dart'; 10 import 'package:sky/widgets/animated_component.dart';
11 import 'package:sky/widgets/animation_builder.dart'; 11 import 'package:sky/widgets/animation_builder.dart';
12 import 'package:sky/widgets/basic.dart'; 12 import 'package:sky/widgets/basic.dart';
13 import 'package:sky/widgets/navigator.dart';
13 import 'package:sky/widgets/scrollable_viewport.dart'; 14 import 'package:sky/widgets/scrollable_viewport.dart';
14 import 'package:sky/widgets/theme.dart'; 15 import 'package:sky/widgets/theme.dart';
15 16
16 // TODO(eseidel): Draw width should vary based on device size: 17 // TODO(eseidel): Draw width should vary based on device size:
17 // http://www.google.com/design/spec/layout/structure.html#structure-side-nav 18 // http://www.google.com/design/spec/layout/structure.html#structure-side-nav
18 19
19 // Mobile: 20 // Mobile:
20 // Width = Screen width − 56 dp 21 // Width = Screen width − 56 dp
21 // Maximum width: 320dp 22 // Maximum width: 320dp
22 // Maximum width applies only when using a left nav. When using a right nav, 23 // Maximum width applies only when using a left nav. When using a right nav,
23 // the panel can cover the full width of the screen. 24 // the panel can cover the full width of the screen.
24 25
25 // Desktop/Tablet: 26 // Desktop/Tablet:
26 // Maximum width for a left nav is 400dp. 27 // Maximum width for a left nav is 400dp.
27 // The right nav can vary depending on content. 28 // The right nav can vary depending on content.
28 29
29 const double _kWidth = 304.0; 30 const double _kWidth = 304.0;
30 const double _kMinFlingVelocity = 0.4; 31 const double _kMinFlingVelocity = 0.4;
31 const Duration _kBaseSettleDuration = const Duration(milliseconds: 246); 32 const Duration _kBaseSettleDuration = const Duration(milliseconds: 246);
32 // TODO(mpcomplete): The curve must be linear if we want the drawer to track 33 // TODO(mpcomplete): The curve must be linear if we want the drawer to track
33 // the user's finger. Odeon remedies this by attaching spring forces to the 34 // the user's finger. Odeon remedies this by attaching spring forces to the
34 // initial timeline when animating (so it doesn't look linear). 35 // initial timeline when animating (so it doesn't look linear).
35 const Curve _kAnimationCurve = linear; 36 const Curve _kAnimationCurve = linear;
36 37
37 typedef void DrawerStatusChangeHandler (bool showing); 38 typedef void DrawerStatusChangeHandler (bool showing);
38 39
39 class DrawerController { 40 enum DrawerStatus {
40 DrawerController(this.onStatusChange) { 41 active,
41 builder = new AnimationBuilder() 42 inactive,
42 ..position = new AnimatedType<Point>( 43 }
43 new Point(-_kWidth, 0.0), end: Point.origin, curve: _kAnimationCurve);
44 performance = builder.createPerformance([builder.position],
45 duration: _kBaseSettleDuration)
46 ..addListener(_checkValue);
47 }
48 final DrawerStatusChangeHandler onStatusChange;
49 44
50 AnimationPerformance performance; 45 typedef void DrawerStatusChangedCallback(DrawerStatus status);
51 AnimationBuilder builder;
52
53 double get xPosition => builder.position.value.x;
54
55 bool _oldClosedState = true;
56 void _checkValue() {
57 var newClosedState = isClosed;
58 if (onStatusChange != null && _oldClosedState != newClosedState) {
59 onStatusChange(!newClosedState);
60 _oldClosedState = newClosedState;
61 }
62 }
63
64 bool get isClosed => performance.isDismissed;
65 bool get _isMostlyClosed => xPosition <= -_kWidth/2;
66
67 void open() => performance.play();
68
69 void close() => performance.reverse();
70
71 void _settle() => _isMostlyClosed ? close() : open();
72
73 void handleMaskTap(_) => close();
74
75 // TODO(mpcomplete): Figure out how to generalize these handlers on a
76 // "PannableThingy" interface.
77 void handlePointerDown(_) => performance.stop();
78
79 void handlePointerMove(sky.PointerEvent event) {
80 if (performance.isAnimating)
81 return;
82 performance.progress += event.dx / _kWidth;
83 }
84
85 void handlePointerUp(_) {
86 if (!performance.isAnimating)
87 _settle();
88 }
89
90 void handlePointerCancel(_) {
91 if (!performance.isAnimating)
92 _settle();
93 }
94
95 void handleFlingStart(event) {
96 double velocityX = event.velocityX / 1000;
97 if (velocityX.abs() >= _kMinFlingVelocity)
98 performance.fling(velocity: velocityX / _kWidth);
99 }
100 }
101 46
102 class Drawer extends AnimatedComponent { 47 class Drawer extends AnimatedComponent {
103 Drawer({ 48 Drawer({
104 String key, 49 String key,
105 this.controller,
106 this.children, 50 this.children,
107 this.level: 0 51 this.showing: false,
52 this.level: 0,
53 this.onStatusChanged,
54 this.navigator
108 }) : super(key: key); 55 }) : super(key: key);
109 56
110 List<Widget> children; 57 List<Widget> children;
58 bool showing;
111 int level; 59 int level;
112 DrawerController controller; 60 DrawerStatusChangedCallback onStatusChanged;
61 Navigator navigator;
62
63 AnimationPerformance _performance;
64 AnimationBuilder _builder;
113 65
114 void initState() { 66 void initState() {
115 watch(controller.performance); 67 _builder = new AnimationBuilder()
68 ..position = new AnimatedType<Point>(
69 new Point(-_kWidth, 0.0), end: Point.origin, curve: _kAnimationCurve);
70 _performance = _builder.createPerformance([_builder.position],
71 duration: _kBaseSettleDuration)
72 ..addListener(_checkForStateChanged);
73 watch(_performance);
74 if (showing)
75 _performance.play();
116 } 76 }
117 77
118 void syncFields(Drawer source) { 78 void syncFields(Drawer source) {
79 const String kDrawerRouteName = "[open drawer]";
119 children = source.children; 80 children = source.children;
120 level = source.level; 81 level = source.level;
121 controller = source.controller; 82 navigator = source.navigator;
83 if (showing != source.showing) {
84 showing = source.showing;
85 if (showing) {
86 if (navigator != null) {
87 navigator.pushState(kDrawerRouteName, (_) {
88 onStatusChanged(DrawerStatus.inactive);
89 });
90 }
91 _performance.play();
92 } else {
93 if (navigator != null && navigator.currentRoute.name == kDrawerRouteName )
94 navigator.pop();
95 _performance.reverse();
96 }
97 }
98 onStatusChanged = source.onStatusChanged;
122 super.syncFields(source); 99 super.syncFields(source);
123 } 100 }
124 101
125 // TODO(mpcomplete): the animation system should handle building, maybe? Or 102 // TODO(mpcomplete): the animation system should handle building, maybe? Or
126 // at least setting the transform. Figure out how this could work for things 103 // at least setting the transform. Figure out how this could work for things
127 // like fades, slides, rotates, pinch, etc. 104 // like fades, slides, rotates, pinch, etc.
128 Widget build() { 105 Widget build() {
129 // TODO(mpcomplete): animate as a fade-in. 106 // TODO(mpcomplete): animate as a fade-in.
130 double scaler = controller.performance.progress; 107 double scaler = _performance.progress;
131 Color maskColor = new Color.fromARGB((0x7F * scaler).floor(), 0, 0, 0); 108 Color maskColor = new Color.fromARGB((0x7F * scaler).floor(), 0, 0, 0);
132 109
133 var mask = new Listener( 110 var mask = new Listener(
134 child: new Container(decoration: new BoxDecoration(backgroundColor: maskCo lor)), 111 child: new Container(decoration: new BoxDecoration(backgroundColor: maskCo lor)),
135 onGestureTap: controller.handleMaskTap 112 onGestureTap: handleMaskTap
136 ); 113 );
137 114
138 Widget content = controller.builder.build( 115 Widget content = _builder.build(
139 new Container( 116 new Container(
140 decoration: new BoxDecoration( 117 decoration: new BoxDecoration(
141 backgroundColor: Theme.of(this).canvasColor, 118 backgroundColor: Theme.of(this).canvasColor,
142 boxShadow: shadows[level]), 119 boxShadow: shadows[level]),
143 width: _kWidth, 120 width: _kWidth,
144 child: new ScrollableBlock(children) 121 child: new ScrollableBlock(children)
145 )); 122 ));
146 123
147 return new Listener( 124 return new Listener(
148 child: new Stack([ mask, content ]), 125 child: new Stack([ mask, content ]),
149 onPointerDown: controller.handlePointerDown, 126 onPointerDown: handlePointerDown,
150 onPointerMove: controller.handlePointerMove, 127 onPointerMove: handlePointerMove,
151 onPointerUp: controller.handlePointerUp, 128 onPointerUp: handlePointerUp,
152 onPointerCancel: controller.handlePointerCancel, 129 onPointerCancel: handlePointerCancel,
153 onGestureFlingStart: controller.handleFlingStart 130 onGestureFlingStart: handleFlingStart
154 ); 131 );
155 } 132 }
156 133
134 double get xPosition => _builder.position.value.x;
135
136 DrawerStatus _lastStatus;
137 void _checkForStateChanged() {
138 DrawerStatus status = _status;
139 if (_lastStatus != null && status != _lastStatus && onStatusChanged != null)
140 onStatusChanged(status);
141 _lastStatus = status;
142 }
143
144 DrawerStatus get _status => _performance.isDismissed ? DrawerStatus.inactive : DrawerStatus.active;
145 bool get _isMostlyClosed => xPosition <= -_kWidth/2;
146
147 void _settle() => _isMostlyClosed ? _performance.reverse() : _performance.play ();
148
149 void handleMaskTap(_) => _performance.reverse();
150
151 // TODO(mpcomplete): Figure out how to generalize these handlers on a
152 // "PannableThingy" interface.
153 void handlePointerDown(_) => _performance.stop();
154
155 void handlePointerMove(sky.PointerEvent event) {
156 if (_performance.isAnimating)
157 return;
158 _performance.progress += event.dx / _kWidth;
159 }
160
161 void handlePointerUp(_) {
162 if (!_performance.isAnimating)
163 _settle();
164 }
165
166 void handlePointerCancel(_) {
167 if (!_performance.isAnimating)
168 _settle();
169 }
170
171 void handleFlingStart(event) {
172 double velocityX = event.velocityX / 1000;
173 if (velocityX.abs() >= _kMinFlingVelocity)
174 _performance.fling(velocity: velocityX / _kWidth);
175 }
157 } 176 }
OLDNEW
« no previous file with comments | « sky/sdk/example/stocks/lib/stock_home.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698