Commit 9802ee18 authored by Viktor Lidholt's avatar Viktor Lidholt

Merge pull request #2906 from vlidholt/master

First pass at new Flutter gallery front page
parents 3a84cef2 d563f508
......@@ -23,3 +23,4 @@ assets:
- packages/flutter_gallery_assets/top_10_australian_beaches.png
- packages/flutter_gallery_assets/jumpingjack.json
- packages/flutter_gallery_assets/jumpingjack.png
- packages/flutter_gallery_assets/grain.png
......@@ -28,10 +28,20 @@ class GalleryAppState extends State<GalleryApp> {
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Material Gallery',
theme: lightTheme ? new ThemeData.light() : new ThemeData.dark(),
theme: lightTheme ? _kGalleryLightTheme : _kGalleryDarkTheme,
routes: {
'/': (BuildContext context) => new GalleryHome()
}
);
}
}
ThemeData _kGalleryLightTheme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
);
ThemeData _kGalleryDarkTheme = new ThemeData(
brightness: ThemeBrightness.dark,
primarySwatch: Colors.purple
);
// 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 'package:flutter/widgets.dart';
typedef Widget GalleryDemoBuilder();
class GalleryDemo {
GalleryDemo({ this.title, this.builder }) {
assert(title != null);
assert(builder != null);
}
final String title;
final GalleryDemoBuilder builder;
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
class GalleryHeader extends StatefulWidget {
@override
_GalleryHeaderState createState() => new _GalleryHeaderState();
}
class _GalleryHeaderState extends State<GalleryHeader> {
_FlutterHeaderNode _headerNode;
ImageMap _images;
Future<Null> _loadAssets() async {
final AssetBundle bundle = DefaultAssetBundle.of(context);
_images = new ImageMap(bundle);
await _images.load(<String>[
'packages/flutter_gallery_assets/grain.png',
]);
}
@override
void initState() {
super.initState();
_loadAssets().then((_) {
setState(() {
_headerNode = new _FlutterHeaderNode(_images);
});
});
}
@override
Widget build(BuildContext context) {
return _headerNode == null ? new Container() : new SpriteWidget(_headerNode);
}
}
const Size _kCanvasSize = const Size(1024.0, 1024.0);
const Point _kCenterPoint = const Point(512.0, 512.0);
class _FlutterHeaderNode extends NodeWithSize {
_FlutterHeaderNode(this._images) : super(_kCanvasSize) {
clippingLayer.opacity = 0.0;
clippingLayer.actions.run(new ActionTween((double a) => clippingLayer.opacity = a, 0.0, 1.0, 0.5));
addChild(clippingLayer);
clippingLayer.addChild(new _BackgroundBox());
paperAnimation.position = _kCenterPoint;
clippingLayer.addChild(paperAnimation);
final Sprite grain = new Sprite.fromImage(_images['packages/flutter_gallery_assets/grain.png'])
..position = _kCenterPoint;
clippingLayer.addChild(grain);
userInteractionEnabled = true;
}
final ImageMap _images;
final Layer clippingLayer = new Layer();
final _PaperAnimation paperAnimation = new _PaperAnimation();
@override
void spriteBoxPerformedLayout() {
clippingLayer.layerRect = spriteBox.visibleArea;
}
}
final List<_PaperConfig> _kPaperConfigs = <_PaperConfig>[
new _PaperConfig(
color: Colors.deepPurple[500],
startPosition: const Point(-300.0, -300.0),
startRotation: -10.0,
rotationSpeed: -1.0,
parallaxDepth: 0.0,
rect: new Rect.fromLTRB(-1024.0, -280.0, 1024.0, 280.0)
),
new _PaperConfig(
color: Colors.purple[400],
startPosition: const Point(550.0, 0.0),
startRotation: 45.0,
rotationSpeed: 0.7,
parallaxDepth: 1.0,
rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0)
),
new _PaperConfig(
color: Colors.purple[600],
startPosition: const Point(550.0, 0.0),
startRotation: 55.0,
rotationSpeed: 0.9,
parallaxDepth: 2.0,
rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0)
),
new _PaperConfig(
color: Colors.purple[700],
startPosition: const Point(550.0, 0.0),
startRotation: 65.0,
rotationSpeed: 1.1,
parallaxDepth: 3.0,
rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0)
)
];
class _PaperAnimation extends Node {
_PaperAnimation() {
for (_PaperConfig config in _kPaperConfigs) {
final _PaperSheet sheet = new _PaperSheet(config);
final _PaperSheetShadow shadow = new _PaperSheetShadow(config);
addChild(shadow);
addChild(sheet);
_sheets.add(sheet);
shadow.constraints = <Constraint>[
new ConstraintRotationToNodeRotation(sheet),
new ConstraintPositionToNode(sheet, offset: const Offset(0.0, 10.0))
];
}
}
final List<_PaperSheet> _sheets = <_PaperSheet>[];
}
class _PaperConfig {
_PaperConfig({
this.color,
this.startPosition,
this.startRotation,
this.rotationSpeed,
this.parallaxDepth,
this.rect
});
final Color color;
final Point startPosition;
final double startRotation;
final double rotationSpeed;
final double parallaxDepth;
final Rect rect;
}
class _PaperSheet extends Node {
_PaperSheet(this._config) {
_paperPaint.color = _config.color;
position = _config.startPosition;
rotation = _config.startRotation;
}
final _PaperConfig _config;
final Paint _paperPaint = new Paint();
@override
void paint(Canvas canvas) {
canvas.drawRect(_config.rect, _paperPaint);
}
@override
void update(double dt) {
rotation += _config.rotationSpeed * dt;
}
}
class _PaperSheetShadow extends Node {
_PaperSheetShadow(this._config) {
_paperPaint.color = Colors.black45;
_paperPaint.maskFilter = new MaskFilter.blur(BlurStyle.normal, 10.0);
}
final _PaperConfig _config;
final Paint _paperPaint = new Paint();
@override
void paint(Canvas canvas) {
canvas.drawRect(_config.rect, _paperPaint);
}
}
class _BackgroundBox extends Node {
final Paint _boxPaint = new Paint()..color = Colors.purple[500];
@override
void paint(Canvas canvas) {
canvas.drawRect(new Rect.fromLTWH(0.0, 0.0, _kCanvasSize.width, _kCanvasSize.height), _boxPaint);
}
}
import 'package:flutter/material.dart';
typedef Widget GalleryDemoBuilder();
class GalleryItem extends StatelessWidget {
GalleryItem({ this.title, this.icon, this.builder });
final String title;
final IconData icon;
final GalleryDemoBuilder builder;
@override
Widget build(BuildContext context) {
Widget leading = icon == null ? new Container() : new Icon(icon: icon);
return new TwoLevelListItem(
leading: leading,
title: new Text(title),
onTap: () {
if (builder != null) {
Navigator.push(context, new MaterialPageRoute<Null>(
builder: (BuildContext context) => builder()
));
}
}
);
}
}
// 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 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'demo.dart';
class GallerySection extends StatelessWidget {
GallerySection({ this.title, this.image, this.colors, this.demos });
final String title;
final String image;
final Map<int, Color> colors;
final List<GalleryDemo> demos;
void showDemo(GalleryDemo demo, BuildContext context, ThemeData theme) {
Navigator.push(context, new MaterialPageRoute<Null>(
builder: (BuildContext context) {
Widget child = (demo.builder == null) ? null : demo.builder();
return new Theme(data: theme, child: child);
}
));
}
void showDemos(BuildContext context) {
final double statusBarHeight = MediaQuery.of(context).padding.top;
final ThemeData theme = new ThemeData(
brightness: Theme.of(context).brightness,
primarySwatch: colors
);
final double appBarHeight = 200.0;
final Key scrollableKey = new ValueKey<String>(title); // assume section titles differ
Navigator.push(context, new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new Theme(
data: theme,
child: new Scaffold(
appBarBehavior: AppBarBehavior.under,
scrollableKey: scrollableKey,
appBar: new AppBar(
expandedHeight: appBarHeight,
flexibleSpace: (BuildContext context) => new FlexibleSpaceBar(title: new Text(title))
),
body: new Material(
child: new MaterialList(
scrollableKey: scrollableKey,
scrollablePadding: new EdgeInsets.only(top: appBarHeight + statusBarHeight),
type: MaterialListType.oneLine,
children: (demos ?? const <GalleryDemo>[]).map((GalleryDemo demo) {
return new ListItem(
title: new Text(demo.title),
onTap: () { showDemo(demo, context, theme); }
);
})
)
)
)
);
}
));
}
@override
Widget build (BuildContext context) {
final ThemeData theme = new ThemeData(
brightness: Theme.of(context).brightness,
primarySwatch: colors
);
final TextStyle titleTextStyle = theme.textTheme.title.copyWith(
color: Colors.white
);
return new Flexible(
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () { showDemos(context); },
child: new Container(
height: 256.0,
margin: const EdgeInsets.all(4.0),
decoration: new BoxDecoration(backgroundColor: theme.primaryColor),
child: new Column(
children: <Widget>[
new Flexible(
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new AssetImage(
name: image,
alignment: const FractionalOffset(0.5, 0.5),
fit: ImageFit.contain
)
)
),
new Padding(
padding: const EdgeInsets.all(16.0),
child: new Align(
alignment: const FractionalOffset(0.0, 1.0),
child: new Text(title, style: titleTextStyle)
)
)
]
)
)
)
);
}
}
......@@ -7,4 +7,4 @@ dependencies:
path: ../../packages/flutter
flutter_sprites:
path: ../../packages/flutter_sprites
flutter_gallery_assets: '0.0.9'
flutter_gallery_assets: '0.0.12'
......@@ -154,14 +154,25 @@ class _TwoLevelSublistState extends State<TwoLevelSublist> {
}
class TwoLevelList extends StatelessWidget {
TwoLevelList({ Key key, this.scrollableKey, this.items, this.type: MaterialListType.twoLine }) : super(key: key);
TwoLevelList({
Key key,
this.scrollableKey,
this.items,
this.type: MaterialListType.twoLine,
this.scrollablePadding
}) : super(key: key);
final List<Widget> items;
final MaterialListType type;
final Key scrollableKey;
final EdgeInsets scrollablePadding;
@override
Widget build(BuildContext context) {
return new Block(children: KeyedSubtree.ensureUniqueKeysForList(items), scrollableKey: scrollableKey);
return new Block(
padding: scrollablePadding,
children: KeyedSubtree.ensureUniqueKeysForList(items),
scrollableKey: scrollableKey
);
}
}
......@@ -66,6 +66,29 @@ class ConstraintRotationToMovement extends Constraint {
}
}
/// A [Constraint] that copies a node's rotation, optionally with [dampening].
class ConstraintRotationToNodeRotation extends Constraint {
/// Creates a new constraint that copies a node's rotation, optionally
/// with a [baseRotation] added and using [dampening].
ConstraintRotationToNodeRotation(this.targetNode, { this.baseRotation: 0.0, this.dampening });
/// The node to copy the rotation from
final Node targetNode;
/// The base rotation will be added to the rotation that copied from the targetNode
final double baseRotation;
/// The filter factor used when constraining the rotation of the node. Valid
/// values are in the range 0.0 to 1.0
final double dampening;
@override
void constrain(Node node, double dt) {
double target = targetNode.rotation + baseRotation;
node.rotation = _dampenRotation(node.rotation, target, dampening);
}
}
/// A [Constraint] that rotates a node to point towards another node. The target
/// node is allowed to have a different parent, but they must be in the same
/// [SpriteBox].
......
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