home.dart 7.66 KB
Newer Older
1 2 3 4
// 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.

5
import 'package:flutter/foundation.dart';
6 7 8
import 'package:flutter/material.dart';

import 'drawer.dart';
9
import 'item.dart';
10
import 'theme.dart';
11

12
const double _kFlexibleSpaceMaxHeight = 256.0;
13
const String _kGalleryAssetsPackage = 'flutter_gallery_assets';
14

15 16
class _BackgroundLayer {
  _BackgroundLayer({ int level, double parallax })
17 18
    : assetName = 'appbar/appbar_background_layer$level.png',
      assetPackage = _kGalleryAssetsPackage,
19 20
      parallaxTween = new Tween<double>(begin: 0.0, end: parallax);
  final String assetName;
21
  final String assetPackage;
22 23 24 25 26 27 28 29 30 31 32 33 34
  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 {
35
  const _AppBarBackground({ Key key, this.animation }) : super(key: key);
36 37 38 39 40 41

  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return new AnimatedBuilder(
42
      animation: animation,
43 44 45 46
      builder: (BuildContext context, Widget child) {
        return new Stack(
          children: _kBackgroundLayers.map((_BackgroundLayer layer) {
            return new Positioned(
47
              top: -layer.parallaxTween.evaluate(animation),
48 49 50 51 52
              left: 0.0,
              right: 0.0,
              bottom: 0.0,
              child: new Image.asset(
                layer.assetName,
53
                package: layer.assetPackage,
54
                fit: BoxFit.cover,
55 56 57 58 59 60 61 62 63 64
                height: _kFlexibleSpaceMaxHeight
              )
            );
          }).toList()
        );
      }
    );
  }
}

65
class GalleryHome extends StatefulWidget {
66
  const GalleryHome({
67
    Key key,
68
    this.galleryTheme,
69
    @required this.onThemeChanged,
70
    this.timeDilation,
71
    @required this.onTimeDilationChanged,
72 73
    this.textScaleFactor,
    this.onTextScaleFactorChanged,
Eric Seidel's avatar
Eric Seidel committed
74
    this.showPerformanceOverlay,
75
    this.onShowPerformanceOverlayChanged,
76 77
    this.checkerboardRasterCacheImages,
    this.onCheckerboardRasterCacheImagesChanged,
78 79
    this.checkerboardOffscreenLayers,
    this.onCheckerboardOffscreenLayersChanged,
80
    this.onPlatformChanged,
81 82
    this.overrideDirection: TextDirection.ltr,
    this.onOverrideDirectionChanged,
83
    this.onSendFeedback,
84 85 86
  }) : assert(onThemeChanged != null),
       assert(onTimeDilationChanged != null),
       super(key: key);
87

88 89
  final GalleryTheme galleryTheme;
  final ValueChanged<GalleryTheme> onThemeChanged;
90 91 92

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

94 95 96
  final double textScaleFactor;
  final ValueChanged<double> onTextScaleFactorChanged;

Eric Seidel's avatar
Eric Seidel committed
97 98 99
  final bool showPerformanceOverlay;
  final ValueChanged<bool> onShowPerformanceOverlayChanged;

100 101 102
  final bool checkerboardRasterCacheImages;
  final ValueChanged<bool> onCheckerboardRasterCacheImagesChanged;

103 104 105
  final bool checkerboardOffscreenLayers;
  final ValueChanged<bool> onCheckerboardOffscreenLayersChanged;

106 107
  final ValueChanged<TargetPlatform> onPlatformChanged;

108 109 110
  final TextDirection overrideDirection;
  final ValueChanged<TextDirection> onOverrideDirectionChanged;

111 112
  final VoidCallback onSendFeedback;

113
  @override
114 115 116
  GalleryHomeState createState() => new GalleryHomeState();
}

117
class GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin {
118
  static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
119

120
  AnimationController _controller;
121 122 123 124

  @override
  void initState() {
    super.initState();
125 126 127 128 129
    _controller = new AnimationController(
      duration: const Duration(milliseconds: 600),
      debugLabel: 'preview banner',
      vsync: this,
    )..forward();
130 131 132 133 134 135 136 137
  }

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

138 139
  List<Widget> _galleryListItems() {
    final List<Widget> listItems = <Widget>[];
140
    final ThemeData themeData = Theme.of(context);
141
    final TextStyle headerStyle = themeData.textTheme.body2.copyWith(color: themeData.accentColor);
142 143 144 145
    String category;
    for (GalleryItem galleryItem in kAllGalleryItems) {
      if (category != galleryItem.category) {
        if (category != null)
146
          listItems.add(const Divider());
147
        listItems.add(
148 149 150
          new MergeSemantics(
            child: new Container(
              height: 48.0,
151 152
              padding: const EdgeInsetsDirectional.only(start: 16.0),
              alignment: AlignmentDirectional.centerStart,
153 154 155
              child: new SafeArea(
                top: false,
                bottom: false,
156 157 158 159
                child: new Semantics(
                  header: true,
                  child: new Text(galleryItem.category, style: headerStyle),
                ),
160
              ),
161
            ),
162 163 164 165
          )
        );
        category = galleryItem.category;
      }
166
      listItems.add(galleryItem);
167
    }
168
    return listItems;
169
  }
170

171 172
  @override
  Widget build(BuildContext context) {
173
    Widget home = new Scaffold(
174
      key: _scaffoldKey,
175
      drawer: new GalleryDrawer(
176
        galleryTheme: widget.galleryTheme,
177 178 179
        onThemeChanged: widget.onThemeChanged,
        timeDilation: widget.timeDilation,
        onTimeDilationChanged: widget.onTimeDilationChanged,
180 181
        textScaleFactor: widget.textScaleFactor,
        onTextScaleFactorChanged: widget.onTextScaleFactorChanged,
182 183 184 185
        showPerformanceOverlay: widget.showPerformanceOverlay,
        onShowPerformanceOverlayChanged: widget.onShowPerformanceOverlayChanged,
        checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
        onCheckerboardRasterCacheImagesChanged: widget.onCheckerboardRasterCacheImagesChanged,
186 187
        checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
        onCheckerboardOffscreenLayersChanged: widget.onCheckerboardOffscreenLayersChanged,
188
        onPlatformChanged: widget.onPlatformChanged,
189 190
        overrideDirection: widget.overrideDirection,
        onOverrideDirectionChanged: widget.onOverrideDirectionChanged,
191
        onSendFeedback: widget.onSendFeedback,
192
      ),
193 194
      body: new CustomScrollView(
        slivers: <Widget>[
195
          const SliverAppBar(
196 197
            pinned: true,
            expandedHeight: _kFlexibleSpaceMaxHeight,
198
            flexibleSpace: const FlexibleSpaceBar(
199
              title: const Text('Flutter Gallery'),
200
              // TODO(abarth): Wire up to the parallax in a way that doesn't pop during hero transition.
201
              background: const _AppBarBackground(animation: kAlwaysDismissedAnimation),
202 203 204 205
            ),
          ),
          new SliverList(delegate: new SliverChildListDelegate(_galleryListItems())),
        ],
206
      )
207
    );
208

209
    // In checked mode our MaterialApp will show the default "debug" banner.
210 211 212 213 214
    // Otherwise show the "preview" banner.
    bool showPreviewBanner = true;
    assert(() {
      showPreviewBanner = false;
      return true;
215
    }());
216 217 218

    if (showPreviewBanner) {
      home = new Stack(
219
        fit: StackFit.expand,
220 221 222 223
        children: <Widget>[
          home,
          new FadeTransition(
            opacity: new CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
224
            child: const Banner(
225
              message: 'PREVIEW',
226
              location: BannerLocation.topEnd,
227 228 229 230 231 232 233
            )
          ),
        ]
      );
    }

    return home;
234 235
  }
}