Commit ec92aca8 authored by Adam Barth's avatar Adam Barth

Port more widgets to fn3

parent 8c6073a5
// Copyright 2015 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 'package:sky/animation.dart';
import 'package:sky/src/fn3/framework.dart';
abstract class AnimatedComponent extends StatefulComponent {
const AnimatedComponent({ Key key, this.direction, this.duration }) : super(key: key);
final Duration duration;
final Direction direction;
}
abstract class AnimatedComponentState<T extends AnimatedComponent> extends ComponentState<T> {
AnimatedComponentState(T config) : super(config) {
_performance = new AnimationPerformance(duration: config.duration);
performance.addStatusListener(_handleAnimationStatusChanged);
if (buildDependsOnPerformance) {
performance.addListener(() {
setState(() {
// We don't actually have any state to change, per se,
// we just know that we have in fact changed state.
});
});
}
performance.play(config.direction);
}
void didUpdateConfig(T oldConfig) {
performance.duration = config.duration;
if (config.duration != oldConfig.duration || config.direction != oldConfig.direction)
performance.play(config.direction);
}
AnimationPerformance get performance => _performance;
AnimationPerformance _performance;
void _handleAnimationStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.completed)
handleCompleted();
else if (status == AnimationStatus.dismissed)
handleDismissed();
}
bool get buildDependsOnPerformance => false;
void handleCompleted() { }
void handleDismissed() { }
}
......@@ -114,14 +114,8 @@ class CustomPaint extends OneChildRenderObjectWidget {
}
class ClipRect extends OneChildRenderObjectWidget {
ClipRect({ Key key, Widget child })
: super(key: key, child: child);
ClipRect({ Key key, Widget child }) : super(key: key, child: child);
RenderClipRect createRenderObject() => new RenderClipRect();
void updateRenderObject(RenderClipRect renderObject, ClipRect oldWidget) {
// Nothing to update
}
}
class ClipRRect extends OneChildRenderObjectWidget {
......@@ -140,14 +134,8 @@ class ClipRRect extends OneChildRenderObjectWidget {
}
class ClipOval extends OneChildRenderObjectWidget {
ClipOval({ Key key, Widget child })
: super(key: key, child: child);
ClipOval({ Key key, Widget child }) : super(key: key, child: child);
RenderClipOval createRenderObject() => new RenderClipOval();
void updateRenderObject(RenderClipOval renderObject, ClipOval oldWidget) {
// Nothing to update
}
}
......@@ -285,14 +273,8 @@ class IntrinsicWidth extends OneChildRenderObjectWidget {
}
class IntrinsicHeight extends OneChildRenderObjectWidget {
IntrinsicHeight({ Key key, Widget child })
: super(key: key, child: child);
IntrinsicHeight({ Key key, Widget child }) : super(key: key, child: child);
RenderIntrinsicHeight createRenderObject() => new RenderIntrinsicHeight();
void updateRenderObject(RenderIntrinsicHeight renderObject, IntrinsicHeight oldWidget) {
// Nothing to update
}
}
class Baseline extends OneChildRenderObjectWidget {
......@@ -459,14 +441,8 @@ class BlockBody extends MultiChildRenderObjectWidget {
}
class Stack extends MultiChildRenderObjectWidget {
Stack(List<Widget> children, { Key key })
: super(key: key, children: children);
Stack(List<Widget> children, { Key key }) : super(key: key, children: children);
RenderStack createRenderObject() => new RenderStack();
void updateRenderObject(RenderStack renderObject, Stack oldWidget) {
// Nothing to update
}
}
class Positioned extends ParentDataWidget {
......@@ -855,7 +831,7 @@ class AssetImage extends StatelessComponent {
class Listener extends OneChildRenderObjectWidget {
Listener({
Key key,
Widget child,
Widget child,
this.onPointerDown,
this.onPointerMove,
this.onPointerUp,
......
......@@ -33,9 +33,9 @@ abstract class ButtonState<T extends StatefulComponent> extends ComponentState<T
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp,
onPointerCancel: _handlePointerCancel,
child: buildContent()
child: buildContent(context)
);
}
Widget buildContent();
Widget buildContent(BuildContext context);
}
// Copyright 2015 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 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/material.dart';
const EdgeDims _kCardMargins = const EdgeDims.all(4.0);
/// A material design card
///
/// <https://www.google.com/design/spec/components/cards.html>
class Card extends StatelessComponent {
const Card({ Key key, this.child, this.color }) : super(key: key);
final Widget child;
final Color color;
Widget build(BuildContext context) {
return new Container(
margin: _kCardMargins,
child: new Material(
color: color,
type: MaterialType.card,
level: 2,
child: child
)
);
}
}
// Copyright 2015 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:sky' as sky;
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/theme.dart';
import 'package:sky/src/rendering/object.dart';
import 'package:sky/src/rendering/toggleable.dart';
export 'package:sky/src/rendering/toggleable.dart' show ValueChanged;
const double _kMidpoint = 0.5;
const sky.Color _kLightUncheckedColor = const sky.Color(0x8A000000);
const sky.Color _kDarkUncheckedColor = const sky.Color(0xB2FFFFFF);
const double _kEdgeSize = 20.0;
const double _kEdgeRadius = 1.0;
const Duration _kCheckDuration = const Duration(milliseconds: 200);
/// A material design checkbox
///
/// The checkbox itself does not maintain any state. Instead, when the state of
/// the checkbox changes, the component calls the `onChange` callback. Most
/// components that use a checkbox will listen for the `onChange` callback and
/// rebuild the checkbox with a new `value` to update the visual appearance of
/// the checkbox.
///
/// <https://www.google.com/design/spec/components/lists-controls.html#lists-controls-types-of-list-controls>
class Checkbox extends StatelessComponent {
/// Constructs a checkbox
///
/// * `value` determines whether the checkbox is checked.
/// * `onChanged` is called whenever the state of the checkbox should change.
const Checkbox({Key key, this.value, this.onChanged}) : super(key: key);
final bool value;
final ValueChanged onChanged;
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
Color uncheckedColor = themeData.brightness == ThemeBrightness.light
? _kLightUncheckedColor
: _kDarkUncheckedColor;
return new _CheckboxWrapper(
value: value,
onChanged: onChanged,
uncheckedColor: uncheckedColor,
accentColor: themeData.accentColor);
}
}
// This wrapper class exists only because Switch needs to be a Component in
// order to get an accent color from a Theme but Components do not know how to
// host RenderObjects.
class _CheckboxWrapper extends LeafRenderObjectWidget {
_CheckboxWrapper({Key key, this.value, this.onChanged, this.uncheckedColor,
this.accentColor})
: super(key: key);
final bool value;
final ValueChanged onChanged;
final Color uncheckedColor;
final Color accentColor;
_RenderCheckbox createRenderObject() => new _RenderCheckbox(
value: value, uncheckedColor: uncheckedColor, onChanged: onChanged);
void updateRenderObject(_RenderCheckbox renderObject, _CheckboxWrapper oldWidget) {
renderObject.value = value;
renderObject.onChanged = onChanged;
renderObject.uncheckedColor = uncheckedColor;
renderObject.accentColor = accentColor;
}
}
class _RenderCheckbox extends RenderToggleable {
_RenderCheckbox({bool value, Color uncheckedColor, ValueChanged onChanged})
: _uncheckedColor = uncheckedColor,
super(
value: value,
onChanged: onChanged,
size: new Size(_kEdgeSize, _kEdgeSize)) {}
Color _uncheckedColor;
Color get uncheckedColor => _uncheckedColor;
void set uncheckedColor(Color value) {
if (value == _uncheckedColor) return;
_uncheckedColor = value;
markNeedsPaint();
}
Color _accentColor;
void set accentColor(Color value) {
if (value == _accentColor) return;
_accentColor = value;
markNeedsPaint();
}
void paint(PaintingContext context, Offset offset) {
final PaintingCanvas canvas = context.canvas;
// Choose a color between grey and the theme color
sky.Paint paint = new sky.Paint()
..strokeWidth = 2.0
..color = uncheckedColor;
// The rrect contracts slightly during the animation
double inset = 2.0 - (position.value - _kMidpoint).abs() * 2.0;
sky.Rect rect = new sky.Rect.fromLTWH(offset.dx + inset, offset.dy + inset,
_kEdgeSize - inset, _kEdgeSize - inset);
sky.RRect rrect = new sky.RRect()
..setRectXY(rect, _kEdgeRadius, _kEdgeRadius);
// Outline of the empty rrect
paint.setStyle(sky.PaintingStyle.stroke);
canvas.drawRRect(rrect, paint);
// Radial gradient that changes size
if (position.value > 0) {
paint.setStyle(sky.PaintingStyle.fill);
paint.setShader(new sky.Gradient.radial(
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
_kEdgeSize * (_kMidpoint - position.value) * 8.0, [
const sky.Color(0x00000000),
uncheckedColor
]));
canvas.drawRRect(rrect, paint);
}
if (position.value > _kMidpoint) {
double t = (position.value - _kMidpoint) / (1.0 - _kMidpoint);
// Solid filled rrect
paint.setStyle(sky.PaintingStyle.strokeAndFill);
paint.color = new Color.fromARGB((t * 255).floor(), _accentColor.red,
_accentColor.green, _accentColor.blue);
canvas.drawRRect(rrect, paint);
// White inner check
paint.color = const sky.Color(0xFFFFFFFF);
paint.setStyle(sky.PaintingStyle.stroke);
sky.Path path = new sky.Path();
sky.Point start = new sky.Point(_kEdgeSize * 0.2, _kEdgeSize * 0.5);
sky.Point mid = new sky.Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
sky.Point end = new sky.Point(_kEdgeSize * 0.8, _kEdgeSize * 0.3);
Point lerp(Point p1, Point p2, double t) =>
new Point(p1.x * (1.0 - t) + p2.x * t, p1.y * (1.0 - t) + p2.y * t);
sky.Point drawStart = lerp(start, mid, 1.0 - t);
sky.Point drawEnd = lerp(mid, end, t);
path.moveTo(offset.dx + drawStart.x, offset.dy + drawStart.y);
path.lineTo(offset.dx + mid.x, offset.dy + mid.y);
path.lineTo(offset.dx + drawEnd.x, offset.dy + drawEnd.y);
canvas.drawPath(path, paint);
}
}
}
// Copyright 2015 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 'package:sky/material.dart';
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/material_button.dart';
import 'package:sky/src/fn3/theme.dart';
class FlatButton extends MaterialButton {
FlatButton({
Key key,
Widget child,
bool enabled: true,
Function onPressed
}) : super(key: key,
child: child,
enabled: enabled,
onPressed: onPressed);
FlatButtonState createState() => new FlatButtonState(this);
}
class FlatButtonState extends MaterialButtonState<FlatButton> {
FlatButtonState(FlatButton config) : super(config);
Color getColor(BuildContext context) {
if (!config.enabled || !highlight)
return null;
switch (Theme.of(context).brightness) {
case ThemeBrightness.light:
return Colors.grey[400];
case ThemeBrightness.dark:
return Colors.grey[200];
}
}
int get level => 0;
}
......@@ -229,7 +229,7 @@ abstract class RenderObjectWidget extends Widget {
/// Copies the configuration described by this RenderObjectWidget to the given
/// RenderObject, which must be of the same type as returned by this class'
/// createRenderObject().
void updateRenderObject(RenderObject renderObject, RenderObjectWidget oldWidget);
void updateRenderObject(RenderObject renderObject, RenderObjectWidget oldWidget) { }
void didUnmountRenderObject(RenderObject renderObject) { }
}
......@@ -604,7 +604,6 @@ typedef void BuildScheduler(BuildableElement element);
class ErrorWidget extends LeafRenderObjectWidget {
RenderBox createRenderObject() => new RenderErrorBox();
void updateRenderObject(RenderObject renderObject, RenderObjectWidget oldWidget) { }
}
/// Base class for the instantiation of StatelessComponent and StatefulComponent
......
// Copyright 2015 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:sky' as sky;
import 'package:sky/gestures.dart';
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/rendering/sky_binding.dart';
class GestureDetector extends StatefulComponent {
const GestureDetector({
Key key,
this.child,
this.onTap,
this.onShowPress,
this.onLongPress,
this.onVerticalDragStart,
this.onVerticalDragUpdate,
this.onVerticalDragEnd,
this.onHorizontalDragStart,
this.onHorizontalDragUpdate,
this.onHorizontalDragEnd,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd
}) : super(key: key);
final Widget child;
final GestureTapListener onTap;
final GestureShowPressListener onShowPress;
final GestureLongPressListener onLongPress;
final GestureDragStartCallback onVerticalDragStart;
final GestureDragUpdateCallback onVerticalDragUpdate;
final GestureDragEndCallback onVerticalDragEnd;
final GestureDragStartCallback onHorizontalDragStart;
final GestureDragUpdateCallback onHorizontalDragUpdate;
final GestureDragEndCallback onHorizontalDragEnd;
final GesturePanStartCallback onPanStart;
final GesturePanUpdateCallback onPanUpdate;
final GesturePanEndCallback onPanEnd;
final GestureScaleStartCallback onScaleStart;
final GestureScaleUpdateCallback onScaleUpdate;
final GestureScaleEndCallback onScaleEnd;
GestureDetectorState createState() => new GestureDetectorState(this);
}
class GestureDetectorState extends ComponentState<GestureDetector> {
GestureDetectorState(GestureDetector config) : super(config);
final PointerRouter _router = SkyBinding.instance.pointerRouter;
TapGestureRecognizer _tap;
TapGestureRecognizer _ensureTap() {
if (_tap == null)
_tap = new TapGestureRecognizer(router: _router);
return _tap;
}
ShowPressGestureRecognizer _showPress;
ShowPressGestureRecognizer _ensureShowPress() {
if (_showPress == null)
_showPress = new ShowPressGestureRecognizer(router: _router);
return _showPress;
}
LongPressGestureRecognizer _longPress;
LongPressGestureRecognizer _ensureLongPress() {
if (_longPress == null)
_longPress = new LongPressGestureRecognizer(router: _router);
return _longPress;
}
VerticalDragGestureRecognizer _verticalDrag;
VerticalDragGestureRecognizer _ensureVerticalDrag() {
if (_verticalDrag == null)
_verticalDrag = new VerticalDragGestureRecognizer(router: _router);
return _verticalDrag;
}
HorizontalDragGestureRecognizer _horizontalDrag;
HorizontalDragGestureRecognizer _ensureHorizontalDrag() {
if (_horizontalDrag == null)
_horizontalDrag = new HorizontalDragGestureRecognizer(router: _router);
return _horizontalDrag;
}
PanGestureRecognizer _pan;
PanGestureRecognizer _ensurePan() {
assert(_scale == null); // Scale is a superset of pan; just use scale
if (_pan == null)
_pan = new PanGestureRecognizer(router: _router);
return _pan;
}
ScaleGestureRecognizer _scale;
ScaleGestureRecognizer _ensureScale() {
assert(_pan == null); // Scale is a superset of pan; just use scale
if (_scale == null)
_scale = new ScaleGestureRecognizer(router: _router);
return _scale;
}
void dispose() {
_tap = _ensureDisposed(_tap);
_showPress = _ensureDisposed(_showPress);
_longPress = _ensureDisposed(_longPress);
_verticalDrag = _ensureDisposed(_verticalDrag);
_horizontalDrag = _ensureDisposed(_horizontalDrag);
_pan = _ensureDisposed(_pan);
_scale = _ensureDisposed(_scale);
}
void didUpdateConfig(GestureDetector oldConfig) {
_syncTap();
_syncShowPress();
_syncLongPress();
_syncVerticalDrag();
_syncHorizontalDrag();
_syncPan();
_syncScale();
}
void _syncTap() {
if (config.onTap == null)
_tap = _ensureDisposed(_tap);
else
_ensureTap().onTap = config.onTap;
}
void _syncShowPress() {
if (config.onShowPress == null)
_showPress = _ensureDisposed(_showPress);
else
_ensureShowPress().onShowPress = config.onShowPress;
}
void _syncLongPress() {
if (config.onLongPress == null)
_longPress = _ensureDisposed(_longPress);
else
_ensureLongPress().onLongPress = config.onLongPress;
}
void _syncVerticalDrag() {
if (config.onVerticalDragStart == null && config.onVerticalDragUpdate == null && config.onVerticalDragEnd == null) {
_verticalDrag = _ensureDisposed(_verticalDrag);
} else {
_ensureVerticalDrag()
..onStart = config.onVerticalDragStart
..onUpdate = config.onVerticalDragUpdate
..onEnd = config.onVerticalDragEnd;
}
}
void _syncHorizontalDrag() {
if (config.onHorizontalDragStart == null && config.onHorizontalDragUpdate == null && config.onHorizontalDragEnd == null) {
_horizontalDrag = _ensureDisposed(_horizontalDrag);
} else {
_ensureHorizontalDrag()
..onStart = config.onHorizontalDragStart
..onUpdate = config.onHorizontalDragUpdate
..onEnd = config.onHorizontalDragEnd;
}
}
void _syncPan() {
if (config.onPanStart == null && config.onPanUpdate == null && config.onPanEnd == null) {
_pan = _ensureDisposed(_pan);
} else {
_ensurePan()
..onStart = config.onPanStart
..onUpdate = config.onPanUpdate
..onEnd = config.onPanEnd;
}
}
void _syncScale() {
if (config.onScaleStart == null && config.onScaleUpdate == null && config.onScaleEnd == null) {
_scale = _ensureDisposed(_pan);
} else {
_ensureScale()
..onStart = config.onScaleStart
..onUpdate = config.onScaleUpdate
..onEnd = config.onScaleEnd;
}
}
GestureRecognizer _ensureDisposed(GestureRecognizer recognizer) {
recognizer?.dispose();
return null;
}
void _handlePointerDown(sky.PointerEvent event) {
if (_tap != null)
_tap.addPointer(event);
if (_showPress != null)
_showPress.addPointer(event);
if (_longPress != null)
_longPress.addPointer(event);
if (_verticalDrag != null)
_verticalDrag.addPointer(event);
if (_horizontalDrag != null)
_horizontalDrag.addPointer(event);
if (_pan != null)
_pan.addPointer(event);
if (_scale != null)
_scale.addPointer(event);
}
Widget build(BuildContext context) {
return new Listener(
onPointerDown: _handlePointerDown,
child: config.child
);
}
}
// Copyright 2015 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:math' as math;
import 'dart:sky' as sky;
import 'package:sky/animation.dart';
import 'package:sky/rendering.dart';
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
const int _kSplashInitialOpacity = 0x30;
const double _kSplashCancelledVelocity = 0.7;
const double _kSplashConfirmedVelocity = 0.7;
const double _kSplashInitialSize = 0.0;
const double _kSplashUnconfirmedVelocity = 0.2;
double _getSplashTargetSize(Size bounds, Point position) {
double d1 = (position - bounds.topLeft(Point.origin)).distance;
double d2 = (position - bounds.topRight(Point.origin)).distance;
double d3 = (position - bounds.bottomLeft(Point.origin)).distance;
double d4 = (position - bounds.bottomRight(Point.origin)).distance;
return math.max(math.max(d1, d2), math.max(d3, d4)).ceil().toDouble();
}
class InkSplash {
InkSplash(this.pointer, this.position, this.well) {
_targetRadius = _getSplashTargetSize(well.size, position);
_radius = new AnimatedValue<double>(
_kSplashInitialSize, end: _targetRadius, curve: easeOut);
_performance = new AnimationPerformance()
..variable = _radius
..duration = new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
..addListener(_handleRadiusChange)
..play();
}
final int pointer;
final Point position;
final RenderInkWell well;
double _targetRadius;
double _pinnedRadius;
AnimatedValue<double> _radius;
AnimationPerformance _performance;
void _updateVelocity(double velocity) {
int duration = (_targetRadius / velocity).floor();
_performance
..duration = new Duration(milliseconds: duration)
..play();
}
void confirm() {
_updateVelocity(_kSplashConfirmedVelocity);
}
void cancel() {
_updateVelocity(_kSplashCancelledVelocity);
_pinnedRadius = _radius.value;
}
void _handleRadiusChange() {
if (_radius.value == _targetRadius)
well._splashes.remove(this);
well.markNeedsPaint();
}
void paint(PaintingCanvas canvas) {
int opacity = (_kSplashInitialOpacity * (1.1 - (_radius.value / _targetRadius))).floor();
sky.Paint paint = new sky.Paint()..color = new sky.Color(opacity << 24);
double radius = _pinnedRadius == null ? _radius.value : _pinnedRadius;
canvas.drawCircle(position, radius, paint);
}
}
class RenderInkWell extends RenderProxyBox {
RenderInkWell({ RenderBox child }) : super(child);
final List<InkSplash> _splashes = new List<InkSplash>();
void handleEvent(sky.Event event, BoxHitTestEntry entry) {
// TODO(abarth): We should trigger these effects based on gestures.
// https://github.com/flutter/engine/issues/1271
if (event is sky.PointerEvent) {
switch (event.type) {
case 'pointerdown':
_startSplash(event.pointer, entry.localPosition);
break;
case 'pointerup':
_confirmSplash(event.pointer);
break;
}
}
}
void _startSplash(int pointer, Point position) {
_splashes.add(new InkSplash(pointer, position, this));
markNeedsPaint();
}
void _forEachSplash(int pointer, Function callback) {
_splashes.where((splash) => splash.pointer == pointer)
.forEach(callback);
}
void _confirmSplash(int pointer) {
_forEachSplash(pointer, (splash) { splash.confirm(); });
markNeedsPaint();
}
void paint(PaintingContext context, Offset offset) {
if (!_splashes.isEmpty) {
final PaintingCanvas canvas = context.canvas;
canvas.save();
canvas.translate(offset.dx, offset.dy);
canvas.clipRect(Point.origin & size);
for (InkSplash splash in _splashes)
splash.paint(canvas);
canvas.restore();
}
super.paint(context, offset);
}
}
class InkWell extends OneChildRenderObjectWidget {
InkWell({ Key key, Widget child }) : super(key: key, child: child);
RenderInkWell createRenderObject() => new RenderInkWell();
}
// Copyright 2015 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 'package:sky/painting.dart';
import 'package:sky/material.dart';
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/theme.dart';
enum MaterialType { canvas, card, circle, button }
const Map<MaterialType, double> edges = const {
MaterialType.canvas: null,
MaterialType.card: 2.0,
MaterialType.circle: null,
MaterialType.button: 2.0,
};
class Material extends StatelessComponent {
Material({
Key key,
this.child,
this.type: MaterialType.card,
this.level: 0,
this.color
}) : super(key: key) {
assert(level != null);
}
final Widget child;
final MaterialType type;
final int level;
final Color color;
Color getBackgroundColor(BuildContext context) {
if (color != null)
return color;
switch (type) {
case MaterialType.canvas:
return Theme.of(context).canvasColor;
case MaterialType.card:
return Theme.of(context).cardColor;
default:
return null;
}
}
Widget build(BuildContext context) {
Widget contents = child;
if (child != null) {
contents = new DefaultTextStyle(
style: Theme.of(context).text.body1,
child: contents
);
if (edges[type] != null) {
contents = new ClipRRect(
xRadius: edges[type],
yRadius: edges[type],
child: contents
);
}
}
// TODO(abarth): This should use AnimatedContainer.
return new Container(
decoration: new BoxDecoration(
backgroundColor: getBackgroundColor(context),
borderRadius: edges[type],
boxShadow: level == 0 ? null : shadows[level],
shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle
),
child: contents
);
}
}
// Copyright 2015 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 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/button_state.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/gesture_detector.dart';
import 'package:sky/src/fn3/ink_well.dart';
import 'package:sky/src/fn3/material.dart';
// Rather than using this class directly, please use FlatButton or RaisedButton.
abstract class MaterialButton extends StatefulComponent {
const MaterialButton({
Key key,
this.child,
this.enabled: true,
this.onPressed
}) : super(key: key);
final Widget child;
final bool enabled;
final Function onPressed;
}
abstract class MaterialButtonState<T extends MaterialButton> extends ButtonState<T> {
MaterialButtonState(T config) : super(config);
Color getColor(BuildContext context);
int get level;
Widget buildContent(BuildContext context) {
Widget contents = new Container(
padding: new EdgeDims.symmetric(horizontal: 8.0),
child: new Center(
shrinkWrap: ShrinkWrap.width,
child: config.child // TODO(ianh): figure out a way to compell the child to have gray text when disabled...
)
);
return new GestureDetector(
onTap: config.enabled ? config.onPressed : null,
child: new Container(
height: 36.0,
constraints: new BoxConstraints(minWidth: 88.0),
margin: new EdgeDims.all(8.0),
child: new Material(
type: MaterialType.button,
child: config.enabled ? new InkWell(child: contents) : contents,
level: level,
color: getColor(context)
)
)
);
}
}
// Copyright 2015 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 'package:sky/material.dart';
import 'package:sky/src/fn3/basic.dart';
import 'package:sky/src/fn3/framework.dart';
import 'package:sky/src/fn3/material_button.dart';
import 'package:sky/src/fn3/theme.dart';
class RaisedButton extends MaterialButton {
RaisedButton({
Key key,
Widget child,
bool enabled: true,
Function onPressed
}) : super(key: key,
child: child,
enabled: enabled,
onPressed: onPressed);
RaisedButtonState createState() => new RaisedButtonState(this);
}
class RaisedButtonState extends MaterialButtonState<RaisedButton> {
RaisedButtonState(RaisedButton config) : super(config);
Color getColor(BuildContext context) {
if (config.enabled) {
switch (Theme.of(context).brightness) {
case ThemeBrightness.light:
if (highlight)
return Colors.grey[350];
else
return Colors.grey[300];
break;
case ThemeBrightness.dark:
if (highlight)
return Theme.of(context).primarySwatch[700];
else
return Theme.of(context).primarySwatch[600];
break;
}
} else {
return Colors.grey[350];
}
}
int get level => config.enabled ? (highlight ? 2 : 1) : 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment