home.dart 6.79 KB
Newer Older
1 2 3 4 5 6 7 8
// 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 'drawer.dart';
9
import 'item.dart';
10

11 12
const double _kFlexibleSpaceMaxHeight = 256.0;

13 14 15 16 17 18 19 20
List<GalleryItem> _itemsWithCategory(String category) {
  return kAllGalleryItems.where((GalleryItem item) => item.category == category).toList();
}

final List<GalleryItem> _demoItems = _itemsWithCategory('Demos');
final List<GalleryItem> _componentItems = _itemsWithCategory('Components');
final List<GalleryItem> _styleItems = _itemsWithCategory('Style');

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
class _BackgroundLayer {
  _BackgroundLayer({ int level, double parallax })
    : assetName = 'packages/flutter_gallery_assets/appbar/appbar_background_layer$level.png',
      parallaxTween = new Tween<double>(begin: 0.0, end: parallax);
  final String assetName;
  final Tween<double> parallaxTween;
}

final List<_BackgroundLayer> _kBackgroundLayers = <_BackgroundLayer>[
  new _BackgroundLayer(level: 0, parallax: _kFlexibleSpaceMaxHeight),
  new _BackgroundLayer(level: 1, parallax: _kFlexibleSpaceMaxHeight),
  new _BackgroundLayer(level: 2, parallax: _kFlexibleSpaceMaxHeight / 2.0),
  new _BackgroundLayer(level: 3, parallax: _kFlexibleSpaceMaxHeight / 4.0),
  new _BackgroundLayer(level: 4, parallax: _kFlexibleSpaceMaxHeight / 2.0),
  new _BackgroundLayer(level: 5, parallax: _kFlexibleSpaceMaxHeight)
];

class _AppBarBackground extends StatelessWidget {
  _AppBarBackground({ Key key, this.animation }) : super(key: key);

  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
45 46 47
    // TODO(abarth): Wire up to the parallax of the FlexibleSpaceBar in a way
    // that doesn't pop during hero transition.
    Animation<double> effectiveAnimation = kAlwaysDismissedAnimation;
48
    return new AnimatedBuilder(
49
      animation: effectiveAnimation,
50 51 52 53
      builder: (BuildContext context, Widget child) {
        return new Stack(
          children: _kBackgroundLayers.map((_BackgroundLayer layer) {
            return new Positioned(
54
              top: -layer.parallaxTween.evaluate(effectiveAnimation),
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
              left: 0.0,
              right: 0.0,
              bottom: 0.0,
              child: new Image.asset(
                layer.assetName,
                fit: ImageFit.cover,
                height: _kFlexibleSpaceMaxHeight
              )
            );
          }).toList()
        );
      }
    );
  }
}

71
class GalleryHome extends StatefulWidget {
72 73
  GalleryHome({
    Key key,
Eric Seidel's avatar
Eric Seidel committed
74
    this.useLightTheme,
75 76
    this.onThemeChanged,
    this.timeDilation,
Eric Seidel's avatar
Eric Seidel committed
77 78
    this.onTimeDilationChanged,
    this.showPerformanceOverlay,
79 80
    this.onShowPerformanceOverlayChanged,
    this.onPlatformChanged,
81 82 83 84 85
  }) : super(key: key) {
    assert(onThemeChanged != null);
    assert(onTimeDilationChanged != null);
  }

Eric Seidel's avatar
Eric Seidel committed
86
  final bool useLightTheme;
87 88 89 90
  final ValueChanged<bool> onThemeChanged;

  final double timeDilation;
  final ValueChanged<double> onTimeDilationChanged;
91

Eric Seidel's avatar
Eric Seidel committed
92 93 94
  final bool showPerformanceOverlay;
  final ValueChanged<bool> onShowPerformanceOverlayChanged;

95 96
  final ValueChanged<TargetPlatform> onPlatformChanged;

97
  @override
98 99 100
  GalleryHomeState createState() => new GalleryHomeState();
}

101 102
class GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin {
  static final Key _homeKey = new ValueKey<String>('Gallery Home');
103
  static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
104

105
  AnimationController _controller;
106 107 108 109

  @override
  void initState() {
    super.initState();
110 111 112 113 114
    _controller = new AnimationController(
      duration: const Duration(milliseconds: 600),
      debugLabel: 'preview banner',
      vsync: this,
    )..forward();
115 116 117 118 119 120 121 122
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

123 124
  List<Widget> _galleryListItems() {
    final List<Widget> listItems = <Widget>[];
125
    final ThemeData themeData = Theme.of(context);
126
    final TextStyle headerStyle = themeData.textTheme.body2.copyWith(color: themeData.accentColor);
127 128 129 130
    String category;
    for (GalleryItem galleryItem in kAllGalleryItems) {
      if (category != galleryItem.category) {
        if (category != null)
131 132
          listItems.add(new Divider());
        listItems.add(
133 134 135
          new Container(
            height: 48.0,
            padding: const EdgeInsets.only(left: 16.0),
136
            alignment: FractionalOffset.centerLeft,
137
            child: new Text(galleryItem.category, style: headerStyle)
138 139 140 141
          )
        );
        category = galleryItem.category;
      }
142
      listItems.add(galleryItem);
143
    }
144
    return listItems;
145
  }
146

147 148
  @override
  Widget build(BuildContext context) {
149
    final double statusBarHeight = MediaQuery.of(context).padding.top;
150
    Widget home = new Scaffold(
151
      key: _homeKey,
152
      scrollableKey: _scrollableKey,
153
      drawer: new GalleryDrawer(
Eric Seidel's avatar
Eric Seidel committed
154
        useLightTheme: config.useLightTheme,
155 156
        onThemeChanged: config.onThemeChanged,
        timeDilation: config.timeDilation,
Eric Seidel's avatar
Eric Seidel committed
157 158
        onTimeDilationChanged: config.onTimeDilationChanged,
        showPerformanceOverlay: config.showPerformanceOverlay,
159 160
        onShowPerformanceOverlayChanged: config.onShowPerformanceOverlayChanged,
        onPlatformChanged: config.onPlatformChanged,
161
      ),
162
      appBar: new AppBar(
163
        expandedHeight: _kFlexibleSpaceMaxHeight,
164
        flexibleSpace: new FlexibleSpaceBar(
165 166 167 168
          title: new Text('Flutter Gallery'),
          background: new Builder(
            builder: (BuildContext context) {
              return new _AppBarBackground(
169
                animation: Scaffold.of(context)?.appBarAnimation
170 171 172
              );
            }
          )
173
        )
174
      ),
175
      appBarBehavior: AppBarBehavior.under,
176 177 178
      // The block's padding just exists to occupy the space behind the flexible app bar.
      // As the block's padded region is scrolled upwards, the app bar's height will
      // shrink keep it above the block content's and over the padded region.
179 180
      body: new Block(
       scrollableKey: _scrollableKey,
181
       padding: new EdgeInsets.only(top: _kFlexibleSpaceMaxHeight + statusBarHeight),
182
       children: _galleryListItems()
183
      )
184
    );
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

    // In checked mode our MaterialApp will show the default "slow mode" banner.
    // Otherwise show the "preview" banner.
    bool showPreviewBanner = true;
    assert(() {
      showPreviewBanner = false;
      return true;
    });

    if (showPreviewBanner) {
      home = new Stack(
        children: <Widget>[
          home,
          new FadeTransition(
            opacity: new CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
            child: new Banner(
              message: 'PREVIEW',
              location: BannerLocation.topRight,
            )
          ),
        ]
      );
    }

    return home;
210 211
  }
}