home.dart 7.24 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

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

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

  final Animation<double> animation;

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

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

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

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

91 92 93
  final double textScaleFactor;
  final ValueChanged<double> onTextScaleFactorChanged;

Eric Seidel's avatar
Eric Seidel committed
94 95 96
  final bool showPerformanceOverlay;
  final ValueChanged<bool> onShowPerformanceOverlayChanged;

97 98 99
  final bool checkerboardRasterCacheImages;
  final ValueChanged<bool> onCheckerboardRasterCacheImagesChanged;

100 101 102
  final bool checkerboardOffscreenLayers;
  final ValueChanged<bool> onCheckerboardOffscreenLayersChanged;

103 104
  final ValueChanged<TargetPlatform> onPlatformChanged;

105 106
  final VoidCallback onSendFeedback;

107
  @override
108 109 110
  GalleryHomeState createState() => new GalleryHomeState();
}

111
class GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin {
112
  static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
113

114
  AnimationController _controller;
115 116 117 118

  @override
  void initState() {
    super.initState();
119 120 121 122 123
    _controller = new AnimationController(
      duration: const Duration(milliseconds: 600),
      debugLabel: 'preview banner',
      vsync: this,
    )..forward();
124 125 126 127 128 129 130 131
  }

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

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

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

    // 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;
204
    }());
205 206 207

    if (showPreviewBanner) {
      home = new Stack(
208
        fit: StackFit.expand,
209 210 211 212
        children: <Widget>[
          home,
          new FadeTransition(
            opacity: new CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
213
            child: const Banner(
214
              message: 'PREVIEW',
215
              location: BannerLocation.topEnd,
216 217 218 219 220 221 222
            )
          ),
        ]
      );
    }

    return home;
223 224
  }
}