diff --git a/web/gallery/README.md b/web/gallery/README.md deleted file mode 100644 index 3f9b48af5..000000000 --- a/web/gallery/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Flutter gallery - -A demo app for Flutter's material design and cupertino widgets, as -well as many other features of the Flutter SDK. - -## Building - -You can follow these instructions to build the gallery app -and install it onto your device. - -### Prerequisites - -If you are new to Flutter, please first follow -the [Flutter Setup](https://flutter.dev/setup/) guide. - -### Building and installing the Flutter app - -* `cd $FLUTTER_ROOT/examples/flutter_gallery` -* `flutter pub get` -* `flutter run --release` - -The `flutter run --release` command both builds and installs the Flutter app. - -## Prerelease checklist - -* Verify that the About box's license page scrolls and reveals its long -long stream of license texts. - -## Icon - -Android launcher icons were generated using Android Asset Studio: -https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html#foreground.type=image&foreground.space.trim=1&foreground.space.pad=0.1&foreColor=607d8b%2C0&crop=0&backgroundShape=square&backColor=fafafa%2C100&effects=none diff --git a/web/gallery/analysis_options.yaml b/web/gallery/analysis_options.yaml deleted file mode 100644 index 44fbe83c0..000000000 --- a/web/gallery/analysis_options.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Take our settings from the repo's main analysis_options.yaml file, but add -# an exclude for the build directory. - -include: ../../analysis_options.yaml - -analyzer: - exclude: - - build/** diff --git a/web/gallery/assets/preview.png b/web/gallery/assets/preview.png deleted file mode 100644 index a70b50cf9..000000000 Binary files a/web/gallery/assets/preview.png and /dev/null differ diff --git a/web/gallery/lib/demo/all.dart b/web/gallery/lib/demo/all.dart deleted file mode 100644 index 0dfe26be8..000000000 --- a/web/gallery/lib/demo/all.dart +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -export 'animation_demo.dart'; -export 'calculator_demo.dart'; -export 'colors_demo.dart'; -export 'contacts_demo.dart'; -export 'cupertino/cupertino.dart'; -export 'fortnightly/fortnightly.dart'; -export 'images_demo.dart'; -export 'material/material.dart'; -export 'pesto_demo.dart'; -export 'shrine_demo.dart'; -export 'transformations/transformations_demo.dart'; -export 'typography_demo.dart'; -export 'video_demo.dart'; diff --git a/web/gallery/lib/demo/animation/home.dart b/web/gallery/lib/demo/animation/home.dart deleted file mode 100644 index 857cf23ea..000000000 --- a/web/gallery/lib/demo/animation/home.dart +++ /dev/null @@ -1,628 +0,0 @@ -// Copyright 2017 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. - -// Based on https://material.uplabs.com/posts/google-newsstand-navigation-pattern -// See also: https://material-motion.github.io/material-motion/documentation/ - -import 'dart:math' as math; - -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -import 'sections.dart'; -import 'widgets.dart'; - -const Color _kAppBackgroundColor = Color(0xFF353662); -const Duration _kScrollDuration = Duration(milliseconds: 400); -const Curve _kScrollCurve = Curves.fastOutSlowIn; - -// This app's contents start out at _kHeadingMaxHeight and they function like -// an appbar. Initially the appbar occupies most of the screen and its section -// headings are laid out in a column. By the time its height has been -// reduced to _kAppBarMidHeight, its layout is horizontal, only one section -// heading is visible, and the section's list of details is visible below the -// heading. The appbar's height can be reduced to no more than _kAppBarMinHeight. -const double _kAppBarMinHeight = 90.0; -const double _kAppBarMidHeight = 256.0; -// The AppBar's max height depends on the screen, see _AnimationDemoHomeState._buildBody() - -// Initially occupies the same space as the status bar and gets smaller as -// the primary scrollable scrolls upwards. -// TODO(hansmuller): it would be worth adding something like this to the framework. -class _RenderStatusBarPaddingSliver extends RenderSliver { - _RenderStatusBarPaddingSliver({ - @required double maxHeight, - @required double scrollFactor, - }) : assert(maxHeight != null && maxHeight >= 0.0), - assert(scrollFactor != null && scrollFactor >= 1.0), - _maxHeight = maxHeight, - _scrollFactor = scrollFactor; - - // The height of the status bar - double get maxHeight => _maxHeight; - double _maxHeight; - set maxHeight(double value) { - assert(maxHeight != null && maxHeight >= 0.0); - if (_maxHeight == value) - return; - _maxHeight = value; - markNeedsLayout(); - } - - // That rate at which this renderer's height shrinks when the scroll - // offset changes. - double get scrollFactor => _scrollFactor; - double _scrollFactor; - set scrollFactor(double value) { - assert(scrollFactor != null && scrollFactor >= 1.0); - if (_scrollFactor == value) - return; - _scrollFactor = value; - markNeedsLayout(); - } - - @override - void performLayout() { - final double height = (maxHeight - constraints.scrollOffset / scrollFactor).clamp(0.0, maxHeight); - geometry = SliverGeometry( - paintExtent: math.min(height, constraints.remainingPaintExtent), - scrollExtent: maxHeight, - maxPaintExtent: maxHeight, - ); - } -} - -class _StatusBarPaddingSliver extends SingleChildRenderObjectWidget { - const _StatusBarPaddingSliver({ - Key key, - @required this.maxHeight, - this.scrollFactor = 5.0, - }) : assert(maxHeight != null && maxHeight >= 0.0), - assert(scrollFactor != null && scrollFactor >= 1.0), - super(key: key); - - final double maxHeight; - final double scrollFactor; - - @override - _RenderStatusBarPaddingSliver createRenderObject(BuildContext context) { - return _RenderStatusBarPaddingSliver( - maxHeight: maxHeight, - scrollFactor: scrollFactor, - ); - } - - @override - void updateRenderObject(BuildContext context, _RenderStatusBarPaddingSliver renderObject) { - renderObject - ..maxHeight = maxHeight - ..scrollFactor = scrollFactor; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder description) { - super.debugFillProperties(description); - description.add(DoubleProperty('maxHeight', maxHeight)); - description.add(DoubleProperty('scrollFactor', scrollFactor)); - } -} - -class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { - _SliverAppBarDelegate({ - @required this.minHeight, - @required this.maxHeight, - @required this.child, - }); - - final double minHeight; - final double maxHeight; - final Widget child; - - @override - double get minExtent => minHeight; - @override - double get maxExtent => math.max(maxHeight, minHeight); - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return SizedBox.expand(child: child); - } - - @override - bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { - return maxHeight != oldDelegate.maxHeight - || minHeight != oldDelegate.minHeight - || child != oldDelegate.child; - } - - @override - String toString() => '_SliverAppBarDelegate'; -} - -// Arrange the section titles, indicators, and cards. The cards are only included when -// the layout is transitioning between vertical and horizontal. Once the layout is -// horizontal the cards are laid out by a PageView. -// -// The layout of the section cards, titles, and indicators is defined by the -// two 0.0-1.0 "t" parameters, both of which are based on the layout's height: -// - tColumnToRow -// 0.0 when height is maxHeight and the layout is a column -// 1.0 when the height is midHeight and the layout is a row -// - tCollapsed -// 0.0 when height is midHeight and the layout is a row -// 1.0 when height is minHeight and the layout is a (still) row -// -// minHeight < midHeight < maxHeight -// -// The general approach here is to compute the column layout and row size -// and position of each element and then interpolate between them using -// tColumnToRow. Once tColumnToRow reaches 1.0, the layout changes are -// defined by tCollapsed. As tCollapsed increases the titles spread out -// until only one title is visible and the indicators cluster together -// until they're all visible. -class _AllSectionsLayout extends MultiChildLayoutDelegate { - _AllSectionsLayout({ - this.translation, - this.tColumnToRow, - this.tCollapsed, - this.cardCount, - this.selectedIndex, - }); - - final Alignment translation; - final double tColumnToRow; - final double tCollapsed; - final int cardCount; - final double selectedIndex; - - Rect _interpolateRect(Rect begin, Rect end) { - return Rect.lerp(begin, end, tColumnToRow); - } - - Offset _interpolatePoint(Offset begin, Offset end) { - return Offset.lerp(begin, end, tColumnToRow); - } - - @override - void performLayout(Size size) { - final double columnCardX = size.width / 5.0; - final double columnCardWidth = size.width - columnCardX; - final double columnCardHeight = size.height / cardCount; - final double rowCardWidth = size.width; - final Offset offset = translation.alongSize(size); - double columnCardY = 0.0; - double rowCardX = -(selectedIndex * rowCardWidth); - - // When tCollapsed > 0 the titles spread apart - final double columnTitleX = size.width / 10.0; - final double rowTitleWidth = size.width * ((1 + tCollapsed) / 2.25); - double rowTitleX = (size.width - rowTitleWidth) / 2.0 - selectedIndex * rowTitleWidth; - - // When tCollapsed > 0, the indicators move closer together - //final double rowIndicatorWidth = 48.0 + (1.0 - tCollapsed) * (rowTitleWidth - 48.0); - const double paddedSectionIndicatorWidth = kSectionIndicatorWidth + 8.0; - final double rowIndicatorWidth = paddedSectionIndicatorWidth + - (1.0 - tCollapsed) * (rowTitleWidth - paddedSectionIndicatorWidth); - double rowIndicatorX = (size.width - rowIndicatorWidth) / 2.0 - selectedIndex * rowIndicatorWidth; - - // Compute the size and origin of each card, title, and indicator for the maxHeight - // "column" layout, and the midHeight "row" layout. The actual layout is just the - // interpolated value between the column and row layouts for t. - for (int index = 0; index < cardCount; index++) { - - // Layout the card for index. - final Rect columnCardRect = Rect.fromLTWH(columnCardX, columnCardY, columnCardWidth, columnCardHeight); - final Rect rowCardRect = Rect.fromLTWH(rowCardX, 0.0, rowCardWidth, size.height); - final Rect cardRect = _interpolateRect(columnCardRect, rowCardRect).shift(offset); - final String cardId = 'card$index'; - if (hasChild(cardId)) { - layoutChild(cardId, BoxConstraints.tight(cardRect.size)); - positionChild(cardId, cardRect.topLeft); - } - - // Layout the title for index. - final Size titleSize = layoutChild('title$index', BoxConstraints.loose(cardRect.size)); - final double columnTitleY = columnCardRect.centerLeft.dy - titleSize.height / 2.0; - final double rowTitleY = rowCardRect.centerLeft.dy - titleSize.height / 2.0; - final double centeredRowTitleX = rowTitleX + (rowTitleWidth - titleSize.width) / 2.0; - final Offset columnTitleOrigin = Offset(columnTitleX, columnTitleY); - final Offset rowTitleOrigin = Offset(centeredRowTitleX, rowTitleY); - final Offset titleOrigin = _interpolatePoint(columnTitleOrigin, rowTitleOrigin); - positionChild('title$index', titleOrigin + offset); - - // Layout the selection indicator for index. - final Size indicatorSize = layoutChild('indicator$index', BoxConstraints.loose(cardRect.size)); - final double columnIndicatorX = cardRect.centerRight.dx - indicatorSize.width - 16.0; - final double columnIndicatorY = cardRect.bottomRight.dy - indicatorSize.height - 16.0; - final Offset columnIndicatorOrigin = Offset(columnIndicatorX, columnIndicatorY); - final Rect titleRect = Rect.fromPoints(titleOrigin, titleSize.bottomRight(titleOrigin)); - final double centeredRowIndicatorX = rowIndicatorX + (rowIndicatorWidth - indicatorSize.width) / 2.0; - final double rowIndicatorY = titleRect.bottomCenter.dy + 16.0; - final Offset rowIndicatorOrigin = Offset(centeredRowIndicatorX, rowIndicatorY); - final Offset indicatorOrigin = _interpolatePoint(columnIndicatorOrigin, rowIndicatorOrigin); - positionChild('indicator$index', indicatorOrigin + offset); - - columnCardY += columnCardHeight; - rowCardX += rowCardWidth; - rowTitleX += rowTitleWidth; - rowIndicatorX += rowIndicatorWidth; - } - } - - @override - bool shouldRelayout(_AllSectionsLayout oldDelegate) { - return tColumnToRow != oldDelegate.tColumnToRow - || cardCount != oldDelegate.cardCount - || selectedIndex != oldDelegate.selectedIndex; - } -} - -class _AllSectionsView extends AnimatedWidget { - _AllSectionsView({ - Key key, - this.sectionIndex, - @required this.sections, - @required this.selectedIndex, - this.minHeight, - this.midHeight, - this.maxHeight, - this.sectionCards = const [], - }) : assert(sections != null), - assert(sectionCards != null), - assert(sectionCards.length == sections.length), - assert(sectionIndex >= 0 && sectionIndex < sections.length), - assert(selectedIndex != null), - assert(selectedIndex.value >= 0.0 && selectedIndex.value < sections.length.toDouble()), - super(key: key, listenable: selectedIndex); - - final int sectionIndex; - final List
sections; - final ValueNotifier selectedIndex; - final double minHeight; - final double midHeight; - final double maxHeight; - final List sectionCards; - - double _selectedIndexDelta(int index) { - return (index.toDouble() - selectedIndex.value).abs().clamp(0.0, 1.0); - } - - Widget _build(BuildContext context, BoxConstraints constraints) { - final Size size = constraints.biggest; - - // The layout's progress from from a column to a row. Its value is - // 0.0 when size.height equals the maxHeight, 1.0 when the size.height - // equals the midHeight. - final double tColumnToRow = - 1.0 - ((size.height - midHeight) / - (maxHeight - midHeight)).clamp(0.0, 1.0); - - - // The layout's progress from from the midHeight row layout to - // a minHeight row layout. Its value is 0.0 when size.height equals - // midHeight and 1.0 when size.height equals minHeight. - final double tCollapsed = - 1.0 - ((size.height - minHeight) / - (midHeight - minHeight)).clamp(0.0, 1.0); - - double _indicatorOpacity(int index) { - return 1.0 - _selectedIndexDelta(index) * 0.5; - } - - double _titleOpacity(int index) { - return 1.0 - _selectedIndexDelta(index) * tColumnToRow * 0.5; - } - - double _titleScale(int index) { - return 1.0 - _selectedIndexDelta(index) * tColumnToRow * 0.15; - } - - final List children = List.from(sectionCards); - - for (int index = 0; index < sections.length; index++) { - final Section section = sections[index]; - children.add(LayoutId( - id: 'title$index', - child: SectionTitle( - section: section, - scale: _titleScale(index), - opacity: _titleOpacity(index), - ), - )); - } - - for (int index = 0; index < sections.length; index++) { - children.add(LayoutId( - id: 'indicator$index', - child: SectionIndicator( - opacity: _indicatorOpacity(index), - ), - )); - } - - return CustomMultiChildLayout( - delegate: _AllSectionsLayout( - translation: Alignment((selectedIndex.value - sectionIndex) * 2.0 - 1.0, -1.0), - tColumnToRow: tColumnToRow, - tCollapsed: tCollapsed, - cardCount: sections.length, - selectedIndex: selectedIndex.value, - ), - children: children, - ); - } - - @override - Widget build(BuildContext context) { - return LayoutBuilder(builder: _build); - } -} - -// Support snapping scrolls to the midScrollOffset: the point at which the -// app bar's height is _kAppBarMidHeight and only one section heading is -// visible. -class _SnappingScrollPhysics extends ClampingScrollPhysics { - const _SnappingScrollPhysics({ - ScrollPhysics parent, - @required this.midScrollOffset, - }) : assert(midScrollOffset != null), - super(parent: parent); - - final double midScrollOffset; - - @override - _SnappingScrollPhysics applyTo(ScrollPhysics ancestor) { - return _SnappingScrollPhysics(parent: buildParent(ancestor), midScrollOffset: midScrollOffset); - } - - Simulation _toMidScrollOffsetSimulation(double offset, double dragVelocity) { - final double velocity = math.max(dragVelocity, minFlingVelocity); - return ScrollSpringSimulation(spring, offset, midScrollOffset, velocity, tolerance: tolerance); - } - - Simulation _toZeroScrollOffsetSimulation(double offset, double dragVelocity) { - final double velocity = math.max(dragVelocity, minFlingVelocity); - return ScrollSpringSimulation(spring, offset, 0.0, velocity, tolerance: tolerance); - } - - @override - Simulation createBallisticSimulation(ScrollMetrics position, double dragVelocity) { - final Simulation simulation = super.createBallisticSimulation(position, dragVelocity); - final double offset = position.pixels; - - if (simulation != null) { - // The drag ended with sufficient velocity to trigger creating a simulation. - // If the simulation is headed up towards midScrollOffset but will not reach it, - // then snap it there. Similarly if the simulation is headed down past - // midScrollOffset but will not reach zero, then snap it to zero. - final double simulationEnd = simulation.x(double.infinity); - if (simulationEnd >= midScrollOffset) - return simulation; - if (dragVelocity > 0.0) - return _toMidScrollOffsetSimulation(offset, dragVelocity); - if (dragVelocity < 0.0) - return _toZeroScrollOffsetSimulation(offset, dragVelocity); - } else { - // The user ended the drag with little or no velocity. If they - // didn't leave the offset above midScrollOffset, then - // snap to midScrollOffset if they're more than halfway there, - // otherwise snap to zero. - final double snapThreshold = midScrollOffset / 2.0; - if (offset >= snapThreshold && offset < midScrollOffset) - return _toMidScrollOffsetSimulation(offset, dragVelocity); - if (offset > 0.0 && offset < snapThreshold) - return _toZeroScrollOffsetSimulation(offset, dragVelocity); - } - return simulation; - } -} - -class AnimationDemoHome extends StatefulWidget { - const AnimationDemoHome({ Key key }) : super(key: key); - - static const String routeName = '/animation'; - - @override - _AnimationDemoHomeState createState() => _AnimationDemoHomeState(); -} - -class _AnimationDemoHomeState extends State { - final ScrollController _scrollController = ScrollController(); - final PageController _headingPageController = PageController(); - final PageController _detailsPageController = PageController(); - ScrollPhysics _headingScrollPhysics = const NeverScrollableScrollPhysics(); - ValueNotifier selectedIndex = ValueNotifier(0.0); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: _kAppBackgroundColor, - body: Builder( - // Insert an element so that _buildBody can find the PrimaryScrollController. - builder: _buildBody, - ), - ); - } - - void _handleBackButton(double midScrollOffset) { - if (_scrollController.offset >= midScrollOffset) - _scrollController.animateTo(0.0, curve: _kScrollCurve, duration: _kScrollDuration); - else - Navigator.maybePop(context); - } - - // Only enable paging for the heading when the user has scrolled to midScrollOffset. - // Paging is enabled/disabled by setting the heading's PageView scroll physics. - bool _handleScrollNotification(ScrollNotification notification, double midScrollOffset) { - if (notification.depth == 0 && notification is ScrollUpdateNotification) { - final ScrollPhysics physics = _scrollController.position.pixels >= midScrollOffset - ? const PageScrollPhysics() - : const NeverScrollableScrollPhysics(); - if (physics != _headingScrollPhysics) { - setState(() { - _headingScrollPhysics = physics; - }); - } - } - return false; - } - - void _maybeScroll(double midScrollOffset, int pageIndex, double xOffset) { - if (_scrollController.offset < midScrollOffset) { - // Scroll the overall list to the point where only one section card shows. - // At the same time scroll the PageViews to the page at pageIndex. - _headingPageController.animateToPage(pageIndex, curve: _kScrollCurve, duration: _kScrollDuration); - _scrollController.animateTo(midScrollOffset, curve: _kScrollCurve, duration: _kScrollDuration); - } else { - // One one section card is showing: scroll one page forward or back. - final double centerX = _headingPageController.position.viewportDimension / 2.0; - final int newPageIndex = xOffset > centerX ? pageIndex + 1 : pageIndex - 1; - _headingPageController.animateToPage(newPageIndex, curve: _kScrollCurve, duration: _kScrollDuration); - } - } - - bool _handlePageNotification(ScrollNotification notification, PageController leader, PageController follower) { - if (notification.depth == 0 && notification is ScrollUpdateNotification) { - selectedIndex.value = leader.page; - if (follower.page != leader.page) - follower.position.jumpToWithoutSettling(leader.position.pixels); // ignore: deprecated_member_use - } - return false; - } - - Iterable _detailItemsFor(Section section) { - final Iterable detailItems = section.details.map((SectionDetail detail) { - return SectionDetailView(detail: detail); - }); - return ListTile.divideTiles(context: context, tiles: detailItems); - } - - Iterable _allHeadingItems(double maxHeight, double midScrollOffset) { - final List sectionCards = []; - for (int index = 0; index < allSections.length; index++) { - sectionCards.add(LayoutId( - id: 'card$index', - child: GestureDetector( - behavior: HitTestBehavior.opaque, - child: SectionCard(section: allSections[index]), - onTapUp: (TapUpDetails details) { - final double xOffset = details.globalPosition.dx; - setState(() { - _maybeScroll(midScrollOffset, index, xOffset); - }); - }, - ), - )); - } - - final List headings = []; - for (int index = 0; index < allSections.length; index++) { - headings.add(Container( - color: _kAppBackgroundColor, - child: ClipRect( - child: _AllSectionsView( - sectionIndex: index, - sections: allSections, - selectedIndex: selectedIndex, - minHeight: _kAppBarMinHeight, - midHeight: _kAppBarMidHeight, - maxHeight: maxHeight, - sectionCards: sectionCards, - ), - ), - ) - ); - } - return headings; - } - - Widget _buildBody(BuildContext context) { - final MediaQueryData mediaQueryData = MediaQuery.of(context); - final double statusBarHeight = mediaQueryData.padding.top; - final double screenHeight = mediaQueryData.size.height; - final double appBarMaxHeight = screenHeight - statusBarHeight; - - // The scroll offset that reveals the appBarMidHeight appbar. - final double appBarMidScrollOffset = statusBarHeight + appBarMaxHeight - _kAppBarMidHeight; - - return SizedBox.expand( - child: Stack( - children: [ - NotificationListener( - onNotification: (ScrollNotification notification) { - return _handleScrollNotification(notification, appBarMidScrollOffset); - }, - child: CustomScrollView( - controller: _scrollController, - physics: _SnappingScrollPhysics(midScrollOffset: appBarMidScrollOffset), - slivers: [ - // Start out below the status bar, gradually move to the top of the screen. - _StatusBarPaddingSliver( - maxHeight: statusBarHeight, - scrollFactor: 7.0, - ), - // Section Headings - SliverPersistentHeader( - pinned: true, - delegate: _SliverAppBarDelegate( - minHeight: _kAppBarMinHeight, - maxHeight: appBarMaxHeight, - child: NotificationListener( - onNotification: (ScrollNotification notification) { - return _handlePageNotification(notification, _headingPageController, _detailsPageController); - }, - child: PageView( - physics: _headingScrollPhysics, - controller: _headingPageController, - children: _allHeadingItems(appBarMaxHeight, appBarMidScrollOffset), - ), - ), - ), - ), - // Details - SliverToBoxAdapter( - child: SizedBox( - height: 610.0, - child: NotificationListener( - onNotification: (ScrollNotification notification) { - return _handlePageNotification(notification, _detailsPageController, _headingPageController); - }, - child: PageView( - controller: _detailsPageController, - children: allSections.map((Section section) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: _detailItemsFor(section).toList(), - ); - }).toList(), - ), - ), - ), - ), - ], - ), - ), - Positioned( - top: statusBarHeight, - left: 0.0, - child: IconTheme( - data: const IconThemeData(color: Colors.white), - child: SafeArea( - top: false, - bottom: false, - child: IconButton( - icon: const BackButtonIcon(), - tooltip: 'Back', - onPressed: () { - _handleBackButton(appBarMidScrollOffset); - }, - ), - ), - ), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/animation/sections.dart b/web/gallery/lib/demo/animation/sections.dart deleted file mode 100644 index 07e7d0919..000000000 --- a/web/gallery/lib/demo/animation/sections.dart +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2017 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. - -// Raw data for the animation demo. - -import 'package:flutter/material.dart'; - -const Color _mariner = Color(0xFF3B5F8F); -const Color _mediumPurple = Color(0xFF8266D4); -const Color _tomato = Color(0xFFF95B57); -const Color _mySin = Color(0xFFF3A646); - -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -class SectionDetail { - const SectionDetail({ - this.title, - this.subtitle, - this.imageAsset, - this.imageAssetPackage, - }); - final String title; - final String subtitle; - final String imageAsset; - final String imageAssetPackage; -} - -class Section { - const Section({ - this.title, - this.backgroundAsset, - this.backgroundAssetPackage, - this.leftColor, - this.rightColor, - this.details, - }); - final String title; - final String backgroundAsset; - final String backgroundAssetPackage; - final Color leftColor; - final Color rightColor; - final List details; - - @override - bool operator==(Object other) { - if (other is! Section) - return false; - final Section otherSection = other; - return title == otherSection.title; - } - - @override - int get hashCode => title.hashCode; -} - -// TODO(hansmuller): replace the SectionDetail images and text. Get rid of -// the const vars like _eyeglassesDetail and insert a variety of titles and -// image SectionDetails in the allSections list. - -const SectionDetail _eyeglassesDetail = SectionDetail( - imageAsset: 'products/sunnies.png', - imageAssetPackage: _kGalleryAssetsPackage, - title: 'Flutter enables interactive animation', - subtitle: '3K views - 5 days', -); - -const SectionDetail _eyeglassesImageDetail = SectionDetail( - imageAsset: 'products/sunnies.png', - imageAssetPackage: _kGalleryAssetsPackage, -); - -const SectionDetail _seatingDetail = SectionDetail( - imageAsset: 'products/table.png', - imageAssetPackage: _kGalleryAssetsPackage, - title: 'Flutter enables interactive animation', - subtitle: '3K views - 5 days', -); - -const SectionDetail _seatingImageDetail = SectionDetail( - imageAsset: 'products/table.png', - imageAssetPackage: _kGalleryAssetsPackage, -); - -const SectionDetail _decorationDetail = SectionDetail( - imageAsset: 'products/earrings.png', - imageAssetPackage: _kGalleryAssetsPackage, - title: 'Flutter enables interactive animation', - subtitle: '3K views - 5 days', -); - -const SectionDetail _decorationImageDetail = SectionDetail( - imageAsset: 'products/earrings.png', - imageAssetPackage: _kGalleryAssetsPackage, -); - -const SectionDetail _protectionDetail = SectionDetail( - imageAsset: 'products/hat.png', - imageAssetPackage: _kGalleryAssetsPackage, - title: 'Flutter enables interactive animation', - subtitle: '3K views - 5 days', -); - -const SectionDetail _protectionImageDetail = SectionDetail( - imageAsset: 'products/hat.png', - imageAssetPackage: _kGalleryAssetsPackage, -); - -final List
allSections =
[ - const Section( - title: 'SUNGLASSES', - leftColor: _mediumPurple, - rightColor: _mariner, - backgroundAsset: 'products/sunnies.png', - backgroundAssetPackage: _kGalleryAssetsPackage, - details: [ - _eyeglassesDetail, - _eyeglassesImageDetail, - _eyeglassesDetail, - _eyeglassesDetail, - _eyeglassesDetail, - _eyeglassesDetail, - ], - ), - const Section( - title: 'FURNITURE', - leftColor: _tomato, - rightColor: _mediumPurple, - backgroundAsset: 'products/table.png', - backgroundAssetPackage: _kGalleryAssetsPackage, - details: [ - _seatingDetail, - _seatingImageDetail, - _seatingDetail, - _seatingDetail, - _seatingDetail, - _seatingDetail, - ], - ), - const Section( - title: 'JEWELRY', - leftColor: _mySin, - rightColor: _tomato, - backgroundAsset: 'products/earrings.png', - backgroundAssetPackage: _kGalleryAssetsPackage, - details: [ - _decorationDetail, - _decorationImageDetail, - _decorationDetail, - _decorationDetail, - _decorationDetail, - _decorationDetail, - ], - ), - const Section( - title: 'HEADWEAR', - leftColor: Colors.white, - rightColor: _tomato, - backgroundAsset: 'products/hat.png', - backgroundAssetPackage: _kGalleryAssetsPackage, - details: [ - _protectionDetail, - _protectionImageDetail, - _protectionDetail, - _protectionDetail, - _protectionDetail, - _protectionDetail, - ], - ), -]; diff --git a/web/gallery/lib/demo/animation/widgets.dart b/web/gallery/lib/demo/animation/widgets.dart deleted file mode 100644 index 60583d3e6..000000000 --- a/web/gallery/lib/demo/animation/widgets.dart +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2017 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 'sections.dart'; - -const double kSectionIndicatorWidth = 32.0; - -// The card for a single section. Displays the section's gradient and background image. -class SectionCard extends StatelessWidget { - const SectionCard({ Key key, @required this.section }) - : assert(section != null), - super(key: key); - - final Section section; - - @override - Widget build(BuildContext context) { - return Semantics( - label: section.title, - button: true, - child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - section.leftColor, - section.rightColor, - ], - ), - ), - child: Image.asset( - section.backgroundAsset, - package: section.backgroundAssetPackage, - color: const Color.fromRGBO(255, 255, 255, 0.075), - colorBlendMode: BlendMode.modulate, - fit: BoxFit.cover, - ), - ), - ); - } -} - -// The title is rendered with two overlapping text widgets that are vertically -// offset a little. It's supposed to look sort-of 3D. -class SectionTitle extends StatelessWidget { - const SectionTitle({ - Key key, - @required this.section, - @required this.scale, - @required this.opacity, - }) : assert(section != null), - assert(scale != null), - assert(opacity != null && opacity >= 0.0 && opacity <= 1.0), - super(key: key); - - final Section section; - final double scale; - final double opacity; - - static const TextStyle sectionTitleStyle = TextStyle( - fontFamily: 'Raleway', - inherit: false, - fontSize: 24.0, - fontWeight: FontWeight.w500, - color: Colors.white, - textBaseline: TextBaseline.alphabetic, - ); - - static final TextStyle sectionTitleShadowStyle = sectionTitleStyle.copyWith( - color: const Color(0x19000000), - ); - - @override - Widget build(BuildContext context) { - return IgnorePointer( - child: Opacity( - opacity: opacity, - child: Transform( - transform: Matrix4.identity()..scale(scale), - alignment: Alignment.center, - child: Stack( - children: [ - Positioned( - top: 4.0, - child: Text(section.title, style: sectionTitleShadowStyle), - ), - Text(section.title, style: sectionTitleStyle), - ], - ), - ), - ), - ); - } -} - -// Small horizontal bar that indicates the selected section. -class SectionIndicator extends StatelessWidget { - const SectionIndicator({ Key key, this.opacity = 1.0 }) : super(key: key); - - final double opacity; - - @override - Widget build(BuildContext context) { - return IgnorePointer( - child: Container( - width: kSectionIndicatorWidth, - height: 3.0, - color: Colors.white.withOpacity(opacity), - ), - ); - } -} - -// Display a single SectionDetail. -class SectionDetailView extends StatelessWidget { - SectionDetailView({ Key key, @required this.detail }) - : assert(detail != null && detail.imageAsset != null), - assert((detail.imageAsset ?? detail.title) != null), - super(key: key); - - final SectionDetail detail; - - @override - Widget build(BuildContext context) { - final Widget image = DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - image: DecorationImage( - image: AssetImage( - detail.imageAsset, - package: detail.imageAssetPackage, - ), - fit: BoxFit.cover, - alignment: Alignment.center, - ), - ), - ); - - Widget item; - if (detail.title == null && detail.subtitle == null) { - item = Container( - height: 240.0, - padding: const EdgeInsets.all(16.0), - child: SafeArea( - top: false, - bottom: false, - child: image, - ), - ); - } else { - item = ListTile( - title: Text(detail.title), - subtitle: Text(detail.subtitle), - leading: SizedBox(width: 32.0, height: 32.0, child: image), - ); - } - - return DecoratedBox( - decoration: BoxDecoration(color: Colors.grey.shade200), - child: item, - ); - } -} diff --git a/web/gallery/lib/demo/animation_demo.dart b/web/gallery/lib/demo/animation_demo.dart deleted file mode 100644 index 62e5ef0d6..000000000 --- a/web/gallery/lib/demo/animation_demo.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 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 'animation/home.dart'; - -class AnimationDemo extends StatelessWidget { - const AnimationDemo({Key key}) : super(key: key); - - static const String routeName = '/animation'; - - @override - Widget build(BuildContext context) => const AnimationDemoHome(); -} diff --git a/web/gallery/lib/demo/calculator/home.dart b/web/gallery/lib/demo/calculator/home.dart deleted file mode 100644 index 84250f616..000000000 --- a/web/gallery/lib/demo/calculator/home.dart +++ /dev/null @@ -1,270 +0,0 @@ -// 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 'logic.dart'; - -class Calculator extends StatefulWidget { - const Calculator({Key key}) : super(key: key); - - @override - _CalculatorState createState() => _CalculatorState(); -} - -class _CalculatorState extends State { - /// As the user taps keys we update the current `_expression` and we also - /// keep a stack of previous expressions so we can return to earlier states - /// when the user hits the DEL key. - final List _expressionStack = []; - CalcExpression _expression = CalcExpression.empty(); - - // Make `expression` the current expression and push the previous current - // expression onto the stack. - void pushExpression(CalcExpression expression) { - _expressionStack.add(_expression); - _expression = expression; - } - - /// Pop the top expression off of the stack and make it the current expression. - void popCalcExpression() { - if (_expressionStack.isNotEmpty) { - _expression = _expressionStack.removeLast(); - } else { - _expression = CalcExpression.empty(); - } - } - - /// Set `resultExpression` to the current expression and clear the stack. - void setResult(CalcExpression resultExpression) { - _expressionStack.clear(); - _expression = resultExpression; - } - - void handleNumberTap(int n) { - final CalcExpression expression = _expression.appendDigit(n); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handlePointTap() { - final CalcExpression expression = _expression.appendPoint(); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handlePlusTap() { - final CalcExpression expression = _expression.appendOperation(Operation.Addition); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handleMinusTap() { - final CalcExpression expression = _expression.appendMinus(); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handleMultTap() { - final CalcExpression expression = _expression.appendOperation(Operation.Multiplication); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handleDivTap() { - final CalcExpression expression = _expression.appendOperation(Operation.Division); - if (expression != null) { - setState(() { - pushExpression(expression); - }); - } - } - - void handleEqualsTap() { - final CalcExpression resultExpression = _expression.computeResult(); - if (resultExpression != null) { - setState(() { - setResult(resultExpression); - }); - } - } - - void handleDelTap() { - setState(() { - popCalcExpression(); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).canvasColor, - elevation: 0.0, - ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // Give the key-pad 3/5 of the vertical space and the display 2/5. - Expanded( - flex: 2, - child: CalcDisplay(content: _expression.toString()), - ), - const Divider(height: 1.0), - Expanded( - flex: 3, - child: KeyPad(calcState: this), - ), - ], - ), - ); - } -} - -class CalcDisplay extends StatelessWidget { - const CalcDisplay({ this.content }); - - final String content; - - @override - Widget build(BuildContext context) { - return Center( - child: Text( - content, - style: const TextStyle(fontSize: 24.0), - ), - ); - } -} - -class KeyPad extends StatelessWidget { - const KeyPad({ this.calcState }); - - final _CalculatorState calcState; - - @override - Widget build(BuildContext context) { - final ThemeData themeData = ThemeData( - primarySwatch: Colors.purple, - brightness: Brightness.dark, - platform: Theme.of(context).platform, - ); - return Theme( - data: themeData, - child: Material( - child: Row( - children: [ - Expanded( - // We set flex equal to the number of columns so that the main keypad - // and the op keypad have sizes proportional to their number of - // columns. - flex: 3, - child: Column( - children: [ - KeyRow([ - NumberKey(7, calcState), - NumberKey(8, calcState), - NumberKey(9, calcState), - ]), - KeyRow([ - NumberKey(4, calcState), - NumberKey(5, calcState), - NumberKey(6, calcState), - ]), - KeyRow([ - NumberKey(1, calcState), - NumberKey(2, calcState), - NumberKey(3, calcState), - ]), - KeyRow([ - CalcKey('.', calcState.handlePointTap), - NumberKey(0, calcState), - CalcKey('=', calcState.handleEqualsTap), - ]), - ], - ), - ), - Expanded( - child: Material( - color: themeData.backgroundColor, - child: Column( - children: [ - CalcKey('\u232B', calcState.handleDelTap), - CalcKey('\u00F7', calcState.handleDivTap), - CalcKey('\u00D7', calcState.handleMultTap), - CalcKey('-', calcState.handleMinusTap), - CalcKey('+', calcState.handlePlusTap), - ], - ), - ), - ), - ], - ), - ), - ); - } -} - -class KeyRow extends StatelessWidget { - const KeyRow(this.keys); - - final List keys; - - @override - Widget build(BuildContext context) { - return Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: keys, - ), - ); - } -} - -class CalcKey extends StatelessWidget { - const CalcKey(this.text, this.onTap); - - final String text; - final GestureTapCallback onTap; - - @override - Widget build(BuildContext context) { - final Orientation orientation = MediaQuery.of(context).orientation; - return Expanded( - child: InkResponse( - onTap: onTap, - child: Center( - child: Text( - text, - style: TextStyle( - fontSize: (orientation == Orientation.portrait) ? 32.0 : 24.0 - ), - ), - ), - ), - ); - } -} - -class NumberKey extends CalcKey { - NumberKey(int value, _CalculatorState calcState) - : super('$value', () { - calcState.handleNumberTap(value); - }); -} diff --git a/web/gallery/lib/demo/calculator/logic.dart b/web/gallery/lib/demo/calculator/logic.dart deleted file mode 100644 index 43ddf6598..000000000 --- a/web/gallery/lib/demo/calculator/logic.dart +++ /dev/null @@ -1,343 +0,0 @@ -// 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. - -/// A token that composes an expression. There are several kinds of tokens -/// that represent arithmetic operation symbols, numbers and pieces of numbers. -/// We need to represent pieces of numbers because the user may have only -/// entered a partial expression so far. -class ExpressionToken { - ExpressionToken(this.stringRep); - - final String stringRep; - - @override - String toString() => stringRep; -} - -/// A token that represents a number. -class NumberToken extends ExpressionToken { - NumberToken(String stringRep, this.number) : super(stringRep); - - NumberToken.fromNumber(num number) : this('$number', number); - - final num number; -} - -/// A token that represents an integer. -class IntToken extends NumberToken { - IntToken(String stringRep) : super(stringRep, int.parse(stringRep)); -} - -/// A token that represents a floating point number. -class FloatToken extends NumberToken { - FloatToken(String stringRep) : super(stringRep, _parse(stringRep)); - - static double _parse(String stringRep) { - String toParse = stringRep; - if (toParse.startsWith('.')) - toParse = '0' + toParse; - if (toParse.endsWith('.')) - toParse = toParse + '0'; - return double.parse(toParse); - } -} - -/// A token that represents a number that is the result of a computation. -class ResultToken extends NumberToken { - ResultToken(num number) : super.fromNumber(round(number)); - - /// rounds `number` to 14 digits of precision. A double precision - /// floating point number is guaranteed to have at least this many - /// decimal digits of precision. - static num round(num number) { - if (number is int) - return number; - return double.parse(number.toStringAsPrecision(14)); - } -} - -/// A token that represents the unary minus prefix. -class LeadingNegToken extends ExpressionToken { - LeadingNegToken() : super('-'); -} - -enum Operation { Addition, Subtraction, Multiplication, Division } - -/// A token that represents an arithmetic operation symbol. -class OperationToken extends ExpressionToken { - OperationToken(this.operation) - : super(opString(operation)); - - Operation operation; - - static String opString(Operation operation) { - switch (operation) { - case Operation.Addition: - return ' + '; - case Operation.Subtraction: - return ' - '; - case Operation.Multiplication: - return ' \u00D7 '; - case Operation.Division: - return ' \u00F7 '; - } - assert(operation != null); - return null; - } -} - -/// As the user taps different keys the current expression can be in one -/// of several states. -enum ExpressionState { - /// The expression is empty or an operation symbol was just entered. - /// A new number must be started now. - Start, - - /// A minus sign was entered as a leading negative prefix. - LeadingNeg, - - /// We are in the midst of a number without a point. - Number, - - /// A point was just entered. - Point, - - /// We are in the midst of a number with a point. - NumberWithPoint, - - /// A result is being displayed - Result, -} - -/// An expression that can be displayed in a calculator. It is the result -/// of a sequence of user entries. It is represented by a sequence of tokens. -/// -/// The tokens are not in one to one correspondence with the key taps because we -/// use one token per number, not one token per digit. A [CalcExpression] is -/// immutable. The `append*` methods return a new [CalcExpression] that -/// represents the appropriate expression when one additional key tap occurs. -class CalcExpression { - CalcExpression(this._list, this.state); - - CalcExpression.empty() - : this([], ExpressionState.Start); - - CalcExpression.result(FloatToken result) - : _list = [], - state = ExpressionState.Result { - _list.add(result); - } - - /// The tokens comprising the expression. - final List _list; - /// The state of the expression. - final ExpressionState state; - - /// The string representation of the expression. This will be displayed - /// in the calculator's display panel. - @override - String toString() { - final StringBuffer buffer = StringBuffer(''); - buffer.writeAll(_list); - return buffer.toString(); - } - - /// Append a digit to the current expression and return a new expression - /// representing the result. Returns null to indicate that it is not legal - /// to append a digit in the current state. - CalcExpression appendDigit(int digit) { - ExpressionState newState = ExpressionState.Number; - ExpressionToken newToken; - final List outList = _list.toList(); - switch (state) { - case ExpressionState.Start: - // Start a new number with digit. - newToken = IntToken('$digit'); - break; - case ExpressionState.LeadingNeg: - // Replace the leading neg with a negative number starting with digit. - outList.removeLast(); - newToken = IntToken('-$digit'); - break; - case ExpressionState.Number: - final ExpressionToken last = outList.removeLast(); - newToken = IntToken('${last.stringRep}$digit'); - break; - case ExpressionState.Point: - case ExpressionState.NumberWithPoint: - final ExpressionToken last = outList.removeLast(); - newState = ExpressionState.NumberWithPoint; - newToken = FloatToken('${last.stringRep}$digit'); - break; - case ExpressionState.Result: - // Cannot enter a number now - return null; - } - outList.add(newToken); - return CalcExpression(outList, newState); - } - - /// Append a point to the current expression and return a new expression - /// representing the result. Returns null to indicate that it is not legal - /// to append a point in the current state. - CalcExpression appendPoint() { - ExpressionToken newToken; - final List outList = _list.toList(); - switch (state) { - case ExpressionState.Start: - newToken = FloatToken('.'); - break; - case ExpressionState.LeadingNeg: - case ExpressionState.Number: - final ExpressionToken last = outList.removeLast(); - newToken = FloatToken(last.stringRep + '.'); - break; - case ExpressionState.Point: - case ExpressionState.NumberWithPoint: - case ExpressionState.Result: - // Cannot enter a point now - return null; - } - outList.add(newToken); - return CalcExpression(outList, ExpressionState.Point); - } - - /// Append an operation symbol to the current expression and return a new - /// expression representing the result. Returns null to indicate that it is not - /// legal to append an operation symbol in the current state. - CalcExpression appendOperation(Operation op) { - switch (state) { - case ExpressionState.Start: - case ExpressionState.LeadingNeg: - case ExpressionState.Point: - // Cannot enter operation now. - return null; - case ExpressionState.Number: - case ExpressionState.NumberWithPoint: - case ExpressionState.Result: - break; - } - final List outList = _list.toList(); - outList.add(OperationToken(op)); - return CalcExpression(outList, ExpressionState.Start); - } - - /// Append a leading minus sign to the current expression and return a new - /// expression representing the result. Returns null to indicate that it is not - /// legal to append a leading minus sign in the current state. - CalcExpression appendLeadingNeg() { - switch (state) { - case ExpressionState.Start: - break; - case ExpressionState.LeadingNeg: - case ExpressionState.Point: - case ExpressionState.Number: - case ExpressionState.NumberWithPoint: - case ExpressionState.Result: - // Cannot enter leading neg now. - return null; - } - final List outList = _list.toList(); - outList.add(LeadingNegToken()); - return CalcExpression(outList, ExpressionState.LeadingNeg); - } - - /// Append a minus sign to the current expression and return a new expression - /// representing the result. Returns null to indicate that it is not legal - /// to append a minus sign in the current state. Depending on the current - /// state the minus sign will be interpreted as either a leading negative - /// sign or a subtraction operation. - CalcExpression appendMinus() { - switch (state) { - case ExpressionState.Start: - return appendLeadingNeg(); - case ExpressionState.LeadingNeg: - case ExpressionState.Point: - case ExpressionState.Number: - case ExpressionState.NumberWithPoint: - case ExpressionState.Result: - return appendOperation(Operation.Subtraction); - default: - return null; - } - } - - /// Computes the result of the current expression and returns a new - /// ResultExpression containing the result. Returns null to indicate that - /// it is not legal to compute a result in the current state. - CalcExpression computeResult() { - switch (state) { - case ExpressionState.Start: - case ExpressionState.LeadingNeg: - case ExpressionState.Point: - case ExpressionState.Result: - // Cannot compute result now. - return null; - case ExpressionState.Number: - case ExpressionState.NumberWithPoint: - break; - } - - // We make a copy of _list because CalcExpressions are supposed to - // be immutable. - final List list = _list.toList(); - // We obey order-of-operations by computing the sum of the 'terms', - // where a "term" is defined to be a sequence of numbers separated by - // multiplication or division symbols. - num currentTermValue = removeNextTerm(list); - while (list.isNotEmpty) { - final OperationToken opToken = list.removeAt(0); - final num nextTermValue = removeNextTerm(list); - switch (opToken.operation) { - case Operation.Addition: - currentTermValue += nextTermValue; - break; - case Operation.Subtraction: - currentTermValue -= nextTermValue; - break; - case Operation.Multiplication: - case Operation.Division: - // Logic error. - assert(false); - } - } - final List outList = [ - ResultToken(currentTermValue), - ]; - return CalcExpression(outList, ExpressionState.Result); - } - - /// Removes the next "term" from `list` and returns its numeric value. - /// A "term" is a sequence of number tokens separated by multiplication - /// and division symbols. - static num removeNextTerm(List list) { - assert(list != null && list.isNotEmpty); - final NumberToken firstNumToken = list.removeAt(0); - num currentValue = firstNumToken.number; - while (list.isNotEmpty) { - bool isDivision = false; - final OperationToken nextOpToken = list.first; - switch (nextOpToken.operation) { - case Operation.Addition: - case Operation.Subtraction: - // We have reached the end of the current term - return currentValue; - case Operation.Multiplication: - break; - case Operation.Division: - isDivision = true; - } - // Remove the operation token. - list.removeAt(0); - // Remove the next number token. - final NumberToken nextNumToken = list.removeAt(0); - final num nextNumber = nextNumToken.number; - if (isDivision) - currentValue /= nextNumber; - else - currentValue *= nextNumber; - } - return currentValue; - } -} diff --git a/web/gallery/lib/demo/calculator_demo.dart b/web/gallery/lib/demo/calculator_demo.dart deleted file mode 100644 index cc75bc469..000000000 --- a/web/gallery/lib/demo/calculator_demo.dart +++ /dev/null @@ -1,16 +0,0 @@ -// 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 'calculator/home.dart'; - -class CalculatorDemo extends StatelessWidget { - const CalculatorDemo({Key key}) : super(key: key); - - static const String routeName = '/calculator'; - - @override - Widget build(BuildContext context) => const Calculator(); -} diff --git a/web/gallery/lib/demo/colors_demo.dart b/web/gallery/lib/demo/colors_demo.dart deleted file mode 100644 index 85d7b8170..000000000 --- a/web/gallery/lib/demo/colors_demo.dart +++ /dev/null @@ -1,149 +0,0 @@ -// 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'; - -const double kColorItemHeight = 48.0; - -class Palette { - Palette({ this.name, this.primary, this.accent, this.threshold = 900}); - - final String name; - final MaterialColor primary; - final MaterialAccentColor accent; - final int threshold; // titles for indices > threshold are white, otherwise black - - bool get isValid => name != null && primary != null && threshold != null; -} - -final List allPalettes = [ - Palette(name: 'RED', primary: Colors.red, accent: Colors.redAccent, threshold: 300), - Palette(name: 'PINK', primary: Colors.pink, accent: Colors.pinkAccent, threshold: 200), - Palette(name: 'PURPLE', primary: Colors.purple, accent: Colors.purpleAccent, threshold: 200), - Palette(name: 'DEEP PURPLE', primary: Colors.deepPurple, accent: Colors.deepPurpleAccent, threshold: 200), - Palette(name: 'INDIGO', primary: Colors.indigo, accent: Colors.indigoAccent, threshold: 200), - Palette(name: 'BLUE', primary: Colors.blue, accent: Colors.blueAccent, threshold: 400), - Palette(name: 'LIGHT BLUE', primary: Colors.lightBlue, accent: Colors.lightBlueAccent, threshold: 500), - Palette(name: 'CYAN', primary: Colors.cyan, accent: Colors.cyanAccent, threshold: 600), - Palette(name: 'TEAL', primary: Colors.teal, accent: Colors.tealAccent, threshold: 400), - Palette(name: 'GREEN', primary: Colors.green, accent: Colors.greenAccent, threshold: 500), - Palette(name: 'LIGHT GREEN', primary: Colors.lightGreen, accent: Colors.lightGreenAccent, threshold: 600), - Palette(name: 'LIME', primary: Colors.lime, accent: Colors.limeAccent, threshold: 800), - Palette(name: 'YELLOW', primary: Colors.yellow, accent: Colors.yellowAccent), - Palette(name: 'AMBER', primary: Colors.amber, accent: Colors.amberAccent), - Palette(name: 'ORANGE', primary: Colors.orange, accent: Colors.orangeAccent, threshold: 700), - Palette(name: 'DEEP ORANGE', primary: Colors.deepOrange, accent: Colors.deepOrangeAccent, threshold: 400), - Palette(name: 'BROWN', primary: Colors.brown, threshold: 200), - Palette(name: 'GREY', primary: Colors.grey, threshold: 500), - Palette(name: 'BLUE GREY', primary: Colors.blueGrey, threshold: 500), -]; - - -class ColorItem extends StatelessWidget { - const ColorItem({ - Key key, - @required this.index, - @required this.color, - this.prefix = '', - }) : assert(index != null), - assert(color != null), - assert(prefix != null), - super(key: key); - - final int index; - final Color color; - final String prefix; - - String colorString() => "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; - - @override - Widget build(BuildContext context) { - return Semantics( - container: true, - child: Container( - height: kColorItemHeight, - padding: const EdgeInsets.symmetric(horizontal: 16.0), - color: color, - child: SafeArea( - top: false, - bottom: false, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text('$prefix$index'), - Text(colorString()), - ], - ), - ), - ), - ); - } -} - -class PaletteTabView extends StatelessWidget { - PaletteTabView({ - Key key, - @required this.colors, - }) : assert(colors != null && colors.isValid), - super(key: key); - - final Palette colors; - - static const List primaryKeys = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]; - static const List accentKeys = [100, 200, 400, 700]; - - @override - Widget build(BuildContext context) { - final TextTheme textTheme = Theme.of(context).textTheme; - final TextStyle whiteTextStyle = textTheme.body1.copyWith(color: Colors.white); - final TextStyle blackTextStyle = textTheme.body1.copyWith(color: Colors.black); - return Scrollbar( - child: ListView( - itemExtent: kColorItemHeight, - children: [ - ...primaryKeys.map((int index) { - return DefaultTextStyle( - style: index > colors.threshold ? whiteTextStyle : blackTextStyle, - child: ColorItem(index: index, color: colors.primary[index]), - ); - }), - if (colors.accent != null) - ...accentKeys.map((int index) { - return DefaultTextStyle( - style: index > colors.threshold ? whiteTextStyle : blackTextStyle, - child: ColorItem(index: index, color: colors.accent[index], prefix: 'A'), - ); - }), - ], - ), - ); - } -} - -class ColorsDemo extends StatelessWidget { - static const String routeName = '/colors'; - - @override - Widget build(BuildContext context) { - return DefaultTabController( - length: allPalettes.length, - child: Scaffold( - appBar: AppBar( - elevation: 0.0, - title: const Text('Colors'), - bottom: TabBar( - isScrollable: true, - tabs: allPalettes.map((Palette swatch) => Tab(text: swatch.name)).toList(), - ), - ), - body: TabBarView( - children: allPalettes.map((Palette colors) { - return PaletteTabView(colors: colors); - }).toList(), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/contacts_demo.dart b/web/gallery/lib/demo/contacts_demo.dart deleted file mode 100644 index 76753c4ae..000000000 --- a/web/gallery/lib/demo/contacts_demo.dart +++ /dev/null @@ -1,345 +0,0 @@ -// 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:flutter/material.dart'; -import 'package:flutter/services.dart'; - -class _ContactCategory extends StatelessWidget { - const _ContactCategory({ Key key, this.icon, this.children }) : super(key: key); - - final IconData icon; - final List children; - - @override - Widget build(BuildContext context) { - final ThemeData themeData = Theme.of(context); - return Container( - padding: const EdgeInsets.symmetric(vertical: 16.0), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: themeData.dividerColor)) - ), - child: DefaultTextStyle( - style: Theme.of(context).textTheme.subhead, - child: SafeArea( - top: false, - bottom: false, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.symmetric(vertical: 24.0), - width: 72.0, - child: Icon(icon, color: themeData.primaryColor), - ), - Expanded(child: Column(children: children)), - ], - ), - ), - ), - ); - } -} - -class _ContactItem extends StatelessWidget { - const _ContactItem({ Key key, this.icon, this.lines, this.tooltip, this.onPressed }) - : assert(lines.length > 1), - super(key: key); - - final IconData icon; - final List lines; - final String tooltip; - final VoidCallback onPressed; - - @override - Widget build(BuildContext context) { - final ThemeData themeData = Theme.of(context); - return MergeSemantics( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...lines.sublist(0, lines.length - 1).map((String line) => Text(line)), - Text(lines.last, style: themeData.textTheme.caption), - ], - ), - ), - if (icon != null) - SizedBox( - width: 72.0, - child: IconButton( - icon: Icon(icon), - color: themeData.primaryColor, - onPressed: onPressed, - ), - ), - ], - ), - ), - ); - } -} - -class ContactsDemo extends StatefulWidget { - static const String routeName = '/contacts'; - - @override - ContactsDemoState createState() => ContactsDemoState(); -} - -enum AppBarBehavior { normal, pinned, floating, snapping } - -class ContactsDemoState extends State { - static final GlobalKey _scaffoldKey = GlobalKey(); - final double _appBarHeight = 256.0; - - AppBarBehavior _appBarBehavior = AppBarBehavior.pinned; - - @override - Widget build(BuildContext context) { - return Theme( - data: ThemeData( - brightness: Brightness.light, - primarySwatch: Colors.indigo, - platform: Theme.of(context).platform, - ), - child: Scaffold( - key: _scaffoldKey, - body: CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: _appBarHeight, - pinned: _appBarBehavior == AppBarBehavior.pinned, - floating: _appBarBehavior == AppBarBehavior.floating || _appBarBehavior == AppBarBehavior.snapping, - snap: _appBarBehavior == AppBarBehavior.snapping, - actions: [ - IconButton( - icon: const Icon(Icons.create), - tooltip: 'Edit', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text("Editing isn't supported in this screen."), - )); - }, - ), - PopupMenuButton( - onSelected: (AppBarBehavior value) { - setState(() { - _appBarBehavior = value; - }); - }, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: AppBarBehavior.normal, - child: Text('App bar scrolls away'), - ), - const PopupMenuItem( - value: AppBarBehavior.pinned, - child: Text('App bar stays put'), - ), - const PopupMenuItem( - value: AppBarBehavior.floating, - child: Text('App bar floats'), - ), - const PopupMenuItem( - value: AppBarBehavior.snapping, - child: Text('App bar snaps'), - ), - ], - ), - ], - flexibleSpace: FlexibleSpaceBar( - title: const Text('Ali Connors'), - background: Stack( - fit: StackFit.expand, - children: [ - Image.asset( - 'people/ali_landscape.png', - package: 'flutter_gallery_assets', - fit: BoxFit.cover, - height: _appBarHeight, - ), - // This gradient ensures that the toolbar icons are distinct - // against the background image. - const DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment(0.0, -1.0), - end: Alignment(0.0, -0.4), - colors: [Color(0x60000000), Color(0x00000000)], - ), - ), - ), - ], - ), - ), - ), - SliverList( - delegate: SliverChildListDelegate([ - AnnotatedRegion( - value: SystemUiOverlayStyle.dark, - child: _ContactCategory( - icon: Icons.call, - children: [ - _ContactItem( - icon: Icons.message, - tooltip: 'Send message', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Pretend that this opened your SMS application.'), - )); - }, - lines: const [ - '(650) 555-1234', - 'Mobile', - ], - ), - _ContactItem( - icon: Icons.message, - tooltip: 'Send message', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('A messaging app appears.'), - )); - }, - lines: const [ - '(323) 555-6789', - 'Work', - ], - ), - _ContactItem( - icon: Icons.message, - tooltip: 'Send message', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Imagine if you will, a messaging application.'), - )); - }, - lines: const [ - '(650) 555-6789', - 'Home', - ], - ), - ], - ), - ), - _ContactCategory( - icon: Icons.contact_mail, - children: [ - _ContactItem( - icon: Icons.email, - tooltip: 'Send personal e-mail', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Here, your e-mail application would open.'), - )); - }, - lines: const [ - 'ali_connors@example.com', - 'Personal', - ], - ), - _ContactItem( - icon: Icons.email, - tooltip: 'Send work e-mail', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Summon your favorite e-mail application here.'), - )); - }, - lines: const [ - 'aliconnors@example.com', - 'Work', - ], - ), - ], - ), - _ContactCategory( - icon: Icons.location_on, - children: [ - _ContactItem( - icon: Icons.map, - tooltip: 'Open map', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('This would show a map of San Francisco.'), - )); - }, - lines: const [ - '2000 Main Street', - 'San Francisco, CA', - 'Home', - ], - ), - _ContactItem( - icon: Icons.map, - tooltip: 'Open map', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('This would show a map of Mountain View.'), - )); - }, - lines: const [ - '1600 Amphitheater Parkway', - 'Mountain View, CA', - 'Work', - ], - ), - _ContactItem( - icon: Icons.map, - tooltip: 'Open map', - onPressed: () { - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('This would also show a map, if this was not a demo.'), - )); - }, - lines: const [ - '126 Severyns Ave', - 'Mountain View, CA', - 'Jet Travel', - ], - ), - ], - ), - _ContactCategory( - icon: Icons.today, - children: [ - _ContactItem( - lines: const [ - 'Birthday', - 'January 9th, 1989', - ], - ), - _ContactItem( - lines: const [ - 'Wedding anniversary', - 'June 21st, 2014', - ], - ), - _ContactItem( - lines: const [ - 'First day in office', - 'January 20th, 2015', - ], - ), - _ContactItem( - lines: const [ - 'Last day in office', - 'August 9th, 2018', - ], - ), - ], - ), - ]), - ), - ], - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino.dart b/web/gallery/lib/demo/cupertino/cupertino.dart deleted file mode 100644 index d76a1e315..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 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. - -export 'cupertino_activity_indicator_demo.dart'; -export 'cupertino_alert_demo.dart'; -export 'cupertino_buttons_demo.dart'; -export 'cupertino_navigation_demo.dart'; -export 'cupertino_picker_demo.dart'; -export 'cupertino_refresh_demo.dart'; -export 'cupertino_segmented_control_demo.dart'; -export 'cupertino_slider_demo.dart'; -export 'cupertino_switch_demo.dart'; -export 'cupertino_text_field_demo.dart'; diff --git a/web/gallery/lib/demo/cupertino/cupertino_activity_indicator_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_activity_indicator_demo.dart deleted file mode 100644 index 549485714..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_activity_indicator_demo.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 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/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoProgressIndicatorDemo extends StatelessWidget { - static const String routeName = '/cupertino/progress_indicator'; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - middle: const Text('Activity Indicator'), - trailing: CupertinoDemoDocumentationButton(routeName), - ), - child: const Center( - child: CupertinoActivityIndicator(), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_alert_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_alert_demo.dart deleted file mode 100644 index 7fbfb0e89..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_alert_demo.dart +++ /dev/null @@ -1,262 +0,0 @@ -// 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/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoAlertDemo extends StatefulWidget { - static const String routeName = '/cupertino/alert'; - - @override - _CupertinoAlertDemoState createState() => _CupertinoAlertDemoState(); -} - -class _CupertinoAlertDemoState extends State { - String lastSelectedValue; - - void showDemoDialog({BuildContext context, Widget child}) { - showCupertinoDialog( - context: context, - builder: (BuildContext context) => child, - ).then((String value) { - if (value != null) { - setState(() { lastSelectedValue = value; }); - } - }); - } - - void showDemoActionSheet({BuildContext context, Widget child}) { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) => child, - ).then((String value) { - if (value != null) { - setState(() { lastSelectedValue = value; }); - } - }); - } - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Alerts'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoAlertDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: Builder( - builder: (BuildContext context) { - return Stack( - alignment: Alignment.center, - children: [ - CupertinoScrollbar( - child: ListView( - // Add more padding to the normal safe area. - padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0) - + MediaQuery.of(context).padding, - children: [ - CupertinoButton.filled( - child: const Text('Alert'), - onPressed: () => _onAlertPress(context), - ), - const Padding(padding: EdgeInsets.all(8.0)), - CupertinoButton.filled( - child: const Text('Alert with Title'), - padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0), - onPressed: () => _onAlertWithTitlePress(context), - ), - const Padding(padding: EdgeInsets.all(8.0)), - CupertinoButton.filled( - child: const Text('Alert with Buttons'), - padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0), - onPressed: () => _onAlertWithButtonsPress(context), - ), - const Padding(padding: EdgeInsets.all(8.0)), - CupertinoButton.filled( - child: const Text('Alert Buttons Only'), - padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0), - onPressed: () { - showDemoDialog( - context: context, - child: const CupertinoDessertDialog(), - ); - }, - ), - const Padding(padding: EdgeInsets.all(8.0)), - CupertinoButton.filled( - child: const Text('Action Sheet'), - padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0), - onPressed: () => _onActionSheetPress(context), - ), - ], - ), - ), - if (lastSelectedValue != null) - Positioned( - bottom: 32.0, - child: Text('You selected: $lastSelectedValue'), - ), - ], - ); - }, - ), - ), - ); - } - - void _onAlertPress(BuildContext context) { - showDemoDialog( - context: context, - child: CupertinoAlertDialog( - title: const Text('Discard draft?'), - actions: [ - CupertinoDialogAction( - child: const Text('Discard'), - isDestructiveAction: true, - onPressed: () => Navigator.pop(context, 'Discard'), - ), - CupertinoDialogAction( - child: const Text('Cancel'), - isDefaultAction: true, - onPressed: () => Navigator.pop(context, 'Cancel'), - ), - ], - ), - ); - } - - void _onAlertWithTitlePress(BuildContext context) { - showDemoDialog( - context: context, - child: CupertinoAlertDialog( - title: const Text('Allow "Maps" to access your location while you are using the app?'), - content: const Text('Your current location will be displayed on the map and used ' - 'for directions, nearby search results, and estimated travel times.'), - actions: [ - CupertinoDialogAction( - child: const Text('Don\'t Allow'), - onPressed: () => Navigator.pop(context, 'Disallow'), - ), - CupertinoDialogAction( - child: const Text('Allow'), - onPressed: () => Navigator.pop(context, 'Allow'), - ), - ], - ), - ); - } - - void _onAlertWithButtonsPress(BuildContext context) { - showDemoDialog( - context: context, - child: const CupertinoDessertDialog( - title: Text('Select Favorite Dessert'), - content: Text('Please select your favorite type of dessert from the ' - 'list below. Your selection will be used to customize the suggested ' - 'list of eateries in your area.'), - ), - ); - } - - void _onActionSheetPress(BuildContext context) { - showDemoActionSheet( - context: context, - child: CupertinoActionSheet( - title: const Text('Favorite Dessert'), - message: const Text('Please select the best dessert from the options below.'), - actions: [ - CupertinoActionSheetAction( - child: const Text('Profiteroles'), - onPressed: () => Navigator.pop(context, 'Profiteroles'), - ), - CupertinoActionSheetAction( - child: const Text('Cannolis'), - onPressed: () => Navigator.pop(context, 'Cannolis'), - ), - CupertinoActionSheetAction( - child: const Text('Trifle'), - onPressed: () => Navigator.pop(context, 'Trifle'), - ), - ], - cancelButton: CupertinoActionSheetAction( - child: const Text('Cancel'), - isDefaultAction: true, - onPressed: () => Navigator.pop(context, 'Cancel'), - ), - ), - ); - } -} - -class CupertinoDessertDialog extends StatelessWidget { - const CupertinoDessertDialog({Key key, this.title, this.content}) : super(key: key); - - final Widget title; - final Widget content; - - @override - Widget build(BuildContext context) { - return CupertinoAlertDialog( - title: title, - content: content, - actions: [ - CupertinoDialogAction( - child: const Text('Cheesecake'), - onPressed: () { - Navigator.pop(context, 'Cheesecake'); - }, - ), - CupertinoDialogAction( - child: const Text('Tiramisu'), - onPressed: () { - Navigator.pop(context, 'Tiramisu'); - }, - ), - CupertinoDialogAction( - child: const Text('Apple Pie'), - onPressed: () { - Navigator.pop(context, 'Apple Pie'); - }, - ), - CupertinoDialogAction( - child: const Text("Devil's food cake"), - onPressed: () { - Navigator.pop(context, "Devil's food cake"); - }, - ), - CupertinoDialogAction( - child: const Text('Banana Split'), - onPressed: () { - Navigator.pop(context, 'Banana Split'); - }, - ), - CupertinoDialogAction( - child: const Text('Oatmeal Cookie'), - onPressed: () { - Navigator.pop(context, 'Oatmeal Cookies'); - }, - ), - CupertinoDialogAction( - child: const Text('Chocolate Brownie'), - onPressed: () { - Navigator.pop(context, 'Chocolate Brownies'); - }, - ), - CupertinoDialogAction( - child: const Text('Cancel'), - isDestructiveAction: true, - onPressed: () { - Navigator.pop(context, 'Cancel'); - }, - ), - ], - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_buttons_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_buttons_demo.dart deleted file mode 100644 index 8bddc8c6a..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_buttons_demo.dart +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2017 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/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoButtonsDemo extends StatefulWidget { - static const String routeName = '/cupertino/buttons'; - - @override - _CupertinoButtonDemoState createState() => _CupertinoButtonDemoState(); -} - -class _CupertinoButtonDemoState extends State { - int _pressedCount = 0; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Buttons'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoButtonsDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: SafeArea( - child: Column( - children: [ - const Padding( - padding: EdgeInsets.all(16.0), - child: Text( - 'iOS themed buttons are flat. They can have borders or backgrounds but ' - 'only when necessary.' - ), - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(_pressedCount > 0 - ? 'Button pressed $_pressedCount time${_pressedCount == 1 ? "" : "s"}' - : ' '), - const Padding(padding: EdgeInsets.all(12.0)), - Align( - alignment: const Alignment(0.0, -0.2), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - CupertinoButton( - child: const Text('Cupertino Button'), - onPressed: () { - setState(() { _pressedCount += 1; }); - }, - ), - const CupertinoButton( - child: Text('Disabled'), - onPressed: null, - ), - ], - ), - ), - const Padding(padding: EdgeInsets.all(12.0)), - CupertinoButton.filled( - child: const Text('With Background'), - onPressed: () { - setState(() { _pressedCount += 1; }); - }, - ), - const Padding(padding: EdgeInsets.all(12.0)), - const CupertinoButton.filled( - child: Text('Disabled'), - onPressed: null, - ), - ], - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_navigation_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_navigation_demo.dart deleted file mode 100644 index a45f7e1f6..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_navigation_demo.dart +++ /dev/null @@ -1,812 +0,0 @@ -// Copyright 2017 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:async'; -import 'dart:math' as math; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -const List coolColors = [ - Color.fromARGB(255, 255, 59, 48), - Color.fromARGB(255, 255, 149, 0), - Color.fromARGB(255, 255, 204, 0), - Color.fromARGB(255, 76, 217, 100), - Color.fromARGB(255, 90, 200, 250), - Color.fromARGB(255, 0, 122, 255), - Color.fromARGB(255, 88, 86, 214), - Color.fromARGB(255, 255, 45, 85), -]; - -const List coolColorNames = [ - 'Sarcoline', 'Coquelicot', 'Smaragdine', 'Mikado', 'Glaucous', 'Wenge', - 'Fulvous', 'Xanadu', 'Falu', 'Eburnean', 'Amaranth', 'Australien', - 'Banan', 'Falu', 'Gingerline', 'Incarnadine', 'Labrador', 'Nattier', - 'Pervenche', 'Sinoper', 'Verditer', 'Watchet', 'Zaffre', -]; - -const int _kChildCount = 50; - -class CupertinoNavigationDemo extends StatelessWidget { - CupertinoNavigationDemo() - : colorItems = List.generate(_kChildCount, (int index) { - return coolColors[math.Random().nextInt(coolColors.length)]; - }) , - colorNameItems = List.generate(_kChildCount, (int index) { - return coolColorNames[math.Random().nextInt(coolColorNames.length)]; - }); - - static const String routeName = '/cupertino/navigation'; - - final List colorItems; - final List colorNameItems; - - @override - Widget build(BuildContext context) { - return WillPopScope( - // Prevent swipe popping of this page. Use explicit exit buttons only. - onWillPop: () => Future.value(true), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: CupertinoTabScaffold( - tabBar: CupertinoTabBar( - items: const [ - BottomNavigationBarItem( - icon: Icon(CupertinoIcons.home), - title: Text('Home'), - ), - BottomNavigationBarItem( - icon: Icon(CupertinoIcons.conversation_bubble), - title: Text('Support'), - ), - BottomNavigationBarItem( - icon: Icon(CupertinoIcons.profile_circled), - title: Text('Profile'), - ), - ], - ), - tabBuilder: (BuildContext context, int index) { - assert(index >= 0 && index <= 2); - switch (index) { - case 0: - return CupertinoTabView( - builder: (BuildContext context) { - return CupertinoDemoTab1( - colorItems: colorItems, - colorNameItems: colorNameItems, - ); - }, - defaultTitle: 'Colors', - ); - break; - case 1: - return CupertinoTabView( - builder: (BuildContext context) => CupertinoDemoTab2(), - defaultTitle: 'Support Chat', - ); - break; - case 2: - return CupertinoTabView( - builder: (BuildContext context) => CupertinoDemoTab3(), - defaultTitle: 'Account', - ); - break; - } - return null; - }, - ), - ), - ); - } -} - -class ExitButton extends StatelessWidget { - const ExitButton(); - - @override - Widget build(BuildContext context) { - return CupertinoButton( - padding: EdgeInsets.zero, - child: const Tooltip( - message: 'Back', - child: Text('Exit'), - excludeFromSemantics: true, - ), - onPressed: () { - // The demo is on the root navigator. - Navigator.of(context, rootNavigator: true).pop(); - }, - ); - } -} - -final Widget trailingButtons = Row( - mainAxisSize: MainAxisSize.min, - children: [ - CupertinoDemoDocumentationButton(CupertinoNavigationDemo.routeName), - const Padding(padding: EdgeInsets.only(left: 8.0)), - const ExitButton(), - ], -); - -class CupertinoDemoTab1 extends StatelessWidget { - const CupertinoDemoTab1({this.colorItems, this.colorNameItems}); - - final List colorItems; - final List colorNameItems; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - backgroundColor: CupertinoColors.systemGroupedBackground, - child: CustomScrollView( - semanticChildCount: _kChildCount, - slivers: [ - CupertinoSliverNavigationBar( - trailing: trailingButtons, - ), - SliverPadding( - // Top media padding consumed by CupertinoSliverNavigationBar. - // Left/Right media padding consumed by Tab1RowItem. - padding: MediaQuery.of(context).removePadding( - removeTop: true, - removeLeft: true, - removeRight: true, - ).padding, - sliver: SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return Tab1RowItem( - index: index, - lastItem: index == _kChildCount - 1, - color: colorItems[index], - colorName: colorNameItems[index], - ); - }, - childCount: _kChildCount, - ), - ), - ), - ], - ), - ); - } -} - -class Tab1RowItem extends StatelessWidget { - const Tab1RowItem({this.index, this.lastItem, this.color, this.colorName}); - - final int index; - final bool lastItem; - final Color color; - final String colorName; - - @override - Widget build(BuildContext context) { - final Widget row = GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - Navigator.of(context).push(CupertinoPageRoute( - title: colorName, - builder: (BuildContext context) => Tab1ItemPage( - color: color, - colorName: colorName, - index: index, - ), - )); - }, - child: Container( - color: CupertinoDynamicColor.resolve(CupertinoColors.systemBackground, context), - child: SafeArea( - top: false, - bottom: false, - child: Padding( - padding: const EdgeInsets.only(left: 16.0, top: 8.0, bottom: 8.0, right: 8.0), - child: Row( - children: [ - Container( - height: 60.0, - width: 60.0, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(8.0), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(colorName), - const Padding(padding: EdgeInsets.only(top: 8.0)), - Text( - 'Buy this cool color', - style: TextStyle( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondaryLabel, context), - fontSize: 13.0, - fontWeight: FontWeight.w300, - ), - ), - ], - ), - ), - ), - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.plus_circled, - semanticLabel: 'Add', - ), - onPressed: () { }, - ), - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.share, - semanticLabel: 'Share', - ), - onPressed: () { }, - ), - ], - ), - ), - ), - ), - ); - - if (lastItem) { - return row; - } - - return Column( - children: [ - row, - Container( - height: 1.0, - color: CupertinoDynamicColor.resolve(CupertinoColors.separator, context), - ), - ], - ); - } -} - -class Tab1ItemPage extends StatefulWidget { - const Tab1ItemPage({this.color, this.colorName, this.index}); - - final Color color; - final String colorName; - final int index; - - @override - State createState() => Tab1ItemPageState(); -} - -class Tab1ItemPageState extends State { - @override - void initState() { - super.initState(); - relatedColors = List.generate(10, (int index) { - final math.Random random = math.Random(); - return Color.fromARGB( - 255, - (widget.color.red + random.nextInt(100) - 50).clamp(0, 255), - (widget.color.green + random.nextInt(100) - 50).clamp(0, 255), - (widget.color.blue + random.nextInt(100) - 50).clamp(0, 255), - ); - }); - } - - List relatedColors; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: const CupertinoNavigationBar( - trailing: ExitButton(), - ), - child: SafeArea( - top: false, - bottom: false, - child: ListView( - children: [ - const Padding(padding: EdgeInsets.only(top: 16.0)), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - height: 128.0, - width: 128.0, - decoration: BoxDecoration( - color: widget.color, - borderRadius: BorderRadius.circular(24.0), - ), - ), - const Padding(padding: EdgeInsets.only(left: 18.0)), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - widget.colorName, - style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold), - ), - const Padding(padding: EdgeInsets.only(top: 6.0)), - Text( - 'Item number ${widget.index}', - style: TextStyle( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondaryLabel, context), - fontSize: 16.0, - fontWeight: FontWeight.w100, - ), - ), - const Padding(padding: EdgeInsets.only(top: 20.0)), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CupertinoButton.filled( - minSize: 30.0, - padding: const EdgeInsets.symmetric(horizontal: 24.0), - borderRadius: BorderRadius.circular(32.0), - child: const Text( - 'GET', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.w700, - letterSpacing: -0.28, - ), - ), - onPressed: () { }, - ), - CupertinoButton.filled( - minSize: 30.0, - padding: EdgeInsets.zero, - borderRadius: BorderRadius.circular(32.0), - child: const Icon(CupertinoIcons.ellipsis), - onPressed: () { }, - ), - ], - ), - ], - ), - ), - ], - ), - ), - const Padding( - padding: EdgeInsets.only(left: 16.0, top: 28.0, bottom: 8.0), - child: Text( - 'USERS ALSO LIKED', - style: TextStyle( - color: Color(0xFF646464), - letterSpacing: -0.60, - fontSize: 15.0, - fontWeight: FontWeight.w500, - ), - ), - ), - SizedBox( - height: 200.0, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: 10, - itemExtent: 160.0, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - color: relatedColors[index], - ), - child: Center( - child: CupertinoButton( - child: const Icon( - CupertinoIcons.plus_circled, - color: CupertinoColors.white, - size: 36.0, - ), - onPressed: () { }, - ), - ), - ), - ); - }, - ), - ), - ], - ), - ), - ); - } -} - -class CupertinoDemoTab2 extends StatelessWidget { - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - trailing: trailingButtons, - ), - child: CupertinoScrollbar( - child: ListView( - children: [ - CupertinoUserInterfaceLevel( - data: CupertinoUserInterfaceLevelData.elevated, - child: Tab2Header(), - ), - ...buildTab2Conversation(), - ], - ), - ), - ); - } -} - -class Tab2Header extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: SafeArea( - top: false, - bottom: false, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(16.0)), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - decoration: BoxDecoration( - color: CupertinoDynamicColor.resolve(CupertinoColors.systemFill, context), - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'SUPPORT TICKET', - style: TextStyle( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondaryLabel, context), - letterSpacing: -0.9, - fontSize: 14.0, - fontWeight: FontWeight.w500, - ), - ), - Text( - 'Show More', - style: TextStyle( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondaryLabel, context), - letterSpacing: -0.6, - fontSize: 12.0, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ), - Container( - decoration: BoxDecoration( - color: CupertinoDynamicColor.resolve(CupertinoColors.quaternarySystemFill, context), - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Product or product packaging damaged during transit', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - letterSpacing: -0.46, - ), - ), - const Padding(padding: EdgeInsets.only(top: 16.0)), - const Text( - 'REVIEWERS', - style: TextStyle( - color: Color(0xFF646464), - fontSize: 12.0, - letterSpacing: -0.6, - fontWeight: FontWeight.w500, - ), - ), - const Padding(padding: EdgeInsets.only(top: 8.0)), - Row( - children: [ - Container( - width: 44.0, - height: 44.0, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'people/square/trevor.png', - package: _kGalleryAssetsPackage, - ), - ), - shape: BoxShape.circle, - ), - ), - const Padding(padding: EdgeInsets.only(left: 8.0)), - Container( - width: 44.0, - height: 44.0, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'people/square/sandra.png', - package: _kGalleryAssetsPackage, - ), - ), - shape: BoxShape.circle, - ), - ), - const Padding(padding: EdgeInsets.only(left: 2.0)), - const Icon( - CupertinoIcons.check_mark_circled, - color: Color(0xFF646464), - size: 20.0, - ), - ], - ), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } -} - -enum Tab2ConversationBubbleColor { - blue, - gray, -} - -class Tab2ConversationBubble extends StatelessWidget { - const Tab2ConversationBubble({this.text, this.color}); - - final String text; - final Tab2ConversationBubbleColor color; - - @override - Widget build(BuildContext context) { - Color backgroundColor; - Color foregroundColor; - - switch (color) { - case Tab2ConversationBubbleColor.gray: - backgroundColor = CupertinoDynamicColor.resolve(CupertinoColors.systemFill, context); - foregroundColor = CupertinoDynamicColor.resolve(CupertinoColors.label, context); - break; - case Tab2ConversationBubbleColor.blue: - backgroundColor = CupertinoTheme.of(context).primaryColor; - foregroundColor = CupertinoColors.white; - break; - } - - return Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(18.0)), - color: backgroundColor, - ), - margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0), - padding: const EdgeInsets.symmetric(horizontal: 14.0, vertical: 10.0), - child: Text( - text, - style: TextStyle( - color: foregroundColor, - letterSpacing: -0.4, - fontSize: 15.0, - fontWeight: FontWeight.w400, - ), - ), - ); - } -} - -class Tab2ConversationAvatar extends StatelessWidget { - const Tab2ConversationAvatar({this.text, this.color}); - - final String text; - final Color color; - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - begin: FractionalOffset.topCenter, - end: FractionalOffset.bottomCenter, - colors: [ - color, - Color.fromARGB( - color.alpha, - (color.red - 60).clamp(0, 255), - (color.green - 60).clamp(0, 255), - (color.blue - 60).clamp(0, 255), - ), - ], - ), - ), - margin: const EdgeInsets.only(left: 8.0, bottom: 8.0), - padding: const EdgeInsets.all(12.0), - child: Text( - text, - style: const TextStyle( - color: CupertinoColors.white, - fontSize: 13.0, - fontWeight: FontWeight.w500, - ), - ), - ); - } -} - -class Tab2ConversationRow extends StatelessWidget { - const Tab2ConversationRow({this.avatar, this.text}); - - final Tab2ConversationAvatar avatar; - final String text; - - @override - Widget build(BuildContext context) { - final bool isSelf = avatar == null; - return SafeArea( - child: Row( - mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: isSelf ? CrossAxisAlignment.center : CrossAxisAlignment.end, - children: [ - if (avatar != null) avatar, - CupertinoUserInterfaceLevel( - data: CupertinoUserInterfaceLevelData.elevated, - child: Tab2ConversationBubble( - text: text, - color: isSelf - ? Tab2ConversationBubbleColor.blue - : Tab2ConversationBubbleColor.gray, - ), - ), - ], - ), - ); - } -} - -List buildTab2Conversation() { - return [ - const Tab2ConversationRow( - text: "My Xanadu doesn't look right", - ), - const Tab2ConversationRow( - avatar: Tab2ConversationAvatar( - text: 'KL', - color: Color(0xFFFD5015), - ), - text: "We'll rush you a new one.\nIt's gonna be incredible", - ), - const Tab2ConversationRow( - text: 'Awesome thanks!', - ), - const Tab2ConversationRow( - avatar: Tab2ConversationAvatar( - text: 'SJ', - color: Color(0xFF34CAD6), - ), - text: "We'll send you our\nnewest Labrador too!", - ), - const Tab2ConversationRow( - text: 'Yay', - ), - const Tab2ConversationRow( - avatar: Tab2ConversationAvatar( - text: 'KL', - color: Color(0xFFFD5015), - ), - text: "Actually there's one more thing...", - ), - const Tab2ConversationRow( - text: "What's that?", - ), - ]; -} - -class CupertinoDemoTab3 extends StatelessWidget { - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(trailing: trailingButtons), - backgroundColor: CupertinoColors.systemBackground, - child: ListView( - children: [ - const Padding(padding: EdgeInsets.only(top: 32.0)), - GestureDetector( - onTap: () { - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - fullscreenDialog: true, - builder: (BuildContext context) => Tab3Dialog(), - ), - ); - }, - child: Container( - decoration: BoxDecoration( - color: CupertinoTheme.of(context).scaffoldBackgroundColor, - border: const Border( - top: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), - bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), - ), - ), - height: 44.0, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: SafeArea( - top: false, - bottom: false, - child: Row( - children: [ - Text( - 'Sign in', - style: TextStyle(color: CupertinoTheme.of(context).primaryColor), - ), - ], - ), - ), - ), - ), - ), - ], - ), - ); - } -} - -class Tab3Dialog extends StatelessWidget { - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - leading: CupertinoButton( - child: const Text('Cancel'), - padding: EdgeInsets.zero, - onPressed: () { - Navigator.of(context).pop(false); - }, - ), - ), - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - CupertinoIcons.profile_circled, - size: 160.0, - color: Color(0xFF646464), - ), - const Padding(padding: EdgeInsets.only(top: 18.0)), - CupertinoButton.filled( - child: const Text('Sign in'), - onPressed: () { - Navigator.pop(context); - }, - ), - ], - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_picker_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_picker_demo.dart deleted file mode 100644 index fb3d31213..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_picker_demo.dart +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2017 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/cupertino.dart'; -import 'package:intl/intl.dart'; - -import '../../gallery/demo.dart'; -import 'cupertino_navigation_demo.dart' show coolColorNames; - -const double _kPickerSheetHeight = 216.0; -const double _kPickerItemHeight = 32.0; - -class CupertinoPickerDemo extends StatefulWidget { - static const String routeName = '/cupertino/picker'; - - @override - _CupertinoPickerDemoState createState() => _CupertinoPickerDemoState(); -} - -class _BottomPicker extends StatelessWidget { - const _BottomPicker({ - Key key, - @required this.child, - }) : assert(child != null), - super(key: key); - - final Widget child; - - @override - Widget build(BuildContext context) { - return Container( - height: _kPickerSheetHeight, - padding: const EdgeInsets.only(top: 6.0), - color: CupertinoColors.systemBackground.resolveFrom(context), - child: DefaultTextStyle( - style: TextStyle( - color: CupertinoColors.label.resolveFrom(context), - fontSize: 22.0, - ), - child: GestureDetector( - // Blocks taps from propagating to the modal sheet and popping. - onTap: () { }, - child: SafeArea( - top: false, - child: child, - ), - ), - ), - ); - } -} - -class _Menu extends StatelessWidget { - const _Menu({ - Key key, - @required this.children, - }) : assert(children != null), - super(key: key); - - final List children; - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - color: CupertinoTheme.of(context).scaffoldBackgroundColor, - border: const Border( - top: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), - bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), - ), - ), - height: 44.0, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: SafeArea( - top: false, - bottom: false, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: children, - ), - ), - ), - ); - } -} - -class _CupertinoPickerDemoState extends State { - int _selectedColorIndex = 0; - - Duration timer = const Duration(); - - // Value that is shown in the date picker in date mode. - DateTime date = DateTime.now(); - - // Value that is shown in the date picker in time mode. - DateTime time = DateTime.now(); - - // Value that is shown in the date picker in dateAndTime mode. - DateTime dateTime = DateTime.now(); - - Widget _buildColorPicker(BuildContext context) { - final FixedExtentScrollController scrollController = - FixedExtentScrollController(initialItem: _selectedColorIndex); - - return GestureDetector( - onTap: () async { - await showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return _BottomPicker( - child: CupertinoPicker( - scrollController: scrollController, - itemExtent: _kPickerItemHeight, - backgroundColor: CupertinoColors.systemBackground.resolveFrom(context), - onSelectedItemChanged: (int index) { - setState(() => _selectedColorIndex = index); - }, - children: List.generate(coolColorNames.length, (int index) { - return Center( - child: Text(coolColorNames[index]), - ); - }), - ), - ); - }, - ); - }, - child: _Menu( - children: [ - const Text('Favorite Color'), - Text( - coolColorNames[_selectedColorIndex], - style: TextStyle(color: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)), - ), - ], - ), - ); - } - - Widget _buildCountdownTimerPicker(BuildContext context) { - return GestureDetector( - onTap: () { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return _BottomPicker( - child: CupertinoTimerPicker( - backgroundColor: CupertinoColors.systemBackground.resolveFrom(context), - initialTimerDuration: timer, - onTimerDurationChanged: (Duration newTimer) { - setState(() => timer = newTimer); - }, - ), - ); - }, - ); - }, - child: _Menu( - children: [ - const Text('Countdown Timer'), - Text( - '${timer.inHours}:' - '${(timer.inMinutes % 60).toString().padLeft(2,'0')}:' - '${(timer.inSeconds % 60).toString().padLeft(2,'0')}', - style: TextStyle(color: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)), - ), - ], - ), - ); - } - - Widget _buildDatePicker(BuildContext context) { - return GestureDetector( - onTap: () { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return _BottomPicker( - child: CupertinoDatePicker( - backgroundColor: CupertinoColors.systemBackground.resolveFrom(context), - mode: CupertinoDatePickerMode.date, - initialDateTime: date, - onDateTimeChanged: (DateTime newDateTime) { - setState(() => date = newDateTime); - }, - ), - ); - }, - ); - }, - child: _Menu( - children: [ - const Text('Date'), - Text( - DateFormat.yMMMMd().format(date), - style: TextStyle(color: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)), - ), - ] - ), - ); - } - - Widget _buildTimePicker(BuildContext context) { - return GestureDetector( - onTap: () { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return _BottomPicker( - child: CupertinoDatePicker( - backgroundColor: CupertinoColors.systemBackground.resolveFrom(context), - mode: CupertinoDatePickerMode.time, - initialDateTime: time, - onDateTimeChanged: (DateTime newDateTime) { - setState(() => time = newDateTime); - }, - ), - ); - }, - ); - }, - child: _Menu( - children: [ - const Text('Time'), - Text( - DateFormat.jm().format(time), - style: TextStyle(color: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)), - ), - ], - ), - ); - } - - Widget _buildDateAndTimePicker(BuildContext context) { - return GestureDetector( - onTap: () { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return _BottomPicker( - child: CupertinoDatePicker( - backgroundColor: CupertinoColors.systemBackground.resolveFrom(context), - mode: CupertinoDatePickerMode.dateAndTime, - initialDateTime: dateTime, - onDateTimeChanged: (DateTime newDateTime) { - setState(() => dateTime = newDateTime); - }, - ), - ); - }, - ); - }, - child: _Menu( - children: [ - const Text('Date and Time'), - Text( - DateFormat.yMMMd().add_jm().format(dateTime), - style: TextStyle(color: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Picker'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoPickerDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: ListView( - children: [ - const Padding(padding: EdgeInsets.only(top: 32.0)), - _buildColorPicker(context), - _buildCountdownTimerPicker(context), - _buildDatePicker(context), - _buildTimePicker(context), - _buildDateAndTimePicker(context), - ], - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_refresh_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_refresh_demo.dart deleted file mode 100644 index fb77ccae8..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_refresh_demo.dart +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2018 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:async'; -import 'dart:math' show Random; - -import 'package:flutter/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoRefreshControlDemo extends StatefulWidget { - static const String routeName = '/cupertino/refresh'; - - @override - _CupertinoRefreshControlDemoState createState() => _CupertinoRefreshControlDemoState(); -} - -class _CupertinoRefreshControlDemoState extends State { - List> randomizedContacts; - - @override - void initState() { - super.initState(); - repopulateList(); - } - - void repopulateList() { - final Random random = Random(); - randomizedContacts = List>.generate( - 100, - (int index) { - return contacts[random.nextInt(contacts.length)] - // Randomly adds a telephone icon next to the contact or not. - ..add(random.nextBool().toString()); - }, - ); - } - - @override - Widget build(BuildContext context) { - return DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: CupertinoPageScaffold( - backgroundColor: CupertinoColors.systemGroupedBackground, - child: CustomScrollView( - // If left unspecified, the [CustomScrollView] appends an - // [AlwaysScrollableScrollPhysics]. Behind the scene, the ScrollableState - // will attach that [AlwaysScrollableScrollPhysics] to the output of - // [ScrollConfiguration.of] which will be a [ClampingScrollPhysics] - // on Android. - // To demonstrate the iOS behavior in this demo and to ensure that the list - // always scrolls, we specifically use a [BouncingScrollPhysics] combined - // with a [AlwaysScrollableScrollPhysics] - physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), - slivers: [ - CupertinoSliverNavigationBar( - largeTitle: const Text('Refresh'), - // We're specifying a back label here because the previous page - // is a Material page. CupertinoPageRoutes could auto-populate - // these back labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoRefreshControlDemo.routeName), - ), - CupertinoSliverRefreshControl( - onRefresh: () { - return Future.delayed(const Duration(seconds: 2)) - ..then((_) { - if (mounted) { - setState(() => repopulateList()); - } - }); - }, - ), - SliverSafeArea( - top: false, // Top safe area is consumed by the navigation bar. - sliver: SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return _ListItem( - name: randomizedContacts[index][0], - place: randomizedContacts[index][1], - date: randomizedContacts[index][2], - called: randomizedContacts[index][3] == 'true', - ); - }, - childCount: 20, - ), - ), - ), - ], - ), - ), - ); - } -} - -List> contacts = >[ - ['George Washington', 'Westmoreland County', ' 4/30/1789'], - ['John Adams', 'Braintree', ' 3/4/1797'], - ['Thomas Jefferson', 'Shadwell', ' 3/4/1801'], - ['James Madison', 'Port Conway', ' 3/4/1809'], - ['James Monroe', 'Monroe Hall', ' 3/4/1817'], - ['Andrew Jackson', 'Waxhaws Region South/North', ' 3/4/1829'], - ['John Quincy Adams', 'Braintree', ' 3/4/1825'], - ['William Henry Harrison', 'Charles City County', ' 3/4/1841'], - ['Martin Van Buren', 'Kinderhook New', ' 3/4/1837'], - ['Zachary Taylor', 'Barboursville', ' 3/4/1849'], - ['John Tyler', 'Charles City County', ' 4/4/1841'], - ['James Buchanan', 'Cove Gap', ' 3/4/1857'], - ['James K. Polk', 'Pineville North', ' 3/4/1845'], - ['Millard Fillmore', 'Summerhill New', '7/9/1850'], - ['Franklin Pierce', 'Hillsborough New', ' 3/4/1853'], - ['Andrew Johnson', 'Raleigh North', ' 4/15/1865'], - ['Abraham Lincoln', 'Sinking Spring', ' 3/4/1861'], - ['Ulysses S. Grant', 'Point Pleasant', ' 3/4/1869'], - ['Rutherford B. Hayes', 'Delaware', ' 3/4/1877'], - ['Chester A. Arthur', 'Fairfield', ' 9/19/1881'], - ['James A. Garfield', 'Moreland Hills', ' 3/4/1881'], - ['Benjamin Harrison', 'North Bend', ' 3/4/1889'], - ['Grover Cleveland', 'Caldwell New', ' 3/4/1885'], - ['William McKinley', 'Niles', ' 3/4/1897'], - ['Woodrow Wilson', 'Staunton', ' 3/4/1913'], - ['William H. Taft', 'Cincinnati', ' 3/4/1909'], - ['Theodore Roosevelt', 'New York City New', ' 9/14/1901'], - ['Warren G. Harding', 'Blooming Grove', ' 3/4/1921'], - ['Calvin Coolidge', 'Plymouth', '8/2/1923'], - ['Herbert Hoover', 'West Branch', ' 3/4/1929'], - ['Franklin D. Roosevelt', 'Hyde Park New', ' 3/4/1933'], - ['Harry S. Truman', 'Lamar', ' 4/12/1945'], - ['Dwight D. Eisenhower', 'Denison', ' 1/20/1953'], - ['Lyndon B. Johnson', 'Stonewall', '11/22/1963'], - ['Ronald Reagan', 'Tampico', ' 1/20/1981'], - ['Richard Nixon', 'Yorba Linda', ' 1/20/1969'], - ['Gerald Ford', 'Omaha', 'August 9/1974'], - ['John F. Kennedy', 'Brookline', ' 1/20/1961'], - ['George H. W. Bush', 'Milton', ' 1/20/1989'], - ['Jimmy Carter', 'Plains', ' 1/20/1977'], - ['George W. Bush', 'New Haven', ' 1/20, 2001'], - ['Bill Clinton', 'Hope', ' 1/20/1993'], - ['Barack Obama', 'Honolulu', ' 1/20/2009'], - ['Donald J. Trump', 'New York City', ' 1/20/2017'], -]; - -class _ListItem extends StatelessWidget { - const _ListItem({ - this.name, - this.place, - this.date, - this.called, - }); - - final String name; - final String place; - final String date; - final bool called; - - @override - Widget build(BuildContext context) { - return Container( - color: CupertinoDynamicColor.resolve(CupertinoColors.systemBackground, context), - height: 60.0, - padding: const EdgeInsets.only(top: 9.0), - child: Row( - children: [ - Container( - width: 38.0, - child: called - ? Align( - alignment: Alignment.topCenter, - child: Icon( - CupertinoIcons.phone_solid, - color: CupertinoColors.inactiveGray.resolveFrom(context), - size: 18.0, - ), - ) - : null, - ), - Expanded( - child: Container( - decoration: const BoxDecoration( - border: Border( - bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), - ), - ), - padding: const EdgeInsets.only(left: 1.0, bottom: 9.0, right: 10.0), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.w600, - letterSpacing: -0.18, - ), - ), - Text( - place, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 15.0, - letterSpacing: -0.24, - color: CupertinoColors.inactiveGray.resolveFrom(context), - ), - ), - ], - ), - ), - Text( - date, - style: TextStyle( - color: CupertinoColors.inactiveGray.resolveFrom(context), - fontSize: 15.0, - letterSpacing: -0.41, - ), - ), - Padding( - padding: const EdgeInsets.only(left: 9.0), - child: Icon( - CupertinoIcons.info, - color: CupertinoTheme.of(context).primaryColor, - ), - ), - ], - ), - ), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_segmented_control_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_segmented_control_demo.dart deleted file mode 100644 index 89b3251d6..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_segmented_control_demo.dart +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2018 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/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const Color _kKeyUmbraOpacity = Color(0x33000000); // alpha = 0.2 -const Color _kKeyPenumbraOpacity = Color(0x24000000); // alpha = 0.14 -const Color _kAmbientShadowOpacity = Color(0x1F000000); // alpha = 0.12 - -class CupertinoSegmentedControlDemo extends StatefulWidget { - static const String routeName = 'cupertino/segmented_control'; - - @override - _CupertinoSegmentedControlDemoState createState() => _CupertinoSegmentedControlDemoState(); -} - -class _CupertinoSegmentedControlDemoState extends State { - final Map children = const { - 0: Text('Midnight'), - 1: Text('Viridian'), - 2: Text('Cerulean'), - }; - - final Map icons = const { - 0: Center( - child: FlutterLogo( - colors: Colors.indigo, - size: 200.0, - ), - ), - 1: Center( - child: FlutterLogo( - colors: Colors.teal, - size: 200.0, - ), - ), - 2: Center( - child: FlutterLogo( - colors: Colors.cyan, - size: 200.0, - ), - ), - }; - - int currentSegment = 0; - - void onValueChanged(int newValue) { - setState(() { - currentSegment = newValue; - }); - } - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Segmented Control'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoSegmentedControlDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 13), - child: SafeArea( - child: Column( - children: [ - const Padding(padding: EdgeInsets.all(16.0)), - SizedBox( - width: 500.0, - child: CupertinoSegmentedControl( - children: children, - onValueChanged: onValueChanged, - groupValue: currentSegment, - ), - ), - SizedBox( - width: 500, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CupertinoSlidingSegmentedControl( - children: children, - onValueChanged: onValueChanged, - groupValue: currentSegment, - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 32.0, - horizontal: 16.0, - ), - child: CupertinoUserInterfaceLevel( - data: CupertinoUserInterfaceLevelData.elevated, - child: Builder( - builder: (BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric( - vertical: 64.0, - horizontal: 16.0, - ), - decoration: BoxDecoration( - color: CupertinoTheme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(3.0), - boxShadow: const [ - BoxShadow( - offset: Offset(0.0, 3.0), - blurRadius: 5.0, - spreadRadius: -1.0, - color: _kKeyUmbraOpacity, - ), - BoxShadow( - offset: Offset(0.0, 6.0), - blurRadius: 10.0, - spreadRadius: 0.0, - color: _kKeyPenumbraOpacity, - ), - BoxShadow( - offset: Offset(0.0, 1.0), - blurRadius: 18.0, - spreadRadius: 0.0, - color: _kAmbientShadowOpacity, - ), - ], - ), - child: icons[currentSegment], - ); - }, - ), - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_slider_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_slider_demo.dart deleted file mode 100644 index bce7687f3..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_slider_demo.dart +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2017 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/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoSliderDemo extends StatefulWidget { - static const String routeName = '/cupertino/slider'; - - @override - _CupertinoSliderDemoState createState() => _CupertinoSliderDemoState(); -} - -class _CupertinoSliderDemoState extends State { - double _value = 25.0; - double _discreteValue = 20.0; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Sliders'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoSliderDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: SafeArea( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - CupertinoSlider( - value: _value, - min: 0.0, - max: 100.0, - onChanged: (double value) { - setState(() { - _value = value; - }); - }, - ), - Text('Cupertino Continuous: ${_value.toStringAsFixed(1)}'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - CupertinoSlider( - value: _discreteValue, - min: 0.0, - max: 100.0, - divisions: 5, - onChanged: (double value) { - setState(() { - _discreteValue = value; - }); - }, - ), - Text('Cupertino Discrete: $_discreteValue'), - ], - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_switch_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_switch_demo.dart deleted file mode 100644 index 2e5b6d9a7..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_switch_demo.dart +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 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/cupertino.dart'; - -import '../../gallery/demo.dart'; - -class CupertinoSwitchDemo extends StatefulWidget { - static const String routeName = '/cupertino/switch'; - - @override - _CupertinoSwitchDemoState createState() => _CupertinoSwitchDemoState(); -} - -class _CupertinoSwitchDemoState extends State { - - bool _switchValue = false; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: const Text('Switch'), - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - trailing: CupertinoDemoDocumentationButton(CupertinoSwitchDemo.routeName), - ), - child: DefaultTextStyle( - style: CupertinoTheme.of(context).textTheme.textStyle, - child: SafeArea( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Semantics( - container: true, - child: Column( - children: [ - CupertinoSwitch( - value: _switchValue, - onChanged: (bool value) { - setState(() { - _switchValue = value; - }); - }, - ), - Text( - "Enabled - ${_switchValue ? "On" : "Off"}" - ), - ], - ), - ), - Semantics( - container: true, - child: Column( - children: const [ - CupertinoSwitch( - value: true, - onChanged: null, - ), - Text( - 'Disabled - On' - ), - ], - ), - ), - Semantics( - container: true, - child: Column( - children: const [ - CupertinoSwitch( - value: false, - onChanged: null, - ), - Text( - 'Disabled - Off' - ), - ], - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/cupertino/cupertino_text_field_demo.dart b/web/gallery/lib/demo/cupertino/cupertino_text_field_demo.dart deleted file mode 100644 index fc36ccecc..000000000 --- a/web/gallery/lib/demo/cupertino/cupertino_text_field_demo.dart +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018 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/cupertino.dart'; - -class CupertinoTextFieldDemo extends StatefulWidget { - static const String routeName = '/cupertino/text_fields'; - - @override - _CupertinoTextFieldDemoState createState() { - return _CupertinoTextFieldDemoState(); - } -} - -class _CupertinoTextFieldDemoState extends State { - TextEditingController _chatTextController; - TextEditingController _locationTextController; - - @override - void initState() { - super.initState(); - _chatTextController = TextEditingController(); - _locationTextController = TextEditingController(text: 'Montreal, Canada'); - } - - Widget _buildChatTextField() { - return CupertinoTextField( - controller: _chatTextController, - textCapitalization: TextCapitalization.sentences, - placeholder: 'Text Message', - decoration: BoxDecoration( - border: Border.all( - width: 0.0, - color: CupertinoColors.inactiveGray, - ), - borderRadius: BorderRadius.circular(15.0), - ), - maxLines: null, - keyboardType: TextInputType.multiline, - prefix: const Padding(padding: EdgeInsets.symmetric(horizontal: 4.0)), - suffix: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: CupertinoButton( - color: CupertinoColors.activeGreen, - minSize: 0.0, - child: const Icon( - CupertinoIcons.up_arrow, - size: 21.0, - color: CupertinoColors.white, - ), - padding: const EdgeInsets.all(2.0), - borderRadius: BorderRadius.circular(15.0), - onPressed: ()=> setState(()=> _chatTextController.clear()), - ), - ), - autofocus: true, - suffixMode: OverlayVisibilityMode.editing, - onSubmitted: (String text)=> setState(()=> _chatTextController.clear()), - ); - } - - Widget _buildNameField() { - return const CupertinoTextField( - prefix: Icon( - CupertinoIcons.person_solid, - color: CupertinoColors.lightBackgroundGray, - size: 28.0, - ), - padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0), - clearButtonMode: OverlayVisibilityMode.editing, - textCapitalization: TextCapitalization.words, - autocorrect: false, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)), - ), - placeholder: 'Name', - ); - } - - Widget _buildEmailField() { - return const CupertinoTextField( - prefix: Icon( - CupertinoIcons.mail_solid, - color: CupertinoColors.lightBackgroundGray, - size: 28.0, - ), - padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0), - clearButtonMode: OverlayVisibilityMode.editing, - keyboardType: TextInputType.emailAddress, - autocorrect: false, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)), - ), - placeholder: 'Email', - ); - } - - Widget _buildLocationField() { - return CupertinoTextField( - controller: _locationTextController, - prefix: const Icon( - CupertinoIcons.location_solid, - color: CupertinoColors.lightBackgroundGray, - size: 28.0, - ), - padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0), - clearButtonMode: OverlayVisibilityMode.editing, - textCapitalization: TextCapitalization.words, - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)), - ), - placeholder: 'Location', - ); - } - - Widget _buildPinField() { - return const CupertinoTextField( - prefix: Icon( - CupertinoIcons.padlock_solid, - color: CupertinoColors.lightBackgroundGray, - size: 28.0, - ), - padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0), - clearButtonMode: OverlayVisibilityMode.editing, - keyboardType: TextInputType.number, - autocorrect: false, - obscureText: true, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)), - ), - placeholder: 'Create a PIN', - ); - } - - Widget _buildTagsField() { - return CupertinoTextField( - controller: TextEditingController(text: 'colleague, reading club'), - prefix: const Icon( - CupertinoIcons.tags_solid, - color: CupertinoColors.lightBackgroundGray, - size: 28.0, - ), - enabled: false, - padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0), - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)), - ), - ); - } - - @override - Widget build(BuildContext context) { - return DefaultTextStyle( - style: const TextStyle( - fontFamily: '.SF UI Text', - inherit: false, - fontSize: 17.0, - color: CupertinoColors.black, - ), - child: CupertinoPageScaffold( - navigationBar: const CupertinoNavigationBar( - // We're specifying a back label here because the previous page is a - // Material page. CupertinoPageRoutes could auto-populate these back - // labels. - previousPageTitle: 'Cupertino', - middle: Text('Text Fields'), - ), - child: CupertinoScrollbar( - child: ListView( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 16.0), - child: Column( - children: [ - _buildNameField(), - _buildEmailField(), - _buildLocationField(), - _buildPinField(), - _buildTagsField(), - ], - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 16.0), - child: _buildChatTextField(), - ), - ], - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/fortnightly/README.md b/web/gallery/lib/demo/fortnightly/README.md deleted file mode 100644 index 45c220334..000000000 --- a/web/gallery/lib/demo/fortnightly/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Fortnightly - -A Flutter sample app based on the Material study Fortnightly (a hypothetical, online newspaper.) It -showcases print-quality, custom typography, Material Theming, and text-heavy UI design and layout. - -For info on the Fortnightly Material Study, see: https://material.io/design/material-studies/fortnightly.html - -## Goals for this sample - -* Help you understand how to customize and layout text. -* Provide you with example code for - * Text - * A short app bar (the menu button top left.) - * Avatar images - -## Widgets / APIs - -* BeveledRectangleBorder -* BoxConstraints on Container -* CircleAvatar -* ExactAssetImage -* Fonts -* SafeArea -* Stack -* SingleChildScrollView -* Text -* TextStyle -* TextTheme - -## Notice - -* Theming is passed as a parameter in the constructor of `MaterialApp` (`theme:`). -* `SafeArea` adds padding around notches and virtual home buttons on screens that have them (like - iPhone X+). Here, it protects the `ShortAppBar` from overlapping with the status bar (time) - and makes sure the bottom of the newspaper article has padding beneath it if necessary. -* The entire newspaper article is wrapped in a `SingleChildScrollView` widget which ensures that the - entire article can be viewed no matter what the screen's size or orientation is. -* The `Text` widget with text ' ¬ ' has a `TextStyle` that changes one parameter of an inherited - `TextStyle` using `.apply()``. -* The `Text` widget with text 'Connor Eghan' has a `TextStyle` created explicitly instead of - inheriting from theming. -* You can break up long strings in your source files by putting them on multiple lines. -* Fonts are imported with multiple files expressing their weights (Bold, Light, Medium, Regular) - but are accessed with a `FontWeight` value like `FontWeight.w800` for Merriweather-Bold.ttf. - -## Questions/issues - -If you have a general question about developing in Flutter, the best places to go are: - -* [The FlutterDev Google Group](https://groups.google.com/forum/#!forum/flutter-dev) -* [The Flutter Gitter channel](https://gitter.im/flutter/flutter) -* [StackOverflow](https://stackoverflow.com/questions/tagged/flutter) diff --git a/web/gallery/lib/demo/fortnightly/fortnightly.dart b/web/gallery/lib/demo/fortnightly/fortnightly.dart deleted file mode 100644 index 1e0209e73..000000000 --- a/web/gallery/lib/demo/fortnightly/fortnightly.dart +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 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'; - -class FortnightlyDemo extends StatelessWidget { - static const String routeName = '/fortnightly'; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Fortnightly Demo', - theme: _fortnightlyTheme, - home: Scaffold( - body: Stack( - children: [ - FruitPage(), - SafeArea( - child: ShortAppBar( - onBackPressed: () { - Navigator.pop(context); - }, - ), - ), - ], - ), - ), - ); - } -} - -class ShortAppBar extends StatelessWidget { - const ShortAppBar({ this.onBackPressed }); - - final VoidCallback onBackPressed; - - @override - Widget build(BuildContext context) { - return SizedBox( - width: 96, - height: 50, - child: Material( - color: Theme.of(context).colorScheme.surface, - elevation: 4, - shape: const BeveledRectangleBorder( - borderRadius: BorderRadius.only(bottomRight: Radius.circular(22)), - ), - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.arrow_back), - tooltip: 'Back', - onPressed: onBackPressed, - ), - const SizedBox(width: 12), - Image.asset( - 'logos/fortnightly/fortnightly_logo.png', - package: 'flutter_gallery_assets', - ), - ], - ), - ), - ); - } -} - -class FruitPage extends StatelessWidget { - static final String paragraph1 = '''Have you ever held a quince? It\'s strange; - covered in a fuzz somewhere between peach skin and a spider web. And it\'s - hard as soft lumber. You\'d be forgiven for thinking it\'s veneered Larch-wood. - But inhale the aroma and you\'ll instantly know you have something wonderful. - Its scent can fill a room for days. And all this before you\'ve even cooked it. -'''.replaceAll('\n', ''); - - static final String paragraph2 = '''Pomegranates on the other hand have become - almost ubiquitous. You can find its juice in any bodega, Walmart, and even some - gas stations. But at what cost? The pomegranate juice craze of the aughts made - \"megafarmers\" Lynda and Stewart Resnick billions. Unfortunately, it takes a lot - of water to make that much pomegranate juice. Water the Resnicks get from their - majority stake in the Kern Water Bank. How did one family come to hold control - over water meant for the whole central valley of California? The story will shock you. -'''.replaceAll('\n', ''); - - @override - Widget build(BuildContext context) { - final TextTheme textTheme = Theme.of(context).primaryTextTheme; - - return SingleChildScrollView( - child: SafeArea( - top: false, - child: Container( - color: Theme.of(context).colorScheme.surface, - child: Column( - children: [ - Container( - constraints: const BoxConstraints.expand(height: 248), - child: Image.asset( - 'food/fruits.png', - package: 'flutter_gallery_assets', - fit: BoxFit.fitWidth, - ), - ), - const SizedBox(height: 17), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - 'US', - style: textTheme.overline, - ), - Text( - ' ¬ ', - // TODO(larche): Replace textTheme.display3.color with a ColorScheme value when known. - style: textTheme.overline.apply(color: textTheme.display3.color), - ), - Text( - 'CULTURE', - style: textTheme.overline, - ), - ], - ), - const SizedBox(height: 10), - Text( - 'Quince for Wisdom, Persimmon for Luck, Pomegranate for Love', - style: textTheme.display1, - ), - const SizedBox(height: 10), - Text( - 'How these crazy fruits sweetened our hearts, relationships,' - 'and puffed pastries', - style: textTheme.body1, - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Row( - children: [ - const CircleAvatar( - backgroundImage: ExactAssetImage( - 'people/square/trevor.png', - package: 'flutter_gallery_assets', - ), - radius: 20, - ), - const SizedBox(width: 12), - Text( - 'by', - style: textTheme.display3, - ), - const SizedBox(width: 4), - const Text( - 'Connor Eghan', - style: TextStyle( - fontFamily: 'Merriweather', - fontSize: 18, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - ), - ], - ), - ), - Text( - '$paragraph1\n\n$paragraph2', - style: textTheme.body2, - ), - ], - ), - ), - ], - ), - ), - ), - ); - } -} - -final ThemeData _fortnightlyTheme = _buildFortnightlyTheme(); - -ThemeData _buildFortnightlyTheme() { - final ThemeData base = ThemeData.light(); - return base.copyWith( - primaryTextTheme: _buildTextTheme(base.primaryTextTheme), - scaffoldBackgroundColor: Colors.white, - ); -} - -TextTheme _buildTextTheme(TextTheme base) { - TextTheme theme = base.apply(bodyColor: Colors.black); - theme = theme.apply(displayColor: Colors.black); - - theme = theme.copyWith( - display1: base.display1.copyWith( - fontFamily: 'Merriweather', - fontStyle: FontStyle.italic, - fontSize: 28, - fontWeight: FontWeight.w800, - color: Colors.black, - height: .88, - ), - display3: base.display3.copyWith( - fontFamily: 'LibreFranklin', - fontSize: 18, - fontWeight: FontWeight.w500, - color: Colors.black.withAlpha(153), - ), - headline: base.headline.copyWith(fontWeight: FontWeight.w500), - body1: base.body1.copyWith( - fontFamily: 'Merriweather', - fontSize: 14, - fontWeight: FontWeight.w300, - color: const Color(0xFF666666), - height: 1.11, - ), - body2: base.body2.copyWith( - fontFamily: 'Merriweather', - fontSize: 16, - fontWeight: FontWeight.w300, - color: const Color(0xFF666666), - height: 1.4, - letterSpacing: .25, - ), - overline: const TextStyle( - fontFamily: 'LibreFranklin', - fontSize: 10, - fontWeight: FontWeight.w700, - color: Colors.black, - ), - ); - - return theme; -} diff --git a/web/gallery/lib/demo/images_demo.dart b/web/gallery/lib/demo/images_demo.dart deleted file mode 100644 index e2d02cd59..000000000 --- a/web/gallery/lib/demo/images_demo.dart +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2014 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 '../gallery/demo.dart'; - -class ImagesDemo extends StatelessWidget { - static const String routeName = '/images'; - - @override - Widget build(BuildContext context) { - return TabbedComponentDemoScaffold( - title: 'Animated images', - demos: [ - ComponentDemoTabData( - tabName: 'WEBP', - description: '', - exampleCodeTag: 'animated_image', - demoWidget: Semantics( - label: 'Example of animated WEBP', - child: Image.asset( - 'animated_images/animated_flutter_stickers.webp', - package: 'flutter_gallery_assets', - ), - ), - ), - ComponentDemoTabData( - tabName: 'GIF', - description: '', - exampleCodeTag: 'animated_image', - demoWidget: Semantics( - label: 'Example of animated GIF', - child:Image.asset( - 'animated_images/animated_flutter_lgtm.gif', - package: 'flutter_gallery_assets', - ), - ), - ), - ], - ); - } -} diff --git a/web/gallery/lib/demo/material/backdrop_demo.dart b/web/gallery/lib/demo/material/backdrop_demo.dart deleted file mode 100644 index 89fb9fb27..000000000 --- a/web/gallery/lib/demo/material/backdrop_demo.dart +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2018 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 'package:flutter/material.dart'; - -// This demo displays one Category at a time. The backdrop show a list -// of all of the categories and the selected category is displayed -// (CategoryView) on top of the backdrop. - -class Category { - const Category({ this.title, this.assets }); - final String title; - final List assets; - @override - String toString() => '$runtimeType("$title")'; -} - -const List allCategories = [ - Category( - title: 'Accessories', - assets: [ - 'products/belt.png', - 'products/earrings.png', - 'products/backpack.png', - 'products/hat.png', - 'products/scarf.png', - 'products/sunnies.png', - ], - ), - Category( - title: 'Blue', - assets: [ - 'products/backpack.png', - 'products/cup.png', - 'products/napkins.png', - 'products/top.png', - ], - ), - Category( - title: 'Cold Weather', - assets: [ - 'products/jacket.png', - 'products/jumper.png', - 'products/scarf.png', - 'products/sweater.png', - 'products/sweats.png', - ], - ), - Category( - title: 'Home', - assets: [ - 'products/cup.png', - 'products/napkins.png', - 'products/planters.png', - 'products/table.png', - 'products/teaset.png', - ], - ), - Category( - title: 'Tops', - assets: [ - 'products/jumper.png', - 'products/shirt.png', - 'products/sweater.png', - 'products/top.png', - ], - ), - Category( - title: 'Everything', - assets: [ - 'products/backpack.png', - 'products/belt.png', - 'products/cup.png', - 'products/dress.png', - 'products/earrings.png', - 'products/flatwear.png', - 'products/hat.png', - 'products/jacket.png', - 'products/jumper.png', - 'products/napkins.png', - 'products/planters.png', - 'products/scarf.png', - 'products/shirt.png', - 'products/sunnies.png', - 'products/sweater.png', - 'products/sweats.png', - 'products/table.png', - 'products/teaset.png', - 'products/top.png', - ], - ), -]; - -class CategoryView extends StatelessWidget { - const CategoryView({ Key key, this.category }) : super(key: key); - - final Category category; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Scrollbar( - child: ListView( - key: PageStorageKey(category), - padding: const EdgeInsets.symmetric( - vertical: 16.0, - horizontal: 64.0, - ), - children: category.assets.map((String asset) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Card( - child: Container( - width: 144.0, - alignment: Alignment.center, - child: Column( - children: [ - Image.asset( - asset, - package: 'flutter_gallery_assets', - fit: BoxFit.contain, - ), - Container( - padding: const EdgeInsets.only(bottom: 16.0), - alignment: AlignmentDirectional.center, - child: Text( - asset, - style: theme.textTheme.caption, - ), - ), - ], - ), - ), - ), - const SizedBox(height: 24.0), - ], - ); - }).toList(), - ), - ); - } -} - -// One BackdropPanel is visible at a time. It's stacked on top of the -// the BackdropDemo. -class BackdropPanel extends StatelessWidget { - const BackdropPanel({ - Key key, - this.onTap, - this.onVerticalDragUpdate, - this.onVerticalDragEnd, - this.title, - this.child, - }) : super(key: key); - - final VoidCallback onTap; - final GestureDragUpdateCallback onVerticalDragUpdate; - final GestureDragEndCallback onVerticalDragEnd; - final Widget title; - final Widget child; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Material( - elevation: 2.0, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onVerticalDragUpdate: onVerticalDragUpdate, - onVerticalDragEnd: onVerticalDragEnd, - onTap: onTap, - child: Container( - height: 48.0, - padding: const EdgeInsetsDirectional.only(start: 16.0), - alignment: AlignmentDirectional.centerStart, - child: DefaultTextStyle( - style: theme.textTheme.subhead, - child: Tooltip( - message: 'Tap to dismiss', - child: title, - ), - ), - ), - ), - const Divider(height: 1.0), - Expanded(child: child), - ], - ), - ); - } -} - -// Cross fades between 'Select a Category' and 'Asset Viewer'. -class BackdropTitle extends AnimatedWidget { - const BackdropTitle({ - Key key, - Listenable listenable, - }) : super(key: key, listenable: listenable); - - @override - Widget build(BuildContext context) { - final Animation animation = listenable; - return DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.title, - softWrap: false, - overflow: TextOverflow.ellipsis, - child: Stack( - children: [ - Opacity( - opacity: CurvedAnimation( - parent: ReverseAnimation(animation), - curve: const Interval(0.5, 1.0), - ).value, - child: const Text('Select a Category'), - ), - Opacity( - opacity: CurvedAnimation( - parent: animation, - curve: const Interval(0.5, 1.0), - ).value, - child: const Text('Asset Viewer'), - ), - ], - ), - ); - } -} - -// This widget is essentially the backdrop itself. -class BackdropDemo extends StatefulWidget { - static const String routeName = '/material/backdrop'; - - @override - _BackdropDemoState createState() => _BackdropDemoState(); -} - -class _BackdropDemoState extends State with SingleTickerProviderStateMixin { - final GlobalKey _backdropKey = GlobalKey(debugLabel: 'Backdrop'); - AnimationController _controller; - Category _category = allCategories[0]; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 300), - value: 1.0, - vsync: this, - ); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _changeCategory(Category category) { - setState(() { - _category = category; - _controller.fling(velocity: 2.0); - }); - } - - bool get _backdropPanelVisible { - final AnimationStatus status = _controller.status; - return status == AnimationStatus.completed || status == AnimationStatus.forward; - } - - void _toggleBackdropPanelVisibility() { - _controller.fling(velocity: _backdropPanelVisible ? -2.0 : 2.0); - } - - double get _backdropHeight { - final RenderBox renderBox = _backdropKey.currentContext.findRenderObject(); - return renderBox.size.height; - } - - // By design: the panel can only be opened with a swipe. To close the panel - // the user must either tap its heading or the backdrop's menu icon. - - void _handleDragUpdate(DragUpdateDetails details) { - if (_controller.isAnimating || _controller.status == AnimationStatus.completed) - return; - - _controller.value -= details.primaryDelta / (_backdropHeight ?? details.primaryDelta); - } - - void _handleDragEnd(DragEndDetails details) { - if (_controller.isAnimating || _controller.status == AnimationStatus.completed) - return; - - final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight; - if (flingVelocity < 0.0) - _controller.fling(velocity: math.max(2.0, -flingVelocity)); - else if (flingVelocity > 0.0) - _controller.fling(velocity: math.min(-2.0, -flingVelocity)); - else - _controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0); - } - - // Stacks a BackdropPanel, which displays the selected category, on top - // of the backdrop. The categories are displayed with ListTiles. Just one - // can be selected at a time. This is a LayoutWidgetBuild function because - // we need to know how big the BackdropPanel will be to set up its - // animation. - Widget _buildStack(BuildContext context, BoxConstraints constraints) { - const double panelTitleHeight = 48.0; - final Size panelSize = constraints.biggest; - final double panelTop = panelSize.height - panelTitleHeight; - - final Animation panelAnimation = _controller.drive( - RelativeRectTween( - begin: RelativeRect.fromLTRB( - 0.0, - panelTop - MediaQuery.of(context).padding.bottom, - 0.0, - panelTop - panelSize.height, - ), - end: const RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0), - ), - ); - - final ThemeData theme = Theme.of(context); - final List backdropItems = allCategories.map((Category category) { - final bool selected = category == _category; - return Material( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4.0)), - ), - color: selected - ? Colors.white.withOpacity(0.25) - : Colors.transparent, - child: ListTile( - title: Text(category.title), - selected: selected, - onTap: () { - _changeCategory(category); - }, - ), - ); - }).toList(); - - return Container( - key: _backdropKey, - color: theme.primaryColor, - child: Stack( - children: [ - ListTileTheme( - iconColor: theme.primaryIconTheme.color, - textColor: theme.primaryTextTheme.title.color.withOpacity(0.6), - selectedColor: theme.primaryTextTheme.title.color, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: backdropItems, - ), - ), - ), - PositionedTransition( - rect: panelAnimation, - child: BackdropPanel( - onTap: _toggleBackdropPanelVisibility, - onVerticalDragUpdate: _handleDragUpdate, - onVerticalDragEnd: _handleDragEnd, - title: Text(_category.title), - child: CategoryView(category: _category), - ), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - elevation: 0.0, - title: BackdropTitle( - listenable: _controller.view, - ), - actions: [ - IconButton( - onPressed: _toggleBackdropPanelVisibility, - icon: AnimatedIcon( - icon: AnimatedIcons.close_menu, - semanticLabel: 'close', - progress: _controller.view, - ), - ), - ], - ), - body: LayoutBuilder( - builder: _buildStack, - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/banner_demo.dart b/web/gallery/lib/demo/material/banner_demo.dart deleted file mode 100644 index d555a092b..000000000 --- a/web/gallery/lib/demo/material/banner_demo.dart +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2019 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 '../../gallery/demo.dart'; - -enum BannerDemoAction { - reset, - showMultipleActions, - showLeading, -} - -class BannerDemo extends StatefulWidget { - const BannerDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/banner'; - - @override - _BannerDemoState createState() => _BannerDemoState(); -} - -class _BannerDemoState extends State { - static const int _numItems = 20; - bool _displayBanner = true; - bool _showMultipleActions = true; - bool _showLeading = true; - - void handleDemoAction(BannerDemoAction action) { - setState(() { - switch (action) { - case BannerDemoAction.reset: - _displayBanner = true; - _showMultipleActions = true; - _showLeading = true; - break; - case BannerDemoAction.showMultipleActions: - _showMultipleActions = !_showMultipleActions; - break; - case BannerDemoAction.showLeading: - _showLeading = !_showLeading; - break; - } - }); - } - - @override - Widget build(BuildContext context) { - final Widget banner = MaterialBanner( - content: const Text('Your password was updated on your other device. Please sign in again.'), - leading: _showLeading ? const CircleAvatar(child: Icon(Icons.access_alarm)) : null, - actions: [ - FlatButton( - child: const Text('SIGN IN'), - onPressed: () { - setState(() { - _displayBanner = false; - }); - }, - ), - if (_showMultipleActions) - FlatButton( - child: const Text('DISMISS'), - onPressed: () { - setState(() { - _displayBanner = false; - }); - }, - ), - ], - ); - - return Scaffold( - appBar: AppBar( - title: const Text('Banner'), - actions: [ - MaterialDemoDocumentationButton(BannerDemo.routeName), - PopupMenuButton( - onSelected: handleDemoAction, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: BannerDemoAction.reset, - child: Text('Reset the banner'), - ), - const PopupMenuDivider(), - CheckedPopupMenuItem( - value: BannerDemoAction.showMultipleActions, - checked: _showMultipleActions, - child: const Text('Multiple actions'), - ), - CheckedPopupMenuItem( - value: BannerDemoAction.showLeading, - checked: _showLeading, - child: const Text('Leading icon'), - ), - ], - ), - ], - ), - body: ListView.builder(itemCount: _displayBanner ? _numItems + 1 : _numItems, itemBuilder: (BuildContext context, int index) { - if (index == 0 && _displayBanner) { - return banner; - } - return ListTile(title: Text('Item ${_displayBanner ? index : index + 1}'),); - }), - ); - } -} diff --git a/web/gallery/lib/demo/material/bottom_app_bar_demo.dart b/web/gallery/lib/demo/material/bottom_app_bar_demo.dart deleted file mode 100644 index d3da0fb87..000000000 --- a/web/gallery/lib/demo/material/bottom_app_bar_demo.dart +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2018 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 '../../gallery/demo.dart'; - -class BottomAppBarDemo extends StatefulWidget { - static const String routeName = '/material/bottom_app_bar'; - - @override - State createState() => _BottomAppBarDemoState(); -} - -// Flutter generally frowns upon abbrevation however this class uses two -// abbrevations extensively: "fab" for floating action button, and "bab" -// for bottom application bar. - -class _BottomAppBarDemoState extends State { - static final GlobalKey _scaffoldKey = GlobalKey(); - - // FAB shape - - static const _ChoiceValue kNoFab = _ChoiceValue( - title: 'None', - label: 'do not show a floating action button', - value: null, - ); - - static const _ChoiceValue kCircularFab = _ChoiceValue( - title: 'Circular', - label: 'circular floating action button', - value: FloatingActionButton( - onPressed: _showSnackbar, - child: Icon(Icons.add, semanticLabel: 'Action'), - backgroundColor: Colors.orange, - ), - ); - - static const _ChoiceValue kDiamondFab = _ChoiceValue( - title: 'Diamond', - label: 'diamond shape floating action button', - value: _DiamondFab( - onPressed: _showSnackbar, - child: Icon(Icons.add, semanticLabel: 'Action'), - ), - ); - - // Notch - - static const _ChoiceValue kShowNotchTrue = _ChoiceValue( - title: 'On', - label: 'show bottom appbar notch', - value: true, - ); - - static const _ChoiceValue kShowNotchFalse = _ChoiceValue( - title: 'Off', - label: 'do not show bottom appbar notch', - value: false, - ); - - // FAB Position - - static const _ChoiceValue kFabEndDocked = _ChoiceValue( - title: 'Attached - End', - label: 'floating action button is docked at the end of the bottom app bar', - value: FloatingActionButtonLocation.endDocked, - ); - - static const _ChoiceValue kFabCenterDocked = _ChoiceValue( - title: 'Attached - Center', - label: 'floating action button is docked at the center of the bottom app bar', - value: FloatingActionButtonLocation.centerDocked, - ); - - static const _ChoiceValue kFabEndFloat= _ChoiceValue( - title: 'Free - End', - label: 'floating action button floats above the end of the bottom app bar', - value: FloatingActionButtonLocation.endFloat, - ); - - static const _ChoiceValue kFabCenterFloat = _ChoiceValue( - title: 'Free - Center', - label: 'floating action button is floats above the center of the bottom app bar', - value: FloatingActionButtonLocation.centerFloat, - ); - - static void _showSnackbar() { - const String text = - "When the Scaffold's floating action button location changes, " - 'the floating action button animates to its new position.' - 'The BottomAppBar adapts its shape appropriately.'; - _scaffoldKey.currentState.showSnackBar( - const SnackBar(content: Text(text)), - ); - } - - // App bar color - - static const List<_NamedColor> kBabColors = <_NamedColor>[ - _NamedColor(null, 'Clear'), - _NamedColor(Color(0xFFFFC100), 'Orange'), - _NamedColor(Color(0xFF91FAFF), 'Light Blue'), - _NamedColor(Color(0xFF00D1FF), 'Cyan'), - _NamedColor(Color(0xFF00BCFF), 'Cerulean'), - _NamedColor(Color(0xFF009BEE), 'Blue'), - ]; - - _ChoiceValue _fabShape = kCircularFab; - _ChoiceValue _showNotch = kShowNotchTrue; - _ChoiceValue _fabLocation = kFabEndDocked; - Color _babColor = kBabColors.first.color; - - void _onShowNotchChanged(_ChoiceValue value) { - setState(() { - _showNotch = value; - }); - } - - void _onFabShapeChanged(_ChoiceValue value) { - setState(() { - _fabShape = value; - }); - } - - void _onFabLocationChanged(_ChoiceValue value) { - setState(() { - _fabLocation = value; - }); - } - - void _onBabColorChanged(Color value) { - setState(() { - _babColor = value; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Bottom app bar'), - elevation: 0.0, - actions: [ - MaterialDemoDocumentationButton(BottomAppBarDemo.routeName), - IconButton( - icon: const Icon(Icons.sentiment_very_satisfied, semanticLabel: 'Update shape'), - onPressed: () { - setState(() { - _fabShape = _fabShape == kCircularFab ? kDiamondFab : kCircularFab; - }); - }, - ), - ], - ), - body: Scrollbar( - child: ListView( - padding: const EdgeInsets.only(bottom: 88.0), - children: [ - const _Heading('FAB Shape'), - - _RadioItem(kCircularFab, _fabShape, _onFabShapeChanged), - _RadioItem(kDiamondFab, _fabShape, _onFabShapeChanged), - _RadioItem(kNoFab, _fabShape, _onFabShapeChanged), - - const Divider(), - const _Heading('Notch'), - - _RadioItem(kShowNotchTrue, _showNotch, _onShowNotchChanged), - _RadioItem(kShowNotchFalse, _showNotch, _onShowNotchChanged), - - const Divider(), - const _Heading('FAB Position'), - - _RadioItem(kFabEndDocked, _fabLocation, _onFabLocationChanged), - _RadioItem(kFabCenterDocked, _fabLocation, _onFabLocationChanged), - _RadioItem(kFabEndFloat, _fabLocation, _onFabLocationChanged), - _RadioItem(kFabCenterFloat, _fabLocation, _onFabLocationChanged), - - const Divider(), - const _Heading('App bar color'), - - _ColorsItem(kBabColors, _babColor, _onBabColorChanged), - ], - ), - ), - floatingActionButton: _fabShape.value, - floatingActionButtonLocation: _fabLocation.value, - bottomNavigationBar: _DemoBottomAppBar( - color: _babColor, - fabLocation: _fabLocation.value, - shape: _selectNotch(), - ), - ); - } - - NotchedShape _selectNotch() { - if (!_showNotch.value) - return null; - if (_fabShape == kCircularFab) - return const CircularNotchedRectangle(); - if (_fabShape == kDiamondFab) - return const _DiamondNotchedRectangle(); - return null; - } -} - -class _ChoiceValue { - const _ChoiceValue({ this.value, this.title, this.label }); - - final T value; - final String title; - final String label; // For the Semantics widget that contains title - - @override - String toString() => '$runtimeType("$title")'; -} - -class _RadioItem extends StatelessWidget { - const _RadioItem(this.value, this.groupValue, this.onChanged); - - final _ChoiceValue value; - final _ChoiceValue groupValue; - final ValueChanged<_ChoiceValue> onChanged; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Container( - height: 56.0, - padding: const EdgeInsetsDirectional.only(start: 16.0), - alignment: AlignmentDirectional.centerStart, - child: MergeSemantics( - child: Row( - children: [ - Radio<_ChoiceValue>( - value: value, - groupValue: groupValue, - onChanged: onChanged, - ), - Expanded( - child: Semantics( - container: true, - button: true, - label: value.label, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - onChanged(value); - }, - child: Text( - value.title, - style: theme.textTheme.subhead, - ), - ), - ), - ), - ], - ), - ), - ); - } -} - -class _NamedColor { - const _NamedColor(this.color, this.name); - - final Color color; - final String name; -} - -class _ColorsItem extends StatelessWidget { - const _ColorsItem(this.colors, this.selectedColor, this.onChanged); - - final List<_NamedColor> colors; - final Color selectedColor; - final ValueChanged onChanged; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: colors.map((_NamedColor namedColor) { - return RawMaterialButton( - onPressed: () { - onChanged(namedColor.color); - }, - constraints: const BoxConstraints.tightFor( - width: 32.0, - height: 32.0, - ), - fillColor: namedColor.color, - shape: CircleBorder( - side: BorderSide( - color: namedColor.color == selectedColor ? Colors.black : const Color(0xFFD5D7DA), - width: 2.0, - ), - ), - child: Semantics( - value: namedColor.name, - selected: namedColor.color == selectedColor, - ), - ); - }).toList(), - ); - } -} - -class _Heading extends StatelessWidget { - const _Heading(this.text); - - final String text; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Container( - height: 48.0, - padding: const EdgeInsetsDirectional.only(start: 56.0), - alignment: AlignmentDirectional.centerStart, - child: Text( - text, - style: theme.textTheme.body1.copyWith( - color: theme.primaryColor, - ), - ), - ); - } -} - -class _DemoBottomAppBar extends StatelessWidget { - const _DemoBottomAppBar({ - this.color, - this.fabLocation, - this.shape, - }); - - final Color color; - final FloatingActionButtonLocation fabLocation; - final NotchedShape shape; - - static final List kCenterLocations = [ - FloatingActionButtonLocation.centerDocked, - FloatingActionButtonLocation.centerFloat, - ]; - - @override - Widget build(BuildContext context) { - return BottomAppBar( - color: color, - shape: shape, - child: Row(children: [ - IconButton( - icon: const Icon(Icons.menu, semanticLabel: 'Show bottom sheet'), - onPressed: () { - showModalBottomSheet( - context: context, - builder: (BuildContext context) => const _DemoDrawer(), - ); - }, - ), - if (kCenterLocations.contains(fabLocation)) const Expanded(child: SizedBox()), - IconButton( - icon: const Icon(Icons.search, semanticLabel: 'show search action',), - onPressed: () { - Scaffold.of(context).showSnackBar( - const SnackBar(content: Text('This is a dummy search action.')), - ); - }, - ), - IconButton( - icon: Icon( - Theme.of(context).platform == TargetPlatform.iOS - ? Icons.more_horiz - : Icons.more_vert, - semanticLabel: 'Show menu actions', - ), - onPressed: () { - Scaffold.of(context).showSnackBar( - const SnackBar(content: Text('This is a dummy menu action.')), - ); - }, - ), - ]), - ); - } -} - -// A drawer that pops up from the bottom of the screen. -class _DemoDrawer extends StatelessWidget { - const _DemoDrawer(); - - @override - Widget build(BuildContext context) { - return Drawer( - child: Column( - children: const [ - ListTile( - leading: Icon(Icons.search), - title: Text('Search'), - ), - ListTile( - leading: Icon(Icons.threed_rotation), - title: Text('3D'), - ), - ], - ), - ); - } -} - -// A diamond-shaped floating action button. -class _DiamondFab extends StatelessWidget { - const _DiamondFab({ - this.child, - this.onPressed, - }); - - final Widget child; - final VoidCallback onPressed; - - @override - Widget build(BuildContext context) { - return Material( - shape: const _DiamondBorder(), - color: Colors.orange, - child: InkWell( - onTap: onPressed, - child: Container( - width: 56.0, - height: 56.0, - child: IconTheme.merge( - data: IconThemeData(color: Theme.of(context).accentIconTheme.color), - child: child, - ), - ), - ), - elevation: 6.0, - ); - } -} - -class _DiamondNotchedRectangle implements NotchedShape { - const _DiamondNotchedRectangle(); - - @override - Path getOuterPath(Rect host, Rect guest) { - if (!host.overlaps(guest)) - return Path()..addRect(host); - assert(guest.width > 0.0); - - final Rect intersection = guest.intersect(host); - // We are computing a "V" shaped notch, as in this diagram: - // -----\**** /----- - // \ / - // \ / - // \ / - // - // "-" marks the top edge of the bottom app bar. - // "\" and "/" marks the notch outline - // - // notchToCenter is the horizontal distance between the guest's center and - // the host's top edge where the notch starts (marked with "*"). - // We compute notchToCenter by similar triangles: - final double notchToCenter = - intersection.height * (guest.height / 2.0) - / (guest.width / 2.0); - - return Path() - ..moveTo(host.left, host.top) - ..lineTo(guest.center.dx - notchToCenter, host.top) - ..lineTo(guest.left + guest.width / 2.0, guest.bottom) - ..lineTo(guest.center.dx + notchToCenter, host.top) - ..lineTo(host.right, host.top) - ..lineTo(host.right, host.bottom) - ..lineTo(host.left, host.bottom) - ..close(); - } -} - -class _DiamondBorder extends ShapeBorder { - const _DiamondBorder(); - - @override - EdgeInsetsGeometry get dimensions { - return const EdgeInsets.only(); - } - - @override - Path getInnerPath(Rect rect, { TextDirection textDirection }) { - return getOuterPath(rect, textDirection: textDirection); - } - - @override - Path getOuterPath(Rect rect, { TextDirection textDirection }) { - return Path() - ..moveTo(rect.left + rect.width / 2.0, rect.top) - ..lineTo(rect.right, rect.top + rect.height / 2.0) - ..lineTo(rect.left + rect.width / 2.0, rect.bottom) - ..lineTo(rect.left, rect.top + rect.height / 2.0) - ..close(); - } - - @override - void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) { } - - // This border doesn't support scaling. - @override - ShapeBorder scale(double t) { - return null; - } -} diff --git a/web/gallery/lib/demo/material/bottom_navigation_demo.dart b/web/gallery/lib/demo/material/bottom_navigation_demo.dart deleted file mode 100644 index b94a402c6..000000000 --- a/web/gallery/lib/demo/material/bottom_navigation_demo.dart +++ /dev/null @@ -1,230 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -class NavigationIconView { - NavigationIconView({ - Widget icon, - Widget activeIcon, - String title, - Color color, - TickerProvider vsync, - }) : _icon = icon, - _color = color, - _title = title, - item = BottomNavigationBarItem( - icon: icon, - activeIcon: activeIcon, - title: Text(title), - backgroundColor: color, - ), - controller = AnimationController( - duration: kThemeAnimationDuration, - vsync: vsync, - ) { - _animation = controller.drive(CurveTween( - curve: const Interval(0.5, 1.0, curve: Curves.fastOutSlowIn), - )); - } - - final Widget _icon; - final Color _color; - final String _title; - final BottomNavigationBarItem item; - final AnimationController controller; - Animation _animation; - - FadeTransition transition(BottomNavigationBarType type, BuildContext context) { - Color iconColor; - if (type == BottomNavigationBarType.shifting) { - iconColor = _color; - } else { - final ThemeData themeData = Theme.of(context); - iconColor = themeData.brightness == Brightness.light - ? themeData.primaryColor - : themeData.accentColor; - } - - return FadeTransition( - opacity: _animation, - child: SlideTransition( - position: _animation.drive( - Tween( - begin: const Offset(0.0, 0.02), // Slightly down. - end: Offset.zero, - ), - ), - child: IconTheme( - data: IconThemeData( - color: iconColor, - size: 120.0, - ), - child: Semantics( - label: 'Placeholder for $_title tab', - child: _icon, - ), - ), - ), - ); - } -} - -class CustomIcon extends StatelessWidget { - @override - Widget build(BuildContext context) { - final IconThemeData iconTheme = IconTheme.of(context); - return Container( - margin: const EdgeInsets.all(4.0), - width: iconTheme.size - 8.0, - height: iconTheme.size - 8.0, - color: iconTheme.color, - ); - } -} - -class CustomInactiveIcon extends StatelessWidget { - @override - Widget build(BuildContext context) { - final IconThemeData iconTheme = IconTheme.of(context); - return Container( - margin: const EdgeInsets.all(4.0), - width: iconTheme.size - 8.0, - height: iconTheme.size - 8.0, - decoration: BoxDecoration( - border: Border.all(color: iconTheme.color, width: 2.0), - ), - ); - } -} - -class BottomNavigationDemo extends StatefulWidget { - static const String routeName = '/material/bottom_navigation'; - - @override - _BottomNavigationDemoState createState() => _BottomNavigationDemoState(); -} - -class _BottomNavigationDemoState extends State - with TickerProviderStateMixin { - int _currentIndex = 0; - BottomNavigationBarType _type = BottomNavigationBarType.shifting; - List _navigationViews; - - @override - void initState() { - super.initState(); - _navigationViews = [ - NavigationIconView( - icon: const Icon(Icons.access_alarm), - title: 'Alarm', - color: Colors.deepPurple, - vsync: this, - ), - NavigationIconView( - activeIcon: CustomIcon(), - icon: CustomInactiveIcon(), - title: 'Box', - color: Colors.deepOrange, - vsync: this, - ), - NavigationIconView( - activeIcon: const Icon(Icons.cloud), - icon: const Icon(Icons.cloud_queue), - title: 'Cloud', - color: Colors.teal, - vsync: this, - ), - NavigationIconView( - activeIcon: const Icon(Icons.favorite), - icon: const Icon(Icons.favorite_border), - title: 'Favorites', - color: Colors.indigo, - vsync: this, - ), - NavigationIconView( - icon: const Icon(Icons.event_available), - title: 'Event', - color: Colors.pink, - vsync: this, - ), - ]; - - _navigationViews[_currentIndex].controller.value = 1.0; - } - - @override - void dispose() { - for (NavigationIconView view in _navigationViews) - view.controller.dispose(); - super.dispose(); - } - - Widget _buildTransitionsStack() { - final List transitions = [ - for (NavigationIconView view in _navigationViews) view.transition(_type, context), - ]; - - // We want to have the newly animating (fading in) views on top. - transitions.sort((FadeTransition a, FadeTransition b) { - final Animation aAnimation = a.opacity; - final Animation bAnimation = b.opacity; - final double aValue = aAnimation.value; - final double bValue = bAnimation.value; - return aValue.compareTo(bValue); - }); - - return Stack(children: transitions); - } - - @override - Widget build(BuildContext context) { - final BottomNavigationBar botNavBar = BottomNavigationBar( - items: _navigationViews - .map((NavigationIconView navigationView) => navigationView.item) - .toList(), - currentIndex: _currentIndex, - type: _type, - onTap: (int index) { - setState(() { - _navigationViews[_currentIndex].controller.reverse(); - _currentIndex = index; - _navigationViews[_currentIndex].controller.forward(); - }); - }, - ); - - return Scaffold( - appBar: AppBar( - title: const Text('Bottom navigation'), - actions: [ - MaterialDemoDocumentationButton(BottomNavigationDemo.routeName), - PopupMenuButton( - onSelected: (BottomNavigationBarType value) { - setState(() { - _type = value; - }); - }, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: BottomNavigationBarType.fixed, - child: Text('Fixed'), - ), - const PopupMenuItem( - value: BottomNavigationBarType.shifting, - child: Text('Shifting'), - ), - ], - ), - ], - ), - body: Center( - child: _buildTransitionsStack(), - ), - bottomNavigationBar: botNavBar, - ); - } -} diff --git a/web/gallery/lib/demo/material/buttons_demo.dart b/web/gallery/lib/demo/material/buttons_demo.dart deleted file mode 100644 index 7ae4ff405..000000000 --- a/web/gallery/lib/demo/material/buttons_demo.dart +++ /dev/null @@ -1,386 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -const String _raisedText = - 'Raised buttons add dimension to mostly flat layouts. They emphasize ' - 'functions on busy or wide spaces.'; - -const String _raisedCode = 'buttons_raised'; - -const String _flatText = 'A flat button displays an ink splash on press ' - 'but does not lift. Use flat buttons on toolbars, in dialogs and ' - 'inline with padding'; - -const String _flatCode = 'buttons_flat'; - -const String _outlineText = - 'Outline buttons become opaque and elevate when pressed. They are often ' - 'paired with raised buttons to indicate an alternative, secondary action.'; - -const String _outlineCode = 'buttons_outline'; - -const String _dropdownText = - 'A dropdown button displays a menu that\'s used to select a value from a ' - 'small set of values. The button displays the current value and a down ' - 'arrow.'; - -const String _dropdownCode = 'buttons_dropdown'; - -const String _iconText = - 'IconButtons are appropriate for toggle buttons that allow a single choice ' - 'to be selected or deselected, such as adding or removing an item\'s star.'; - -const String _iconCode = 'buttons_icon'; - -const String _actionText = - 'Floating action buttons are used for a promoted action. They are ' - 'distinguished by a circled icon floating above the UI and can have motion ' - 'behaviors that include morphing, launching, and a transferring anchor ' - 'point.'; - -const String _actionCode = 'buttons_action'; - -class ButtonsDemo extends StatefulWidget { - static const String routeName = '/material/buttons'; - - @override - _ButtonsDemoState createState() => _ButtonsDemoState(); -} - -class _ButtonsDemoState extends State { - ShapeBorder _buttonShape; - - @override - Widget build(BuildContext context) { - final ButtonThemeData buttonTheme = ButtonTheme.of(context).copyWith( - shape: _buttonShape - ); - - final List demos = [ - ComponentDemoTabData( - tabName: 'RAISED', - description: _raisedText, - demoWidget: ButtonTheme.fromButtonThemeData( - data: buttonTheme, - child: buildRaisedButton(), - ), - exampleCodeTag: _raisedCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/RaisedButton-class.html', - ), - ComponentDemoTabData( - tabName: 'FLAT', - description: _flatText, - demoWidget: ButtonTheme.fromButtonThemeData( - data: buttonTheme, - child: buildFlatButton(), - ), - exampleCodeTag: _flatCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/FlatButton-class.html', - ), - ComponentDemoTabData( - tabName: 'OUTLINE', - description: _outlineText, - demoWidget: ButtonTheme.fromButtonThemeData( - data: buttonTheme, - child: buildOutlineButton(), - ), - exampleCodeTag: _outlineCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/OutlineButton-class.html', - ), - ComponentDemoTabData( - tabName: 'DROPDOWN', - description: _dropdownText, - demoWidget: buildDropdownButton(), - exampleCodeTag: _dropdownCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/DropdownButton-class.html', - ), - ComponentDemoTabData( - tabName: 'ICON', - description: _iconText, - demoWidget: buildIconButton(), - exampleCodeTag: _iconCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/IconButton-class.html', - ), - ComponentDemoTabData( - tabName: 'ACTION', - description: _actionText, - demoWidget: buildActionButton(), - exampleCodeTag: _actionCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/FloatingActionButton-class.html', - ), - ]; - - return TabbedComponentDemoScaffold( - title: 'Buttons', - demos: demos, - actions: [ - IconButton( - icon: const Icon(Icons.sentiment_very_satisfied, semanticLabel: 'Update shape'), - onPressed: () { - setState(() { - _buttonShape = _buttonShape == null ? const StadiumBorder() : null; - }); - }, - ), - ], - ); - } - - Widget buildRaisedButton() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - RaisedButton( - child: const Text('RAISED BUTTON', semanticsLabel: 'RAISED BUTTON 1'), - onPressed: () { - // Perform some action - }, - ), - const RaisedButton( - child: Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 1'), - onPressed: null, - ), - ], - ), - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - RaisedButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('RAISED BUTTON', semanticsLabel: 'RAISED BUTTON 2'), - onPressed: () { - // Perform some action - }, - ), - RaisedButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 2'), - onPressed: null, - ), - ], - ), - ], - ), - ); - } - - Widget buildFlatButton() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - FlatButton( - child: const Text('FLAT BUTTON', semanticsLabel: 'FLAT BUTTON 1'), - onPressed: () { - // Perform some action - }, - ), - const FlatButton( - child: Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 3',), - onPressed: null, - ), - ], - ), - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - FlatButton.icon( - icon: const Icon(Icons.add_circle_outline, size: 18.0), - label: const Text('FLAT BUTTON', semanticsLabel: 'FLAT BUTTON 2'), - onPressed: () { - // Perform some action - }, - ), - FlatButton.icon( - icon: const Icon(Icons.add_circle_outline, size: 18.0), - label: const Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 4'), - onPressed: null, - ), - ], - ), - ], - ), - ); - } - - Widget buildOutlineButton() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - OutlineButton( - child: const Text('OUTLINE BUTTON', semanticsLabel: 'OUTLINE BUTTON 1'), - onPressed: () { - // Perform some action - }, - ), - const OutlineButton( - child: Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 5'), - onPressed: null, - ), - ], - ), - ButtonBar( - mainAxisSize: MainAxisSize.min, - children: [ - OutlineButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('OUTLINE BUTTON', semanticsLabel: 'OUTLINE BUTTON 2'), - onPressed: () { - // Perform some action - }, - ), - OutlineButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 6'), - onPressed: null, - ), - ], - ), - ], - ), - ); - } - - // https://en.wikipedia.org/wiki/Free_Four - String dropdown1Value = 'Free'; - String dropdown2Value; - String dropdown3Value = 'Four'; - - Widget buildDropdownButton() { - return Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ListTile( - title: const Text('Simple dropdown:'), - trailing: DropdownButton( - value: dropdown1Value, - onChanged: (String newValue) { - setState(() { - dropdown1Value = newValue; - }); - }, - items: ['One', 'Two', 'Free', 'Four'].map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - ), - ), - const SizedBox( - height: 24.0, - ), - ListTile( - title: const Text('Dropdown with a hint:'), - trailing: DropdownButton( - value: dropdown2Value, - hint: const Text('Choose'), - onChanged: (String newValue) { - setState(() { - dropdown2Value = newValue; - }); - }, - items: ['One', 'Two', 'Free', 'Four'].map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - ), - ), - const SizedBox( - height: 24.0, - ), - ListTile( - title: const Text('Scrollable dropdown:'), - trailing: DropdownButton( - value: dropdown3Value, - onChanged: (String newValue) { - setState(() { - dropdown3Value = newValue; - }); - }, - items: [ - 'One', 'Two', 'Free', 'Four', 'Can', 'I', 'Have', 'A', 'Little', - 'Bit', 'More', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', - ] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }) - .toList(), - ), - ), - ], - ), - ); - } - - bool iconButtonToggle = false; - - Widget buildIconButton() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.thumb_up, - semanticLabel: 'Thumbs up', - ), - onPressed: () { - setState(() => iconButtonToggle = !iconButtonToggle); - }, - color: iconButtonToggle ? Theme.of(context).primaryColor : null, - ), - const IconButton( - icon: Icon( - Icons.thumb_up, - semanticLabel: 'Thumbs not up', - ), - onPressed: null, - ), - ] - .map((Widget button) => SizedBox(width: 64.0, height: 64.0, child: button)) - .toList(), - ), - ); - } - - Widget buildActionButton() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: FloatingActionButton( - child: const Icon(Icons.add), - onPressed: () { - // Perform some action - }, - tooltip: 'floating action button', - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/cards_demo.dart b/web/gallery/lib/demo/material/cards_demo.dart deleted file mode 100644 index fe7e29971..000000000 --- a/web/gallery/lib/demo/material/cards_demo.dart +++ /dev/null @@ -1,409 +0,0 @@ -// 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/foundation.dart'; -import 'package:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -enum CardDemoType { - standard, - tappable, - selectable, -} - -class TravelDestination { - const TravelDestination({ - @required this.assetName, - @required this.assetPackage, - @required this.title, - @required this.description, - @required this.city, - @required this.location, - this.type = CardDemoType.standard, - }) : assert(assetName != null), - assert(assetPackage != null), - assert(title != null), - assert(description != null), - assert(city != null), - assert(location != null); - - final String assetName; - final String assetPackage; - final String title; - final String description; - final String city; - final String location; - final CardDemoType type; -} - -const List destinations = [ - TravelDestination( - assetName: 'places/india_thanjavur_market.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Top 10 Cities to Visit in Tamil Nadu', - description: 'Number 10', - city: 'Thanjavur', - location: 'Thanjavur, Tamil Nadu', - ), - TravelDestination( - assetName: 'places/india_chettinad_silk_maker.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Artisans of Southern India', - description: 'Silk Spinners', - city: 'Chettinad', - location: 'Sivaganga, Tamil Nadu', - type: CardDemoType.tappable, - ), - TravelDestination( - assetName: 'places/india_tanjore_thanjavur_temple.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Brihadisvara Temple', - description: 'Temples', - city: 'Thanjavur', - location: 'Thanjavur, Tamil Nadu', - type: CardDemoType.selectable, - ), -]; - -class TravelDestinationItem extends StatelessWidget { - const TravelDestinationItem({ Key key, @required this.destination, this.shape }) - : assert(destination != null), - super(key: key); - - // This height will allow for all the Card's content to fit comfortably within the card. - static const double height = 338.0; - final TravelDestination destination; - final ShapeBorder shape; - - @override - Widget build(BuildContext context) { - return SafeArea( - top: false, - bottom: false, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - const SectionTitle(title: 'Normal'), - SizedBox( - height: height, - child: Card( - // This ensures that the Card's children are clipped correctly. - clipBehavior: Clip.antiAlias, - shape: shape, - child: TravelDestinationContent(destination: destination), - ), - ), - ], - ), - ), - ); - } -} - -class TappableTravelDestinationItem extends StatelessWidget { - const TappableTravelDestinationItem({ Key key, @required this.destination, this.shape }) - : assert(destination != null), - super(key: key); - - // This height will allow for all the Card's content to fit comfortably within the card. - static const double height = 298.0; - final TravelDestination destination; - final ShapeBorder shape; - - @override - Widget build(BuildContext context) { - return SafeArea( - top: false, - bottom: false, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - const SectionTitle(title: 'Tappable'), - SizedBox( - height: height, - child: Card( - // This ensures that the Card's children (including the ink splash) are clipped correctly. - clipBehavior: Clip.antiAlias, - shape: shape, - child: InkWell( - onTap: () { - print('Card was tapped'); - }, - // Generally, material cards use onSurface with 12% opacity for the pressed state. - splashColor: Theme.of(context).colorScheme.onSurface.withOpacity(0.12), - // Generally, material cards do not have a highlight overlay. - highlightColor: Colors.transparent, - child: TravelDestinationContent(destination: destination), - ), - ), - ), - ], - ), - ), - ); - } -} - -class SelectableTravelDestinationItem extends StatefulWidget { - const SelectableTravelDestinationItem({ Key key, @required this.destination, this.shape }) - : assert(destination != null), - super(key: key); - - final TravelDestination destination; - final ShapeBorder shape; - - @override - _SelectableTravelDestinationItemState createState() => _SelectableTravelDestinationItemState(); -} - -class _SelectableTravelDestinationItemState extends State { - - // This height will allow for all the Card's content to fit comfortably within the card. - static const double height = 298.0; - bool _isSelected = false; - - @override - Widget build(BuildContext context) { - final ColorScheme colorScheme = Theme.of(context).colorScheme; - - return SafeArea( - top: false, - bottom: false, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - const SectionTitle(title: 'Selectable (long press)'), - SizedBox( - height: height, - child: Card( - // This ensures that the Card's children (including the ink splash) are clipped correctly. - clipBehavior: Clip.antiAlias, - shape: widget.shape, - child: InkWell( - onLongPress: () { - print('Selectable card state changed'); - setState(() { - _isSelected = !_isSelected; - }); - }, - // Generally, material cards use onSurface with 12% opacity for the pressed state. - splashColor: colorScheme.onSurface.withOpacity(0.12), - // Generally, material cards do not have a highlight overlay. - highlightColor: Colors.transparent, - child: Stack( - children: [ - Container( - color: _isSelected - // Generally, material cards use primary with 8% opacity for the selected state. - // See: https://material.io/design/interaction/states.html#anatomy - ? colorScheme.primary.withOpacity(0.08) - : Colors.transparent, - ), - TravelDestinationContent(destination: widget.destination), - Align( - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.check_circle, - color: _isSelected ? colorScheme.primary : Colors.transparent, - ), - ), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } -} - -class SectionTitle extends StatelessWidget { - const SectionTitle({ - Key key, - this.title, - }) : super(key: key); - - final String title; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 12.0), - child: Align( - alignment: Alignment.centerLeft, - child: Text(title, style: Theme.of(context).textTheme.subhead), - ), - ); - } -} - -class TravelDestinationContent extends StatelessWidget { - const TravelDestinationContent({ Key key, @required this.destination }) - : assert(destination != null), - super(key: key); - - final TravelDestination destination; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextStyle titleStyle = theme.textTheme.headline.copyWith(color: Colors.white); - final TextStyle descriptionStyle = theme.textTheme.subhead; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Photo and title. - SizedBox( - height: 184.0, - child: Stack( - children: [ - Positioned.fill( - // In order to have the ink splash appear above the image, you - // must use Ink.image. This allows the image to be painted as part - // of the Material and display ink effects above it. Using a - // standard Image will obscure the ink splash. - child: Ink.image( - image: AssetImage(destination.assetName, package: destination.assetPackage), - fit: BoxFit.cover, - child: Container(), - ), - ), - Positioned( - bottom: 16.0, - left: 16.0, - right: 16.0, - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text( - destination.title, - style: titleStyle, - ), - ), - ), - ], - ), - ), - // Description and share/explore buttons. - Padding( - padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0), - child: DefaultTextStyle( - softWrap: false, - overflow: TextOverflow.ellipsis, - style: descriptionStyle, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // three line description - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Text( - destination.description, - style: descriptionStyle.copyWith(color: Colors.black54), - ), - ), - Text(destination.city), - Text(destination.location), - ], - ), - ), - ), - if (destination.type == CardDemoType.standard) - // share, explore buttons - ButtonBar( - alignment: MainAxisAlignment.start, - children: [ - FlatButton( - child: Text('SHARE', semanticsLabel: 'Share ${destination.title}'), - textColor: Colors.amber.shade500, - onPressed: () { print('pressed'); }, - ), - FlatButton( - child: Text('EXPLORE', semanticsLabel: 'Explore ${destination.title}'), - textColor: Colors.amber.shade500, - onPressed: () { print('pressed'); }, - ), - ], - ), - ], - ); - } -} - -class CardsDemo extends StatefulWidget { - static const String routeName = '/material/cards'; - - @override - _CardsDemoState createState() => _CardsDemoState(); -} - -class _CardsDemoState extends State { - ShapeBorder _shape; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Cards'), - actions: [ - MaterialDemoDocumentationButton(CardsDemo.routeName), - IconButton( - icon: const Icon( - Icons.sentiment_very_satisfied, - semanticLabel: 'update shape', - ), - onPressed: () { - setState(() { - _shape = _shape != null ? null : const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - bottomLeft: Radius.circular(2.0), - bottomRight: Radius.circular(2.0), - ), - ); - }); - }, - ), - ], - ), - body: Scrollbar( - child: ListView( - padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), - children: destinations.map((TravelDestination destination) { - Widget child; - switch (destination.type) { - case CardDemoType.standard: - child = TravelDestinationItem(destination: destination, shape: _shape); - break; - case CardDemoType.tappable: - child = TappableTravelDestinationItem(destination: destination, shape: _shape); - break; - case CardDemoType.selectable: - child = SelectableTravelDestinationItem(destination: destination, shape: _shape); - break; - } - - return Container( - margin: const EdgeInsets.only(bottom: 8.0), - child: child, - ); - }).toList(), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/chip_demo.dart b/web/gallery/lib/demo/material/chip_demo.dart deleted file mode 100644 index 8528bd1a4..000000000 --- a/web/gallery/lib/demo/material/chip_demo.dart +++ /dev/null @@ -1,331 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const List _defaultMaterials = [ - 'poker', - 'tortilla', - 'fish and', - 'micro', - 'wood', -]; - -const List _defaultActions = [ - 'flake', - 'cut', - 'fragment', - 'splinter', - 'nick', - 'fry', - 'solder', - 'cash in', - 'eat', -]; - -const Map _results = { - 'flake': 'flaking', - 'cut': 'cutting', - 'fragment': 'fragmenting', - 'splinter': 'splintering', - 'nick': 'nicking', - 'fry': 'frying', - 'solder': 'soldering', - 'cash in': 'cashing in', - 'eat': 'eating', -}; - -const List _defaultTools = [ - 'hammer', - 'chisel', - 'fryer', - 'fabricator', - 'customer', -]; - -const Map _avatars = { - 'hammer': 'people/square/ali.png', - 'chisel': 'people/square/sandra.png', - 'fryer': 'people/square/trevor.png', - 'fabricator': 'people/square/stella.png', - 'customer': 'people/square/peter.png', -}; - -const Map> _toolActions = >{ - 'hammer': {'flake', 'fragment', 'splinter'}, - 'chisel': {'flake', 'nick', 'splinter'}, - 'fryer': {'fry'}, - 'fabricator': {'solder'}, - 'customer': {'cash in', 'eat'}, -}; - -const Map> _materialActions = >{ - 'poker': {'cash in'}, - 'tortilla': {'fry', 'eat'}, - 'fish and': {'fry', 'eat'}, - 'micro': {'solder', 'fragment'}, - 'wood': {'flake', 'cut', 'splinter', 'nick'}, -}; - -class _ChipsTile extends StatelessWidget { - const _ChipsTile({ - Key key, - this.label, - this.children, - }) : super(key: key); - - final String label; - final List children; - - // Wraps a list of chips into a ListTile for display as a section in the demo. - @override - Widget build(BuildContext context) { - return Card( - semanticContainer: false, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.only(top: 16.0, bottom: 4.0), - alignment: Alignment.center, - child: Text(label, textAlign: TextAlign.start), - ), - if (children.isNotEmpty) - Wrap( - children: children.map((Widget chip) { - return Padding( - padding: const EdgeInsets.all(2.0), - child: chip, - ); - }).toList(), - ) - else - Semantics( - container: true, - child: Container( - alignment: Alignment.center, - constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0), - padding: const EdgeInsets.all(8.0), - child: Text('None', style: Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic)), - ), - ), - ], - ), - ); - } -} - -class ChipDemo extends StatefulWidget { - static const String routeName = '/material/chip'; - - @override - _ChipDemoState createState() => _ChipDemoState(); -} - -class _ChipDemoState extends State { - _ChipDemoState() { - _reset(); - } - - final Set _materials = {}; - String _selectedMaterial = ''; - String _selectedAction = ''; - final Set _tools = {}; - final Set _selectedTools = {}; - final Set _actions = {}; - bool _showShapeBorder = false; - - // Initialize members with the default data. - void _reset() { - _materials.clear(); - _materials.addAll(_defaultMaterials); - _actions.clear(); - _actions.addAll(_defaultActions); - _tools.clear(); - _tools.addAll(_defaultTools); - _selectedMaterial = ''; - _selectedAction = ''; - _selectedTools.clear(); - } - - void _removeMaterial(String name) { - _materials.remove(name); - if (_selectedMaterial == name) { - _selectedMaterial = ''; - } - } - - void _removeTool(String name) { - _tools.remove(name); - _selectedTools.remove(name); - } - - String _capitalize(String name) { - assert(name != null && name.isNotEmpty); - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - - // This converts a String to a unique color, based on the hash value of the - // String object. It takes the bottom 16 bits of the hash, and uses that to - // pick a hue for an HSV color, and then creates the color (with a preset - // saturation and value). This means that any unique strings will also have - // unique colors, but they'll all be readable, since they have the same - // saturation and value. - Color _nameToColor(String name) { - assert(name.length > 1); - final int hash = name.hashCode & 0xffff; - final double hue = (360.0 * hash / (1 << 15)) % 360.0; - return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); - } - - AssetImage _nameToAvatar(String name) { - assert(_avatars.containsKey(name)); - return AssetImage( - _avatars[name], - package: 'flutter_gallery_assets', - ); - } - - String _createResult() { - if (_selectedAction.isEmpty) { - return ''; - } - return _capitalize(_results[_selectedAction]) + '!'; - } - - @override - Widget build(BuildContext context) { - final List chips = _materials.map((String name) { - return Chip( - key: ValueKey(name), - backgroundColor: _nameToColor(name), - label: Text(_capitalize(name)), - onDeleted: () { - setState(() { - _removeMaterial(name); - }); - }, - ); - }).toList(); - - final List inputChips = _tools.map((String name) { - return InputChip( - key: ValueKey(name), - avatar: CircleAvatar( - backgroundImage: _nameToAvatar(name), - ), - label: Text(_capitalize(name)), - onDeleted: () { - setState(() { - _removeTool(name); - }); - }); - }).toList(); - - final List choiceChips = _materials.map((String name) { - return ChoiceChip( - key: ValueKey(name), - backgroundColor: _nameToColor(name), - label: Text(_capitalize(name)), - selected: _selectedMaterial == name, - onSelected: (bool value) { - setState(() { - _selectedMaterial = value ? name : ''; - }); - }, - ); - }).toList(); - - final List filterChips = _defaultTools.map((String name) { - return FilterChip( - key: ValueKey(name), - label: Text(_capitalize(name)), - selected: _tools.contains(name) && _selectedTools.contains(name), - onSelected: !_tools.contains(name) - ? null - : (bool value) { - setState(() { - if (!value) { - _selectedTools.remove(name); - } else { - _selectedTools.add(name); - } - }); - }, - ); - }).toList(); - - Set allowedActions = {}; - if (_selectedMaterial != null && _selectedMaterial.isNotEmpty) { - for (String tool in _selectedTools) { - allowedActions.addAll(_toolActions[tool]); - } - allowedActions = allowedActions.intersection(_materialActions[_selectedMaterial]); - } - - final List actionChips = allowedActions.map((String name) { - return ActionChip( - label: Text(_capitalize(name)), - onPressed: () { - setState(() { - _selectedAction = name; - }); - }, - ); - }).toList(); - - final ThemeData theme = Theme.of(context); - final List tiles = [ - const SizedBox(height: 8.0, width: 0.0), - _ChipsTile(label: 'Available Materials (Chip)', children: chips), - _ChipsTile(label: 'Available Tools (InputChip)', children: inputChips), - _ChipsTile(label: 'Choose a Material (ChoiceChip)', children: choiceChips), - _ChipsTile(label: 'Choose Tools (FilterChip)', children: filterChips), - _ChipsTile(label: 'Perform Allowed Action (ActionChip)', children: actionChips), - const Divider(), - Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Text( - _createResult(), - style: theme.textTheme.title, - ), - ), - ), - ]; - - return Scaffold( - appBar: AppBar( - title: const Text('Chips'), - actions: [ - MaterialDemoDocumentationButton(ChipDemo.routeName), - IconButton( - onPressed: () { - setState(() { - _showShapeBorder = !_showShapeBorder; - }); - }, - icon: const Icon(Icons.vignette, semanticLabel: 'Update border shape'), - ), - ], - ), - body: ChipTheme( - data: _showShapeBorder - ? theme.chipTheme.copyWith( - shape: BeveledRectangleBorder( - side: const BorderSide(width: 0.66, style: BorderStyle.solid, color: Colors.grey), - borderRadius: BorderRadius.circular(10.0), - )) - : theme.chipTheme, - child: Scrollbar(child: ListView(children: tiles)), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => setState(_reset), - child: const Icon(Icons.refresh, semanticLabel: 'Reset chips'), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/data_table_demo.dart b/web/gallery/lib/demo/material/data_table_demo.dart deleted file mode 100644 index 5611829d5..000000000 --- a/web/gallery/lib/demo/material/data_table_demo.dart +++ /dev/null @@ -1,236 +0,0 @@ -// 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/rendering.dart'; - -import '../../gallery/demo.dart'; - -class Dessert { - Dessert(this.name, this.calories, this.fat, this.carbs, this.protein, this.sodium, this.calcium, this.iron); - final String name; - final int calories; - final double fat; - final int carbs; - final double protein; - final int sodium; - final int calcium; - final int iron; - - bool selected = false; -} - -class DessertDataSource extends DataTableSource { - final List _desserts = [ - Dessert('Frozen yogurt', 159, 6.0, 24, 4.0, 87, 14, 1), - Dessert('Ice cream sandwich', 237, 9.0, 37, 4.3, 129, 8, 1), - Dessert('Eclair', 262, 16.0, 24, 6.0, 337, 6, 7), - Dessert('Cupcake', 305, 3.7, 67, 4.3, 413, 3, 8), - Dessert('Gingerbread', 356, 16.0, 49, 3.9, 327, 7, 16), - Dessert('Jelly bean', 375, 0.0, 94, 0.0, 50, 0, 0), - Dessert('Lollipop', 392, 0.2, 98, 0.0, 38, 0, 2), - Dessert('Honeycomb', 408, 3.2, 87, 6.5, 562, 0, 45), - Dessert('Donut', 452, 25.0, 51, 4.9, 326, 2, 22), - Dessert('KitKat', 518, 26.0, 65, 7.0, 54, 12, 6), - - Dessert('Frozen yogurt with sugar', 168, 6.0, 26, 4.0, 87, 14, 1), - Dessert('Ice cream sandwich with sugar', 246, 9.0, 39, 4.3, 129, 8, 1), - Dessert('Eclair with sugar', 271, 16.0, 26, 6.0, 337, 6, 7), - Dessert('Cupcake with sugar', 314, 3.7, 69, 4.3, 413, 3, 8), - Dessert('Gingerbread with sugar', 345, 16.0, 51, 3.9, 327, 7, 16), - Dessert('Jelly bean with sugar', 364, 0.0, 96, 0.0, 50, 0, 0), - Dessert('Lollipop with sugar', 401, 0.2, 100, 0.0, 38, 0, 2), - Dessert('Honeycomb with sugar', 417, 3.2, 89, 6.5, 562, 0, 45), - Dessert('Donut with sugar', 461, 25.0, 53, 4.9, 326, 2, 22), - Dessert('KitKat with sugar', 527, 26.0, 67, 7.0, 54, 12, 6), - - Dessert('Frozen yogurt with honey', 223, 6.0, 36, 4.0, 87, 14, 1), - Dessert('Ice cream sandwich with honey', 301, 9.0, 49, 4.3, 129, 8, 1), - Dessert('Eclair with honey', 326, 16.0, 36, 6.0, 337, 6, 7), - Dessert('Cupcake with honey', 369, 3.7, 79, 4.3, 413, 3, 8), - Dessert('Gingerbread with honey', 420, 16.0, 61, 3.9, 327, 7, 16), - Dessert('Jelly bean with honey', 439, 0.0, 106, 0.0, 50, 0, 0), - Dessert('Lollipop with honey', 456, 0.2, 110, 0.0, 38, 0, 2), - Dessert('Honeycomb with honey', 472, 3.2, 99, 6.5, 562, 0, 45), - Dessert('Donut with honey', 516, 25.0, 63, 4.9, 326, 2, 22), - Dessert('KitKat with honey', 582, 26.0, 77, 7.0, 54, 12, 6), - - Dessert('Frozen yogurt with milk', 262, 8.4, 36, 12.0, 194, 44, 1), - Dessert('Ice cream sandwich with milk', 339, 11.4, 49, 12.3, 236, 38, 1), - Dessert('Eclair with milk', 365, 18.4, 36, 14.0, 444, 36, 7), - Dessert('Cupcake with milk', 408, 6.1, 79, 12.3, 520, 33, 8), - Dessert('Gingerbread with milk', 459, 18.4, 61, 11.9, 434, 37, 16), - Dessert('Jelly bean with milk', 478, 2.4, 106, 8.0, 157, 30, 0), - Dessert('Lollipop with milk', 495, 2.6, 110, 8.0, 145, 30, 2), - Dessert('Honeycomb with milk', 511, 5.6, 99, 14.5, 669, 30, 45), - Dessert('Donut with milk', 555, 27.4, 63, 12.9, 433, 32, 22), - Dessert('KitKat with milk', 621, 28.4, 77, 15.0, 161, 42, 6), - - Dessert('Coconut slice and frozen yogurt', 318, 21.0, 31, 5.5, 96, 14, 7), - Dessert('Coconut slice and ice cream sandwich', 396, 24.0, 44, 5.8, 138, 8, 7), - Dessert('Coconut slice and eclair', 421, 31.0, 31, 7.5, 346, 6, 13), - Dessert('Coconut slice and cupcake', 464, 18.7, 74, 5.8, 422, 3, 14), - Dessert('Coconut slice and gingerbread', 515, 31.0, 56, 5.4, 316, 7, 22), - Dessert('Coconut slice and jelly bean', 534, 15.0, 101, 1.5, 59, 0, 6), - Dessert('Coconut slice and lollipop', 551, 15.2, 105, 1.5, 47, 0, 8), - Dessert('Coconut slice and honeycomb', 567, 18.2, 94, 8.0, 571, 0, 51), - Dessert('Coconut slice and donut', 611, 40.0, 58, 6.4, 335, 2, 28), - Dessert('Coconut slice and KitKat', 677, 41.0, 72, 8.5, 63, 12, 12), - ]; - - void _sort(Comparable getField(Dessert d), bool ascending) { - _desserts.sort((Dessert a, Dessert b) { - if (!ascending) { - final Dessert c = a; - a = b; - b = c; - } - final Comparable aValue = getField(a); - final Comparable bValue = getField(b); - return Comparable.compare(aValue, bValue); - }); - notifyListeners(); - } - - int _selectedCount = 0; - - @override - DataRow getRow(int index) { - assert(index >= 0); - if (index >= _desserts.length) - return null; - final Dessert dessert = _desserts[index]; - return DataRow.byIndex( - index: index, - selected: dessert.selected, - onSelectChanged: (bool value) { - if (dessert.selected != value) { - _selectedCount += value ? 1 : -1; - assert(_selectedCount >= 0); - dessert.selected = value; - notifyListeners(); - } - }, - cells: [ - DataCell(Text('${dessert.name}')), - DataCell(Text('${dessert.calories}')), - DataCell(Text('${dessert.fat.toStringAsFixed(1)}')), - DataCell(Text('${dessert.carbs}')), - DataCell(Text('${dessert.protein.toStringAsFixed(1)}')), - DataCell(Text('${dessert.sodium}')), - DataCell(Text('${dessert.calcium}%')), - DataCell(Text('${dessert.iron}%')), - ], - ); - } - - @override - int get rowCount => _desserts.length; - - @override - bool get isRowCountApproximate => false; - - @override - int get selectedRowCount => _selectedCount; - - void _selectAll(bool checked) { - for (Dessert dessert in _desserts) - dessert.selected = checked; - _selectedCount = checked ? _desserts.length : 0; - notifyListeners(); - } -} - -class DataTableDemo extends StatefulWidget { - static const String routeName = '/material/data-table'; - - @override - _DataTableDemoState createState() => _DataTableDemoState(); -} - -class _DataTableDemoState extends State { - int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; - int _sortColumnIndex; - bool _sortAscending = true; - final DessertDataSource _dessertsDataSource = DessertDataSource(); - - void _sort(Comparable getField(Dessert d), int columnIndex, bool ascending) { - _dessertsDataSource._sort(getField, ascending); - setState(() { - _sortColumnIndex = columnIndex; - _sortAscending = ascending; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Data tables'), - actions: [ - MaterialDemoDocumentationButton(DataTableDemo.routeName), - ], - ), - body: Scrollbar( - child: ListView( - padding: const EdgeInsets.all(20.0), - children: [ - PaginatedDataTable( - header: const Text('Nutrition'), - rowsPerPage: _rowsPerPage, - onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); }, - sortColumnIndex: _sortColumnIndex, - sortAscending: _sortAscending, - onSelectAll: _dessertsDataSource._selectAll, - columns: [ - DataColumn( - label: const Text('Dessert (100g serving)'), - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.name, columnIndex, ascending), - ), - DataColumn( - label: const Text('Calories'), - tooltip: 'The total amount of food energy in the given serving size.', - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.calories, columnIndex, ascending), - ), - DataColumn( - label: const Text('Fat (g)'), - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.fat, columnIndex, ascending), - ), - DataColumn( - label: const Text('Carbs (g)'), - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.carbs, columnIndex, ascending), - ), - DataColumn( - label: const Text('Protein (g)'), - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.protein, columnIndex, ascending), - ), - DataColumn( - label: const Text('Sodium (mg)'), - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.sodium, columnIndex, ascending), - ), - DataColumn( - label: const Text('Calcium (%)'), - tooltip: 'The amount of calcium as a percentage of the recommended daily amount.', - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.calcium, columnIndex, ascending), - ), - DataColumn( - label: const Text('Iron (%)'), - numeric: true, - onSort: (int columnIndex, bool ascending) => _sort((Dessert d) => d.iron, columnIndex, ascending), - ), - ], - source: _dessertsDataSource, - ), - ], - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/date_and_time_picker_demo.dart b/web/gallery/lib/demo/material/date_and_time_picker_demo.dart deleted file mode 100644 index 9dda962c5..000000000 --- a/web/gallery/lib/demo/material/date_and_time_picker_demo.dart +++ /dev/null @@ -1,219 +0,0 @@ -// 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:async'; - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -import '../../gallery/demo.dart'; - -class _InputDropdown extends StatelessWidget { - const _InputDropdown({ - Key key, - this.child, - this.labelText, - this.valueText, - this.valueStyle, - this.onPressed, - }) : super(key: key); - - final String labelText; - final String valueText; - final TextStyle valueStyle; - final VoidCallback onPressed; - final Widget child; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onPressed, - child: InputDecorator( - decoration: InputDecoration( - labelText: labelText, - ), - baseStyle: valueStyle, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - Text(valueText, style: valueStyle), - Icon(Icons.arrow_drop_down, - color: Theme.of(context).brightness == Brightness.light ? Colors.grey.shade700 : Colors.white70, - ), - ], - ), - ), - ); - } -} - -class _DateTimePicker extends StatelessWidget { - const _DateTimePicker({ - Key key, - this.labelText, - this.selectedDate, - this.selectedTime, - this.selectDate, - this.selectTime, - }) : super(key: key); - - final String labelText; - final DateTime selectedDate; - final TimeOfDay selectedTime; - final ValueChanged selectDate; - final ValueChanged selectTime; - - Future _selectDate(BuildContext context) async { - final DateTime picked = await showDatePicker( - context: context, - initialDate: selectedDate, - firstDate: DateTime(2015, 8), - lastDate: DateTime(2101), - ); - if (picked != null && picked != selectedDate) - selectDate(picked); - } - - Future _selectTime(BuildContext context) async { - final TimeOfDay picked = await showTimePicker( - context: context, - initialTime: selectedTime, - ); - if (picked != null && picked != selectedTime) - selectTime(picked); - } - - @override - Widget build(BuildContext context) { - final TextStyle valueStyle = Theme.of(context).textTheme.title; - return Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - flex: 4, - child: _InputDropdown( - labelText: labelText, - valueText: DateFormat.yMMMd().format(selectedDate), - valueStyle: valueStyle, - onPressed: () { _selectDate(context); }, - ), - ), - const SizedBox(width: 12.0), - Expanded( - flex: 3, - child: _InputDropdown( - valueText: selectedTime.format(context), - valueStyle: valueStyle, - onPressed: () { _selectTime(context); }, - ), - ), - ], - ); - } -} - -class DateAndTimePickerDemo extends StatefulWidget { - static const String routeName = '/material/date-and-time-pickers'; - - @override - _DateAndTimePickerDemoState createState() => _DateAndTimePickerDemoState(); -} - -class _DateAndTimePickerDemoState extends State { - DateTime _fromDate = DateTime.now(); - TimeOfDay _fromTime = const TimeOfDay(hour: 7, minute: 28); - DateTime _toDate = DateTime.now(); - TimeOfDay _toTime = const TimeOfDay(hour: 7, minute: 28); - final List _allActivities = ['hiking', 'swimming', 'boating', 'fishing']; - String _activity = 'fishing'; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Date and time pickers'), - actions: [MaterialDemoDocumentationButton(DateAndTimePickerDemo.routeName)], - ), - body: DropdownButtonHideUnderline( - child: SafeArea( - top: false, - bottom: false, - child: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - TextField( - enabled: true, - decoration: const InputDecoration( - labelText: 'Event name', - border: OutlineInputBorder(), - ), - style: Theme.of(context).textTheme.display1, - ), - TextField( - decoration: const InputDecoration( - labelText: 'Location', - ), - style: Theme.of(context).textTheme.display1.copyWith(fontSize: 20.0), - ), - _DateTimePicker( - labelText: 'From', - selectedDate: _fromDate, - selectedTime: _fromTime, - selectDate: (DateTime date) { - setState(() { - _fromDate = date; - }); - }, - selectTime: (TimeOfDay time) { - setState(() { - _fromTime = time; - }); - }, - ), - _DateTimePicker( - labelText: 'To', - selectedDate: _toDate, - selectedTime: _toTime, - selectDate: (DateTime date) { - setState(() { - _toDate = date; - }); - }, - selectTime: (TimeOfDay time) { - setState(() { - _toTime = time; - }); - }, - ), - const SizedBox(height: 8.0), - InputDecorator( - decoration: const InputDecoration( - labelText: 'Activity', - hintText: 'Choose an activity', - contentPadding: EdgeInsets.zero, - ), - isEmpty: _activity == null, - child: DropdownButton( - value: _activity, - onChanged: (String newValue) { - setState(() { - _activity = newValue; - }); - }, - items: _allActivities.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/dialog_demo.dart b/web/gallery/lib/demo/material/dialog_demo.dart deleted file mode 100644 index 6f4116eb1..000000000 --- a/web/gallery/lib/demo/material/dialog_demo.dart +++ /dev/null @@ -1,214 +0,0 @@ -// 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 '../../gallery/demo.dart'; -import 'full_screen_dialog_demo.dart'; - -enum DialogDemoAction { - cancel, - discard, - disagree, - agree, -} - -const String _alertWithoutTitleText = 'Discard draft?'; - -const String _alertWithTitleText = - 'Let Google help apps determine location. This means sending anonymous location ' - 'data to Google, even when no apps are running.'; - -class DialogDemoItem extends StatelessWidget { - const DialogDemoItem({ Key key, this.icon, this.color, this.text, this.onPressed }) : super(key: key); - - final IconData icon; - final Color color; - final String text; - final VoidCallback onPressed; - - @override - Widget build(BuildContext context) { - return SimpleDialogOption( - onPressed: onPressed, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon(icon, size: 36.0, color: color), - Padding( - padding: const EdgeInsets.only(left: 16.0), - child: Text(text), - ), - ], - ), - ); - } -} - -class DialogDemo extends StatefulWidget { - static const String routeName = '/material/dialog'; - - @override - DialogDemoState createState() => DialogDemoState(); -} - -class DialogDemoState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - TimeOfDay _selectedTime; - - @override - void initState() { - super.initState(); - final DateTime now = DateTime.now(); - _selectedTime = TimeOfDay(hour: now.hour, minute: now.minute); - } - - void showDemoDialog({ BuildContext context, Widget child }) { - showDialog( - context: context, - builder: (BuildContext context) => child, - ) - .then((T value) { // The value passed to Navigator.pop() or null. - if (value != null) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text('You selected: $value'), - )); - } - }); - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); - - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Dialogs'), - actions: [MaterialDemoDocumentationButton(DialogDemo.routeName)], - ), - body: ListView( - padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0), - children: [ - RaisedButton( - child: const Text('ALERT'), - onPressed: () { - showDemoDialog( - context: context, - child: AlertDialog( - content: Text( - _alertWithoutTitleText, - style: dialogTextStyle, - ), - actions: [ - FlatButton( - child: const Text('CANCEL'), - onPressed: () { Navigator.pop(context, DialogDemoAction.cancel); }, - ), - FlatButton( - child: const Text('DISCARD'), - onPressed: () { Navigator.pop(context, DialogDemoAction.discard); }, - ), - ], - ), - ); - }, - ), - RaisedButton( - child: const Text('ALERT WITH TITLE'), - onPressed: () { - showDemoDialog( - context: context, - child: AlertDialog( - title: const Text('Use Google\'s location service?'), - content: Text( - _alertWithTitleText, - style: dialogTextStyle, - ), - actions: [ - FlatButton( - child: const Text('DISAGREE'), - onPressed: () { Navigator.pop(context, DialogDemoAction.disagree); }, - ), - FlatButton( - child: const Text('AGREE'), - onPressed: () { Navigator.pop(context, DialogDemoAction.agree); }, - ), - ], - ), - ); - }, - ), - RaisedButton( - child: const Text('SIMPLE'), - onPressed: () { - showDemoDialog( - context: context, - child: SimpleDialog( - title: const Text('Set backup account'), - children: [ - DialogDemoItem( - icon: Icons.account_circle, - color: theme.primaryColor, - text: 'username@gmail.com', - onPressed: () { Navigator.pop(context, 'username@gmail.com'); }, - ), - DialogDemoItem( - icon: Icons.account_circle, - color: theme.primaryColor, - text: 'user02@gmail.com', - onPressed: () { Navigator.pop(context, 'user02@gmail.com'); }, - ), - DialogDemoItem( - icon: Icons.add_circle, - text: 'add account', - color: theme.disabledColor, - ), - ], - ), - ); - }, - ), - RaisedButton( - child: const Text('CONFIRMATION'), - onPressed: () { - showTimePicker( - context: context, - initialTime: _selectedTime, - ) - .then((TimeOfDay value) { - if (value != null && value != _selectedTime) { - _selectedTime = value; - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text('You selected: ${value.format(context)}'), - )); - } - }); - }, - ), - RaisedButton( - child: const Text('FULLSCREEN'), - onPressed: () { - Navigator.push(context, MaterialPageRoute( - builder: (BuildContext context) => FullScreenDialogDemo(), - fullscreenDialog: true, - )); - }, - ), - ] - // Add a little space between the buttons - .map((Widget button) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: button, - ); - }) - .toList(), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/drawer_demo.dart b/web/gallery/lib/demo/material/drawer_demo.dart deleted file mode 100644 index 08f69d20f..000000000 --- a/web/gallery/lib/demo/material/drawer_demo.dart +++ /dev/null @@ -1,266 +0,0 @@ -// 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/gestures.dart' show DragStartBehavior; - -import '../../gallery/demo.dart'; - -const String _kAsset0 = 'people/square/trevor.png'; -const String _kAsset1 = 'people/square/stella.png'; -const String _kAsset2 = 'people/square/sandra.png'; -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -class DrawerDemo extends StatefulWidget { - static const String routeName = '/material/drawer'; - - @override - _DrawerDemoState createState() => _DrawerDemoState(); -} - -class _DrawerDemoState extends State with TickerProviderStateMixin { - final GlobalKey _scaffoldKey = GlobalKey(); - - static const List _drawerContents = [ - 'A', 'B', 'C', 'D', 'E', - ]; - - static final Animatable _drawerDetailsTween = Tween( - begin: const Offset(0.0, -1.0), - end: Offset.zero, - ).chain(CurveTween( - curve: Curves.fastOutSlowIn, - )); - - AnimationController _controller; - Animation _drawerContentsOpacity; - Animation _drawerDetailsPosition; - bool _showDrawerContents = true; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 200), - ); - _drawerContentsOpacity = CurvedAnimation( - parent: ReverseAnimation(_controller), - curve: Curves.fastOutSlowIn, - ); - _drawerDetailsPosition = _controller.drive(_drawerDetailsTween); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - IconData _backIcon() { - switch (Theme.of(context).platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - return Icons.arrow_back; - case TargetPlatform.iOS: - case TargetPlatform.macOS: - return Icons.arrow_back_ios; - } - assert(false); - return null; - } - - void _showNotImplementedMessage() { - Navigator.pop(context); // Dismiss the drawer. - _scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text("The drawer's items don't do anything"), - )); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - drawerDragStartBehavior: DragStartBehavior.down, - key: _scaffoldKey, - appBar: AppBar( - leading: IconButton( - icon: Icon(_backIcon()), - alignment: Alignment.centerLeft, - tooltip: 'Back', - onPressed: () { - Navigator.pop(context); - }, - ), - title: const Text('Navigation drawer'), - actions: [MaterialDemoDocumentationButton(DrawerDemo.routeName)], - ), - drawer: Drawer( - child: Column( - children: [ - UserAccountsDrawerHeader( - accountName: const Text('Trevor Widget'), - accountEmail: const Text('trevor.widget@example.com'), - currentAccountPicture: const CircleAvatar( - backgroundImage: AssetImage( - _kAsset0, - package: _kGalleryAssetsPackage, - ), - ), - otherAccountsPictures: [ - GestureDetector( - dragStartBehavior: DragStartBehavior.down, - onTap: () { - _onOtherAccountsTap(context); - }, - child: Semantics( - label: 'Switch to Account B', - child: const CircleAvatar( - backgroundImage: AssetImage( - _kAsset1, - package: _kGalleryAssetsPackage, - ), - ), - ), - ), - GestureDetector( - dragStartBehavior: DragStartBehavior.down, - onTap: () { - _onOtherAccountsTap(context); - }, - child: Semantics( - label: 'Switch to Account C', - child: const CircleAvatar( - backgroundImage: AssetImage( - _kAsset2, - package: _kGalleryAssetsPackage, - ), - ), - ), - ), - ], - margin: EdgeInsets.zero, - onDetailsPressed: () { - _showDrawerContents = !_showDrawerContents; - if (_showDrawerContents) - _controller.reverse(); - else - _controller.forward(); - }, - ), - MediaQuery.removePadding( - context: context, - // DrawerHeader consumes top MediaQuery padding. - removeTop: true, - child: Expanded( - child: ListView( - dragStartBehavior: DragStartBehavior.down, - padding: const EdgeInsets.only(top: 8.0), - children: [ - Stack( - children: [ - // The initial contents of the drawer. - FadeTransition( - opacity: _drawerContentsOpacity, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: _drawerContents.map((String id) { - return ListTile( - leading: CircleAvatar(child: Text(id)), - title: Text('Drawer item $id'), - onTap: _showNotImplementedMessage, - ); - }).toList(), - ), - ), - // The drawer's "details" view. - SlideTransition( - position: _drawerDetailsPosition, - child: FadeTransition( - opacity: ReverseAnimation(_drawerContentsOpacity), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ListTile( - leading: const Icon(Icons.add), - title: const Text('Add account'), - onTap: _showNotImplementedMessage, - ), - ListTile( - leading: const Icon(Icons.settings), - title: const Text('Manage accounts'), - onTap: _showNotImplementedMessage, - ), - ], - ), - ), - ), - ], - ), - ], - ), - ), - ), - ], - ), - ), - body: Center( - child: InkWell( - onTap: () { - _scaffoldKey.currentState.openDrawer(); - }, - child: Semantics( - button: true, - label: 'Open drawer', - excludeSemantics: true, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 100.0, - height: 100.0, - decoration: const BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: AssetImage( - _kAsset0, - package: _kGalleryAssetsPackage, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text('Tap here to open the drawer', - style: Theme.of(context).textTheme.subhead, - ), - ), - ], - ), - ), - ), - ), - ); - } - - void _onOtherAccountsTap(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Account switching not implemented.'), - actions: [ - FlatButton( - child: const Text('OK'), - onPressed: () { - Navigator.pop(context); - }, - ), - ], - ); - }, - ); - } -} diff --git a/web/gallery/lib/demo/material/elevation_demo.dart b/web/gallery/lib/demo/material/elevation_demo.dart deleted file mode 100644 index ec44b389e..000000000 --- a/web/gallery/lib/demo/material/elevation_demo.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2014 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 '../../gallery/demo.dart'; - -class ElevationDemo extends StatefulWidget { - static const String routeName = '/material/elevation'; - - @override - State createState() => _ElevationDemoState(); -} - -class _ElevationDemoState extends State { - bool _showElevation = true; - - List buildCards() { - const List elevations = [ - 0.0, - 1.0, - 2.0, - 3.0, - 4.0, - 5.0, - 8.0, - 16.0, - 24.0, - ]; - - return elevations.map((double elevation) { - return Center( - child: Card( - margin: const EdgeInsets.all(20.0), - elevation: _showElevation ? elevation : 0.0, - child: SizedBox( - height: 100.0, - width: 100.0, - child: Center( - child: Text('${elevation.toStringAsFixed(0)} pt'), - ), - ), - ), - ); - }).toList(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Elevation'), - actions: [ - MaterialDemoDocumentationButton(ElevationDemo.routeName), - IconButton( - icon: const Icon(Icons.sentiment_very_satisfied), - onPressed: () { - setState(() => _showElevation = !_showElevation); - }, - ), - ], - ), - body: Scrollbar(child: ListView(children: buildCards())), - ); - } -} diff --git a/web/gallery/lib/demo/material/expansion_panels_demo.dart b/web/gallery/lib/demo/material/expansion_panels_demo.dart deleted file mode 100644 index c65438f55..000000000 --- a/web/gallery/lib/demo/material/expansion_panels_demo.dart +++ /dev/null @@ -1,362 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -@visibleForTesting -enum Location { - Barbados, - Bahamas, - Bermuda -} - -typedef DemoItemBodyBuilder = Widget Function(DemoItem item); -typedef ValueToString = String Function(T value); - -class DualHeaderWithHint extends StatelessWidget { - const DualHeaderWithHint({ - this.name, - this.value, - this.hint, - this.showHint, - }); - - final String name; - final String value; - final String hint; - final bool showHint; - - Widget _crossFade(Widget first, Widget second, bool isExpanded) { - return AnimatedCrossFade( - firstChild: first, - secondChild: second, - firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn), - secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn), - sizeCurve: Curves.fastOutSlowIn, - crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, - duration: const Duration(milliseconds: 200), - ); - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextTheme textTheme = theme.textTheme; - - return Row( - children: [ - Expanded( - flex: 2, - child: Container( - margin: const EdgeInsets.only(left: 24.0), - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text( - name, - style: textTheme.body1.copyWith(fontSize: 15.0), - ), - ), - ), - ), - Expanded( - flex: 3, - child: Container( - margin: const EdgeInsets.only(left: 24.0), - child: _crossFade( - Text(value, style: textTheme.caption.copyWith(fontSize: 15.0)), - Text(hint, style: textTheme.caption.copyWith(fontSize: 15.0)), - showHint, - ), - ), - ), - ], - ); - } -} - -class CollapsibleBody extends StatelessWidget { - const CollapsibleBody({ - this.margin = EdgeInsets.zero, - this.child, - this.onSave, - this.onCancel, - }); - - final EdgeInsets margin; - final Widget child; - final VoidCallback onSave; - final VoidCallback onCancel; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextTheme textTheme = theme.textTheme; - - return Column( - children: [ - Container( - margin: const EdgeInsets.only( - left: 24.0, - right: 24.0, - bottom: 24.0, - ) - margin, - child: Center( - child: DefaultTextStyle( - style: textTheme.caption.copyWith(fontSize: 15.0), - child: child, - ), - ), - ), - const Divider(height: 1.0), - Container( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Container( - margin: const EdgeInsets.only(right: 8.0), - child: FlatButton( - onPressed: onCancel, - child: const Text('CANCEL', style: TextStyle( - color: Colors.black54, - fontSize: 15.0, - fontWeight: FontWeight.w500, - )), - ), - ), - Container( - margin: const EdgeInsets.only(right: 8.0), - child: FlatButton( - onPressed: onSave, - textTheme: ButtonTextTheme.accent, - child: const Text('SAVE'), - ), - ), - ], - ), - ), - ], - ); - } -} - -class DemoItem { - DemoItem({ - this.name, - this.value, - this.hint, - this.builder, - this.valueToString, - }) : textController = TextEditingController(text: valueToString(value)); - - final String name; - final String hint; - final TextEditingController textController; - final DemoItemBodyBuilder builder; - final ValueToString valueToString; - T value; - bool isExpanded = false; - - ExpansionPanelHeaderBuilder get headerBuilder { - return (BuildContext context, bool isExpanded) { - return DualHeaderWithHint( - name: name, - value: valueToString(value), - hint: hint, - showHint: isExpanded, - ); - }; - } - - Widget build() => builder(this); -} - -class ExpansionPanelsDemo extends StatefulWidget { - static const String routeName = '/material/expansion_panels'; - - @override - _ExpansionPanelsDemoState createState() => _ExpansionPanelsDemoState(); -} - -class _ExpansionPanelsDemoState extends State { - List> _demoItems; - - @override - void initState() { - super.initState(); - - _demoItems = >[ - DemoItem( - name: 'Trip', - value: 'Caribbean cruise', - hint: 'Change trip name', - valueToString: (String value) => value, - builder: (DemoItem item) { - void close() { - setState(() { - item.isExpanded = false; - }); - } - - return Form( - child: Builder( - builder: (BuildContext context) { - return CollapsibleBody( - margin: const EdgeInsets.symmetric(horizontal: 16.0), - onSave: () { Form.of(context).save(); close(); }, - onCancel: () { Form.of(context).reset(); close(); }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: TextFormField( - controller: item.textController, - decoration: InputDecoration( - hintText: item.hint, - labelText: item.name, - ), - onSaved: (String value) { item.value = value; }, - ), - ), - ); - }, - ), - ); - }, - ), - DemoItem( - name: 'Location', - value: Location.Bahamas, - hint: 'Select location', - valueToString: (Location location) => location.toString().split('.')[1], - builder: (DemoItem item) { - void close() { - setState(() { - item.isExpanded = false; - }); - } - return Form( - child: Builder( - builder: (BuildContext context) { - return CollapsibleBody( - onSave: () { Form.of(context).save(); close(); }, - onCancel: () { Form.of(context).reset(); close(); }, - child: FormField( - initialValue: item.value, - onSaved: (Location result) { item.value = result; }, - builder: (FormFieldState field) { - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RadioListTile( - value: Location.Bahamas, - title: const Text('Bahamas'), - groupValue: field.value, - onChanged: field.didChange, - ), - RadioListTile( - value: Location.Barbados, - title: const Text('Barbados'), - groupValue: field.value, - onChanged: field.didChange, - ), - RadioListTile( - value: Location.Bermuda, - title: const Text('Bermuda'), - groupValue: field.value, - onChanged: field.didChange, - ), - ], - ); - }, - ), - ); - } - ), - ); - }, - ), - DemoItem( - name: 'Sun', - value: 80.0, - hint: 'Select sun level', - valueToString: (double amount) => '${amount.round()}', - builder: (DemoItem item) { - void close() { - setState(() { - item.isExpanded = false; - }); - } - - return Form( - child: Builder( - builder: (BuildContext context) { - return CollapsibleBody( - onSave: () { Form.of(context).save(); close(); }, - onCancel: () { Form.of(context).reset(); close(); }, - child: FormField( - initialValue: item.value, - onSaved: (double value) { item.value = value; }, - builder: (FormFieldState field) { - return Container( - // Allow room for the value indicator. - padding: const EdgeInsets.only(top: 44.0), - child: Slider( - min: 0.0, - max: 100.0, - divisions: 5, - activeColor: Colors.orange[100 + (field.value * 5.0).round()], - label: '${field.value.round()}', - value: field.value, - onChanged: field.didChange, - ), - ); - }, - ), - ); - } - ), - ); - }, - ), - ]; - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Expansion panels'), - actions: [ - MaterialDemoDocumentationButton(ExpansionPanelsDemo.routeName), - ], - ), - body: SingleChildScrollView( - child: SafeArea( - top: false, - bottom: false, - child: Container( - margin: const EdgeInsets.all(24.0), - child: ExpansionPanelList( - expansionCallback: (int index, bool isExpanded) { - setState(() { - _demoItems[index].isExpanded = !isExpanded; - }); - }, - children: _demoItems.map((DemoItem item) { - return ExpansionPanel( - isExpanded: item.isExpanded, - headerBuilder: item.headerBuilder, - body: item.build(), - ); - }).toList(), - ), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/expansion_tile_list_demo.dart b/web/gallery/lib/demo/material/expansion_tile_list_demo.dart deleted file mode 100644 index 10ad11f2f..000000000 --- a/web/gallery/lib/demo/material/expansion_tile_list_demo.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -class ExpansionTileListDemo extends StatelessWidget { - static const String routeName = '/material/expansion-tile-list'; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Expand/collapse list control'), - actions: [MaterialDemoDocumentationButton(routeName)], - ), - body: Scrollbar( - child: ListView( - children: [ - const ListTile(title: Text('Top')), - ExpansionTile( - title: const Text('Sublist'), - backgroundColor: Theme.of(context).accentColor.withOpacity(0.025), - children: const [ - ListTile(title: Text('One')), - ListTile(title: Text('Two')), - // https://en.wikipedia.org/wiki/Free_Four - ListTile(title: Text('Free')), - ListTile(title: Text('Four')), - ], - ), - const ListTile(title: Text('Bottom')), - ], - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/full_screen_dialog_demo.dart b/web/gallery/lib/demo/material/full_screen_dialog_demo.dart deleted file mode 100644 index ab4a29592..000000000 --- a/web/gallery/lib/demo/material/full_screen_dialog_demo.dart +++ /dev/null @@ -1,268 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -// This demo is based on -// https://material.io/design/components/dialogs.html#full-screen-dialog - -enum DismissDialogAction { - cancel, - discard, - save, -} - -class DateTimeItem extends StatelessWidget { - DateTimeItem({ Key key, DateTime dateTime, @required this.onChanged }) - : assert(onChanged != null), - date = DateTime(dateTime.year, dateTime.month, dateTime.day), - time = TimeOfDay(hour: dateTime.hour, minute: dateTime.minute), - super(key: key); - - final DateTime date; - final TimeOfDay time; - final ValueChanged onChanged; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - - return DefaultTextStyle( - style: theme.textTheme.subhead, - child: Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: theme.dividerColor)) - ), - child: InkWell( - onTap: () { - showDatePicker( - context: context, - initialDate: date, - firstDate: date.subtract(const Duration(days: 30)), - lastDate: date.add(const Duration(days: 30)), - ) - .then((DateTime value) { - if (value != null) - onChanged(DateTime(value.year, value.month, value.day, time.hour, time.minute)); - }); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(DateFormat('EEE, MMM d yyyy').format(date)), - const Icon(Icons.arrow_drop_down, color: Colors.black54), - ], - ), - ), - ), - ), - Container( - margin: const EdgeInsets.only(left: 8.0), - padding: const EdgeInsets.symmetric(vertical: 8.0), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: theme.dividerColor)) - ), - child: InkWell( - onTap: () { - showTimePicker( - context: context, - initialTime: time, - ) - .then((TimeOfDay value) { - if (value != null) - onChanged(DateTime(date.year, date.month, date.day, value.hour, value.minute)); - }); - }, - child: Row( - children: [ - Text('${time.format(context)}'), - const Icon(Icons.arrow_drop_down, color: Colors.black54), - ], - ), - ), - ), - ], - ), - ); - } -} - -class FullScreenDialogDemo extends StatefulWidget { - @override - FullScreenDialogDemoState createState() => FullScreenDialogDemoState(); -} - -class FullScreenDialogDemoState extends State { - DateTime _fromDateTime = DateTime.now(); - DateTime _toDateTime = DateTime.now(); - bool _allDayValue = false; - bool _saveNeeded = false; - bool _hasLocation = false; - bool _hasName = false; - String _eventName; - - Future _onWillPop() async { - _saveNeeded = _hasLocation || _hasName || _saveNeeded; - if (!_saveNeeded) - return true; - - final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); - - return await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: Text( - 'Discard new event?', - style: dialogTextStyle, - ), - actions: [ - FlatButton( - child: const Text('CANCEL'), - onPressed: () { - Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page. - }, - ), - FlatButton( - child: const Text('DISCARD'), - onPressed: () { - Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again. - }, - ), - ], - ); - }, - ) ?? false; - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - - return Scaffold( - appBar: AppBar( - title: Text(_hasName ? _eventName : 'Event Name TBD'), - actions: [ - FlatButton( - child: Text('SAVE', style: theme.textTheme.body1.copyWith(color: Colors.white)), - onPressed: () { - Navigator.pop(context, DismissDialogAction.save); - }, - ), - ], - ), - body: Form( - onWillPop: _onWillPop, - child: Scrollbar( - child: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - alignment: Alignment.bottomLeft, - child: TextField( - decoration: const InputDecoration( - labelText: 'Event name', - filled: true, - ), - style: theme.textTheme.headline, - onChanged: (String value) { - setState(() { - _hasName = value.isNotEmpty; - if (_hasName) { - _eventName = value; - } - }); - }, - ), - ), - Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - alignment: Alignment.bottomLeft, - child: TextField( - decoration: const InputDecoration( - labelText: 'Location', - hintText: 'Where is the event?', - filled: true, - ), - onChanged: (String value) { - setState(() { - _hasLocation = value.isNotEmpty; - }); - }, - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('From', style: theme.textTheme.caption), - DateTimeItem( - dateTime: _fromDateTime, - onChanged: (DateTime value) { - setState(() { - _fromDateTime = value; - _saveNeeded = true; - }); - }, - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('To', style: theme.textTheme.caption), - DateTimeItem( - dateTime: _toDateTime, - onChanged: (DateTime value) { - setState(() { - _toDateTime = value; - _saveNeeded = true; - }); - }, - ), - const Text('All-day'), - ], - ), - Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: theme.dividerColor)) - ), - child: Row( - children: [ - Checkbox( - value: _allDayValue, - onChanged: (bool value) { - setState(() { - _allDayValue = value; - _saveNeeded = true; - }); - }, - ), - const Text('All-day'), - ], - ), - ), - ] - .map((Widget child) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - height: 96.0, - child: child, - ); - }) - .toList(), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/grid_list_demo.dart b/web/gallery/lib/demo/material/grid_list_demo.dart deleted file mode 100644 index 2267606cd..000000000 --- a/web/gallery/lib/demo/material/grid_list_demo.dart +++ /dev/null @@ -1,395 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -enum GridDemoTileStyle { - imageOnly, - oneLine, - twoLine -} - -typedef BannerTapCallback = void Function(Photo photo); - -const double _kMinFlingVelocity = 800.0; -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -class Photo { - Photo({ - this.assetName, - this.assetPackage, - this.title, - this.caption, - this.isFavorite = false, - }); - - final String assetName; - final String assetPackage; - final String title; - final String caption; - - bool isFavorite; - String get tag => assetName; // Assuming that all asset names are unique. - - bool get isValid => assetName != null && title != null && caption != null && isFavorite != null; -} - -class GridPhotoViewer extends StatefulWidget { - const GridPhotoViewer({ Key key, this.photo }) : super(key: key); - - final Photo photo; - - @override - _GridPhotoViewerState createState() => _GridPhotoViewerState(); -} - -class _GridTitleText extends StatelessWidget { - const _GridTitleText(this.text); - - final String text; - - @override - Widget build(BuildContext context) { - return FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text(text), - ); - } -} - -class _GridPhotoViewerState extends State with SingleTickerProviderStateMixin { - AnimationController _controller; - Animation _flingAnimation; - Offset _offset = Offset.zero; - double _scale = 1.0; - Offset _normalizedOffset; - double _previousScale; - - @override - void initState() { - super.initState(); - _controller = AnimationController(vsync: this) - ..addListener(_handleFlingAnimation); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - // The maximum offset value is 0,0. If the size of this renderer's box is w,h - // then the minimum offset value is w - _scale * w, h - _scale * h. - Offset _clampOffset(Offset offset) { - final Size size = context.size; - final Offset minOffset = Offset(size.width, size.height) * (1.0 - _scale); - return Offset(offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0)); - } - - void _handleFlingAnimation() { - setState(() { - _offset = _flingAnimation.value; - }); - } - - void _handleOnScaleStart(ScaleStartDetails details) { - setState(() { - _previousScale = _scale; - _normalizedOffset = (details.focalPoint - _offset) / _scale; - // The fling animation stops if an input gesture starts. - _controller.stop(); - }); - } - - void _handleOnScaleUpdate(ScaleUpdateDetails details) { - setState(() { - _scale = (_previousScale * details.scale).clamp(1.0, 4.0); - // Ensure that image location under the focal point stays in the same place despite scaling. - _offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale); - }); - } - - void _handleOnScaleEnd(ScaleEndDetails details) { - final double magnitude = details.velocity.pixelsPerSecond.distance; - if (magnitude < _kMinFlingVelocity) - return; - final Offset direction = details.velocity.pixelsPerSecond / magnitude; - final double distance = (Offset.zero & context.size).shortestSide; - _flingAnimation = _controller.drive(Tween( - begin: _offset, - end: _clampOffset(_offset + direction * distance), - )); - _controller - ..value = 0.0 - ..fling(velocity: magnitude / 1000.0); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onScaleStart: _handleOnScaleStart, - onScaleUpdate: _handleOnScaleUpdate, - onScaleEnd: _handleOnScaleEnd, - child: ClipRect( - child: Transform( - transform: Matrix4.identity() - ..translate(_offset.dx, _offset.dy) - ..scale(_scale), - child: Image.asset( - widget.photo.assetName, - package: widget.photo.assetPackage, - fit: BoxFit.cover, - ), - ), - ), - ); - } -} - -class GridDemoPhotoItem extends StatelessWidget { - GridDemoPhotoItem({ - Key key, - @required this.photo, - @required this.tileStyle, - @required this.onBannerTap, - }) : assert(photo != null && photo.isValid), - assert(tileStyle != null), - assert(onBannerTap != null), - super(key: key); - - final Photo photo; - final GridDemoTileStyle tileStyle; - final BannerTapCallback onBannerTap; // User taps on the photo's header or footer. - - void showPhoto(BuildContext context) { - Navigator.push(context, MaterialPageRoute( - builder: (BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(photo.title), - ), - body: SizedBox.expand( - child: Hero( - tag: photo.tag, - child: GridPhotoViewer(photo: photo), - ), - ), - ); - } - )); - } - - @override - Widget build(BuildContext context) { - final Widget image = GestureDetector( - onTap: () { showPhoto(context); }, - child: Hero( - key: Key(photo.assetName), - tag: photo.tag, - child: Image.asset( - photo.assetName, - package: photo.assetPackage, - fit: BoxFit.cover, - ), - ), - ); - - final IconData icon = photo.isFavorite ? Icons.star : Icons.star_border; - - switch (tileStyle) { - case GridDemoTileStyle.imageOnly: - return image; - - case GridDemoTileStyle.oneLine: - return GridTile( - header: GestureDetector( - onTap: () { onBannerTap(photo); }, - child: GridTileBar( - title: _GridTitleText(photo.title), - backgroundColor: Colors.black45, - leading: Icon( - icon, - color: Colors.white, - ), - ), - ), - child: image, - ); - - case GridDemoTileStyle.twoLine: - return GridTile( - footer: GestureDetector( - onTap: () { onBannerTap(photo); }, - child: GridTileBar( - backgroundColor: Colors.black45, - title: _GridTitleText(photo.title), - subtitle: _GridTitleText(photo.caption), - trailing: Icon( - icon, - color: Colors.white, - ), - ), - ), - child: image, - ); - } - assert(tileStyle != null); - return null; - } -} - -class GridListDemo extends StatefulWidget { - const GridListDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/grid-list'; - - @override - GridListDemoState createState() => GridListDemoState(); -} - -class GridListDemoState extends State { - GridDemoTileStyle _tileStyle = GridDemoTileStyle.twoLine; - - List photos = [ - Photo( - assetName: 'places/india_chennai_flower_market.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Chennai', - caption: 'Flower Market', - ), - Photo( - assetName: 'places/india_tanjore_bronze_works.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Tanjore', - caption: 'Bronze Works', - ), - Photo( - assetName: 'places/india_tanjore_market_merchant.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Tanjore', - caption: 'Market', - ), - Photo( - assetName: 'places/india_tanjore_thanjavur_temple.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Tanjore', - caption: 'Thanjavur Temple', - ), - Photo( - assetName: 'places/india_tanjore_thanjavur_temple_carvings.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Tanjore', - caption: 'Thanjavur Temple', - ), - Photo( - assetName: 'places/india_pondicherry_salt_farm.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Pondicherry', - caption: 'Salt Farm', - ), - Photo( - assetName: 'places/india_chennai_highway.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Chennai', - caption: 'Scooters', - ), - Photo( - assetName: 'places/india_chettinad_silk_maker.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Chettinad', - caption: 'Silk Maker', - ), - Photo( - assetName: 'places/india_chettinad_produce.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Chettinad', - caption: 'Lunch Prep', - ), - Photo( - assetName: 'places/india_tanjore_market_technology.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Tanjore', - caption: 'Market', - ), - Photo( - assetName: 'places/india_pondicherry_beach.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Pondicherry', - caption: 'Beach', - ), - Photo( - assetName: 'places/india_pondicherry_fisherman.png', - assetPackage: _kGalleryAssetsPackage, - title: 'Pondicherry', - caption: 'Fisherman', - ), - ]; - - void changeTileStyle(GridDemoTileStyle value) { - setState(() { - _tileStyle = value; - }); - } - - @override - Widget build(BuildContext context) { - final Orientation orientation = MediaQuery.of(context).orientation; - return Scaffold( - appBar: AppBar( - title: const Text('Grid list'), - actions: [ - MaterialDemoDocumentationButton(GridListDemo.routeName), - PopupMenuButton( - onSelected: changeTileStyle, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: GridDemoTileStyle.imageOnly, - child: Text('Image only'), - ), - const PopupMenuItem( - value: GridDemoTileStyle.oneLine, - child: Text('One line'), - ), - const PopupMenuItem( - value: GridDemoTileStyle.twoLine, - child: Text('Two line'), - ), - ], - ), - ], - ), - body: Column( - children: [ - Expanded( - child: SafeArea( - top: false, - bottom: false, - child: GridView.count( - crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3, - mainAxisSpacing: 4.0, - crossAxisSpacing: 4.0, - padding: const EdgeInsets.all(4.0), - childAspectRatio: (orientation == Orientation.portrait) ? 1.0 : 1.3, - children: photos.map((Photo photo) { - return GridDemoPhotoItem( - photo: photo, - tileStyle: _tileStyle, - onBannerTap: (Photo photo) { - setState(() { - photo.isFavorite = !photo.isFavorite; - }); - }, - ); - }).toList(), - ), - ), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/icons_demo.dart b/web/gallery/lib/demo/material/icons_demo.dart deleted file mode 100644 index b35a290a7..000000000 --- a/web/gallery/lib/demo/material/icons_demo.dart +++ /dev/null @@ -1,138 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -class IconsDemo extends StatefulWidget { - static const String routeName = '/material/icons'; - - @override - IconsDemoState createState() => IconsDemoState(); -} - -class IconsDemoState extends State { - static final List iconColors = [ - Colors.red, - Colors.pink, - Colors.purple, - Colors.deepPurple, - Colors.indigo, - Colors.blue, - Colors.lightBlue, - Colors.cyan, - Colors.teal, - Colors.green, - Colors.lightGreen, - Colors.lime, - Colors.yellow, - Colors.amber, - Colors.orange, - Colors.deepOrange, - Colors.brown, - Colors.grey, - Colors.blueGrey, - ]; - - int iconColorIndex = 8; // teal - - Color get iconColor => iconColors[iconColorIndex]; - - void handleIconButtonPress() { - setState(() { - iconColorIndex = (iconColorIndex + 1) % iconColors.length; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Icons'), - actions: [MaterialDemoDocumentationButton(IconsDemo.routeName)], - ), - body: IconTheme( - data: IconThemeData(color: iconColor), - child: SafeArea( - top: false, - bottom: false, - child: Scrollbar( - child: ListView( - padding: const EdgeInsets.all(24.0), - children: [ - _IconsDemoCard(handleIconButtonPress, Icons.face), // direction-agnostic icon - const SizedBox(height: 24.0), - _IconsDemoCard(handleIconButtonPress, Icons.battery_unknown), // direction-aware icon - ], - ), - ), - ), - ), - ); - } -} - -class _IconsDemoCard extends StatelessWidget { - const _IconsDemoCard(this.handleIconButtonPress, this.icon); - - final VoidCallback handleIconButtonPress; - final IconData icon; - - Widget _buildIconButton(double iconSize, IconData icon, bool enabled) { - return IconButton( - icon: Icon(icon), - iconSize: iconSize, - tooltip: "${enabled ? 'Enabled' : 'Disabled'} icon button", - onPressed: enabled ? handleIconButtonPress : null, - ); - } - - Widget _centeredText(String label) => - Padding( - // Match the default padding of IconButton. - padding: const EdgeInsets.all(8.0), - child: Text(label, textAlign: TextAlign.center), - ); - - TableRow _buildIconRow(double size) { - return TableRow( - children: [ - _centeredText(size.floor().toString()), - _buildIconButton(size, icon, true), - _buildIconButton(size, icon, false), - ], - ); - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextStyle textStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); - return Card( - child: DefaultTextStyle( - style: textStyle, - child: Semantics( - explicitChildNodes: true, - child: Table( - defaultVerticalAlignment: TableCellVerticalAlignment.middle, - children: [ - TableRow( - children: [ - _centeredText('Size'), - _centeredText('Enabled'), - _centeredText('Disabled'), - ] - ), - _buildIconRow(18.0), - _buildIconRow(24.0), - _buildIconRow(36.0), - _buildIconRow(48.0), - ], - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/leave_behind_demo.dart b/web/gallery/lib/demo/material/leave_behind_demo.dart deleted file mode 100644 index 87e8d3eca..000000000 --- a/web/gallery/lib/demo/material/leave_behind_demo.dart +++ /dev/null @@ -1,302 +0,0 @@ -// 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:collection/collection.dart' show lowerBound; - -import 'package:flutter/material.dart'; -import 'package:flutter/semantics.dart'; - -import '../../gallery/demo.dart'; - -enum LeaveBehindDemoAction { - reset, - horizontalSwipe, - leftSwipe, - rightSwipe, - confirmDismiss, -} - -class LeaveBehindItem implements Comparable { - LeaveBehindItem({ this.index, this.name, this.subject, this.body }); - - LeaveBehindItem.from(LeaveBehindItem item) - : index = item.index, name = item.name, subject = item.subject, body = item.body; - - final int index; - final String name; - final String subject; - final String body; - - @override - int compareTo(LeaveBehindItem other) => index.compareTo(other.index); -} - -class LeaveBehindDemo extends StatefulWidget { - const LeaveBehindDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/leave-behind'; - - @override - LeaveBehindDemoState createState() => LeaveBehindDemoState(); -} - -class LeaveBehindDemoState extends State { - static final GlobalKey _scaffoldKey = GlobalKey(); - DismissDirection _dismissDirection = DismissDirection.horizontal; - bool _confirmDismiss = true; - List leaveBehindItems; - - void initListItems() { - leaveBehindItems = List.generate(16, (int index) { - return LeaveBehindItem( - index: index, - name: 'Item $index Sender', - subject: 'Subject: $index', - body: "[$index] first line of the message's body...", - ); - }); - } - - @override - void initState() { - super.initState(); - initListItems(); - } - - void handleDemoAction(LeaveBehindDemoAction action) { - setState(() { - switch (action) { - case LeaveBehindDemoAction.reset: - initListItems(); - break; - case LeaveBehindDemoAction.horizontalSwipe: - _dismissDirection = DismissDirection.horizontal; - break; - case LeaveBehindDemoAction.leftSwipe: - _dismissDirection = DismissDirection.endToStart; - break; - case LeaveBehindDemoAction.rightSwipe: - _dismissDirection = DismissDirection.startToEnd; - break; - case LeaveBehindDemoAction.confirmDismiss: - _confirmDismiss = !_confirmDismiss; - break; - } - }); - } - - void handleUndo(LeaveBehindItem item) { - final int insertionIndex = lowerBound(leaveBehindItems, item); - setState(() { - leaveBehindItems.insert(insertionIndex, item); - }); - } - - void _handleArchive(LeaveBehindItem item) { - setState(() { - leaveBehindItems.remove(item); - }); - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text('You archived item ${item.index}'), - action: SnackBarAction( - label: 'UNDO', - onPressed: () { handleUndo(item); }, - ), - )); - } - - void _handleDelete(LeaveBehindItem item) { - setState(() { - leaveBehindItems.remove(item); - }); - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text('You deleted item ${item.index}'), - action: SnackBarAction( - label: 'UNDO', - onPressed: () { handleUndo(item); }, - ), - )); - } - - @override - Widget build(BuildContext context) { - Widget body; - if (leaveBehindItems.isEmpty) { - body = Center( - child: RaisedButton( - onPressed: () => handleDemoAction(LeaveBehindDemoAction.reset), - child: const Text('Reset the list'), - ), - ); - } else { - body = Scrollbar( - child: ListView( - children: leaveBehindItems.map((LeaveBehindItem item) { - return _LeaveBehindListItem( - confirmDismiss: _confirmDismiss, - item: item, - onArchive: _handleArchive, - onDelete: _handleDelete, - dismissDirection: _dismissDirection, - ); - }).toList(), - ), - ); - } - - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Swipe to dismiss'), - actions: [ - MaterialDemoDocumentationButton(LeaveBehindDemo.routeName), - PopupMenuButton( - onSelected: handleDemoAction, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: LeaveBehindDemoAction.reset, - child: Text('Reset the list'), - ), - const PopupMenuDivider(), - CheckedPopupMenuItem( - value: LeaveBehindDemoAction.horizontalSwipe, - checked: _dismissDirection == DismissDirection.horizontal, - child: const Text('Horizontal swipe'), - ), - CheckedPopupMenuItem( - value: LeaveBehindDemoAction.leftSwipe, - checked: _dismissDirection == DismissDirection.endToStart, - child: const Text('Only swipe left'), - ), - CheckedPopupMenuItem( - value: LeaveBehindDemoAction.rightSwipe, - checked: _dismissDirection == DismissDirection.startToEnd, - child: const Text('Only swipe right'), - ), - CheckedPopupMenuItem( - value: LeaveBehindDemoAction.confirmDismiss, - checked: _confirmDismiss, - child: const Text('Confirm dismiss'), - ), - ], - ), - ], - ), - body: body, - ); - } -} - -class _LeaveBehindListItem extends StatelessWidget { - const _LeaveBehindListItem({ - Key key, - @required this.item, - @required this.onArchive, - @required this.onDelete, - @required this.dismissDirection, - @required this.confirmDismiss, - }) : super(key: key); - - final LeaveBehindItem item; - final DismissDirection dismissDirection; - final void Function(LeaveBehindItem) onArchive; - final void Function(LeaveBehindItem) onDelete; - final bool confirmDismiss; - - void _handleArchive() { - onArchive(item); - } - - void _handleDelete() { - onDelete(item); - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Semantics( - customSemanticsActions: { - const CustomSemanticsAction(label: 'Archive'): _handleArchive, - const CustomSemanticsAction(label: 'Delete'): _handleDelete, - }, - child: Dismissible( - key: ObjectKey(item), - direction: dismissDirection, - onDismissed: (DismissDirection direction) { - if (direction == DismissDirection.endToStart) - _handleArchive(); - else - _handleDelete(); - }, - confirmDismiss: !confirmDismiss ? null : (DismissDirection dismissDirection) async { - switch(dismissDirection) { - case DismissDirection.endToStart: - return await _showConfirmationDialog(context, 'archive') == true; - case DismissDirection.startToEnd: - return await _showConfirmationDialog(context, 'delete') == true; - case DismissDirection.horizontal: - case DismissDirection.vertical: - case DismissDirection.up: - case DismissDirection.down: - assert(false); - } - return false; - }, - background: Container( - color: theme.primaryColor, - child: const Center( - child: ListTile( - leading: Icon(Icons.delete, color: Colors.white, size: 36.0), - ), - ), - ), - secondaryBackground: Container( - color: theme.primaryColor, - child: const Center( - child: ListTile( - trailing: Icon(Icons.archive, color: Colors.white, size: 36.0), - ), - ), - ), - child: Container( - decoration: BoxDecoration( - color: theme.canvasColor, - border: Border(bottom: BorderSide(color: theme.dividerColor)), - ), - child: ListTile( - title: Text(item.name), - subtitle: Text('${item.subject}\n${item.body}'), - isThreeLine: true, - ), - ), - ), - ); - } - - Future _showConfirmationDialog(BuildContext context, String action) { - return showDialog( - context: context, - barrierDismissible: true, - builder: (BuildContext context) { - return AlertDialog( - title: Text('Do you want to $action this item?'), - actions: [ - FlatButton( - child: const Text('Yes'), - onPressed: () { - Navigator.pop(context, true); // showDialog() returns true - }, - ), - FlatButton( - child: const Text('No'), - onPressed: () { - Navigator.pop(context, false); // showDialog() returns false - }, - ), - ], - ); - }, - ); - } -} diff --git a/web/gallery/lib/demo/material/list_demo.dart b/web/gallery/lib/demo/material/list_demo.dart deleted file mode 100644 index 0e90ef69f..000000000 --- a/web/gallery/lib/demo/material/list_demo.dart +++ /dev/null @@ -1,251 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -enum _MaterialListType { - /// A list tile that contains a single line of text. - oneLine, - - /// A list tile that contains a [CircleAvatar] followed by a single line of text. - oneLineWithAvatar, - - /// A list tile that contains two lines of text. - twoLine, - - /// A list tile that contains three lines of text. - threeLine, -} - -class ListDemo extends StatefulWidget { - const ListDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/list'; - - @override - _ListDemoState createState() => _ListDemoState(); -} - -class _ListDemoState extends State { - static final GlobalKey scaffoldKey = GlobalKey(); - - PersistentBottomSheetController _bottomSheet; - _MaterialListType _itemType = _MaterialListType.threeLine; - bool _dense = false; - bool _showAvatars = true; - bool _showIcons = false; - bool _showDividers = false; - bool _reverseSort = false; - List items = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - ]; - - void changeItemType(_MaterialListType type) { - setState(() { - _itemType = type; - }); - _bottomSheet?.setState(() { }); - } - - void _showConfigurationSheet() { - final PersistentBottomSheetController bottomSheet = scaffoldKey.currentState.showBottomSheet((BuildContext bottomSheetContext) { - return Container( - decoration: const BoxDecoration( - border: Border(top: BorderSide(color: Colors.black26)), - ), - child: ListView( - shrinkWrap: true, - primary: false, - children: [ - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('One-line'), - trailing: Radio<_MaterialListType>( - value: _showAvatars ? _MaterialListType.oneLineWithAvatar : _MaterialListType.oneLine, - groupValue: _itemType, - onChanged: changeItemType, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Two-line'), - trailing: Radio<_MaterialListType>( - value: _MaterialListType.twoLine, - groupValue: _itemType, - onChanged: changeItemType, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Three-line'), - trailing: Radio<_MaterialListType>( - value: _MaterialListType.threeLine, - groupValue: _itemType, - onChanged: changeItemType, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Show avatar'), - trailing: Checkbox( - value: _showAvatars, - onChanged: (bool value) { - setState(() { - _showAvatars = value; - }); - _bottomSheet?.setState(() { }); - }, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Show icon'), - trailing: Checkbox( - value: _showIcons, - onChanged: (bool value) { - setState(() { - _showIcons = value; - }); - _bottomSheet?.setState(() { }); - }, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Show dividers'), - trailing: Checkbox( - value: _showDividers, - onChanged: (bool value) { - setState(() { - _showDividers = value; - }); - _bottomSheet?.setState(() { }); - }, - ), - ), - ), - MergeSemantics( - child: ListTile( - dense: true, - title: const Text('Dense layout'), - trailing: Checkbox( - value: _dense, - onChanged: (bool value) { - setState(() { - _dense = value; - }); - _bottomSheet?.setState(() { }); - }, - ), - ), - ), - ], - ), - ); - }); - - setState(() { - _bottomSheet = bottomSheet; - }); - - _bottomSheet.closed.whenComplete(() { - if (mounted) { - setState(() { - _bottomSheet = null; - }); - } - }); - } - - Widget buildListTile(BuildContext context, String item) { - Widget secondary; - if (_itemType == _MaterialListType.twoLine) { - secondary = const Text('Additional item information.'); - } else if (_itemType == _MaterialListType.threeLine) { - secondary = const Text( - 'Even more additional list item information appears on line three.', - ); - } - return MergeSemantics( - child: ListTile( - isThreeLine: _itemType == _MaterialListType.threeLine, - dense: _dense, - leading: _showAvatars ? ExcludeSemantics(child: CircleAvatar(child: Text(item))) : null, - title: Text('This item represents $item.'), - subtitle: secondary, - trailing: _showIcons ? Icon(Icons.info, color: Theme.of(context).disabledColor) : null, - ), - ); - } - - @override - Widget build(BuildContext context) { - final String layoutText = _dense ? ' \u2013 Dense' : ''; - String itemTypeText; - switch (_itemType) { - case _MaterialListType.oneLine: - case _MaterialListType.oneLineWithAvatar: - itemTypeText = 'Single-line'; - break; - case _MaterialListType.twoLine: - itemTypeText = 'Two-line'; - break; - case _MaterialListType.threeLine: - itemTypeText = 'Three-line'; - break; - } - - Iterable listTiles = items.map((String item) => buildListTile(context, item)); - if (_showDividers) - listTiles = ListTile.divideTiles(context: context, tiles: listTiles); - - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: Text('Scrolling list\n$itemTypeText$layoutText'), - actions: [ - MaterialDemoDocumentationButton(ListDemo.routeName), - IconButton( - icon: const Icon(Icons.sort_by_alpha), - tooltip: 'Sort', - onPressed: () { - setState(() { - _reverseSort = !_reverseSort; - items.sort((String a, String b) => _reverseSort ? b.compareTo(a) : a.compareTo(b)); - }); - }, - ), - IconButton( - icon: Icon( - Theme.of(context).platform == TargetPlatform.iOS - ? Icons.more_horiz - : Icons.more_vert, - ), - tooltip: 'Show menu', - onPressed: _bottomSheet == null ? _showConfigurationSheet : null, - ), - ], - ), - body: Scrollbar( - child: ListView( - padding: EdgeInsets.symmetric(vertical: _dense ? 4.0 : 8.0), - children: listTiles.toList(), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/material.dart b/web/gallery/lib/demo/material/material.dart deleted file mode 100644 index eff2d39ea..000000000 --- a/web/gallery/lib/demo/material/material.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 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. - -export 'backdrop_demo.dart'; -export 'banner_demo.dart'; -export 'bottom_app_bar_demo.dart'; -export 'bottom_navigation_demo.dart'; -export 'buttons_demo.dart'; -export 'cards_demo.dart'; -export 'chip_demo.dart'; -export 'data_table_demo.dart'; -export 'date_and_time_picker_demo.dart'; -export 'dialog_demo.dart'; -export 'drawer_demo.dart'; -export 'elevation_demo.dart'; -export 'expansion_panels_demo.dart'; -export 'expansion_tile_list_demo.dart'; -export 'grid_list_demo.dart'; -export 'icons_demo.dart'; -export 'leave_behind_demo.dart'; -export 'list_demo.dart'; -export 'menu_demo.dart'; -export 'modal_bottom_sheet_demo.dart'; -export 'overscroll_demo.dart'; -export 'page_selector_demo.dart'; -export 'persistent_bottom_sheet_demo.dart'; -export 'progress_indicator_demo.dart'; -export 'reorderable_list_demo.dart'; -export 'scrollable_tabs_demo.dart'; -export 'search_demo.dart'; -export 'selection_controls_demo.dart'; -export 'slider_demo.dart'; -export 'snack_bar_demo.dart'; -export 'tabs_demo.dart'; -export 'tabs_fab_demo.dart'; -export 'text_form_field_demo.dart'; -export 'tooltip_demo.dart'; diff --git a/web/gallery/lib/demo/material/menu_demo.dart b/web/gallery/lib/demo/material/menu_demo.dart deleted file mode 100644 index 2434b4de5..000000000 --- a/web/gallery/lib/demo/material/menu_demo.dart +++ /dev/null @@ -1,219 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -class MenuDemo extends StatefulWidget { - const MenuDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/menu'; - - @override - MenuDemoState createState() => MenuDemoState(); -} - -class MenuDemoState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - final String _simpleValue1 = 'Menu item value one'; - final String _simpleValue2 = 'Menu item value two'; - final String _simpleValue3 = 'Menu item value three'; - String _simpleValue; - - final String _checkedValue1 = 'One'; - final String _checkedValue2 = 'Two'; - final String _checkedValue3 = 'Free'; - final String _checkedValue4 = 'Four'; - List _checkedValues; - - @override - void initState() { - super.initState(); - _simpleValue = _simpleValue2; - _checkedValues = [_checkedValue3]; - } - - void showInSnackBar(String value) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text(value), - )); - } - - void showMenuSelection(String value) { - if ([_simpleValue1, _simpleValue2, _simpleValue3].contains(value)) - _simpleValue = value; - showInSnackBar('You selected: $value'); - } - - void showCheckedMenuSelections(String value) { - if (_checkedValues.contains(value)) - _checkedValues.remove(value); - else - _checkedValues.add(value); - - showInSnackBar('Checked $_checkedValues'); - } - - bool isChecked(String value) => _checkedValues.contains(value); - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Menus'), - actions: [ - MaterialDemoDocumentationButton(MenuDemo.routeName), - PopupMenuButton( - onSelected: showMenuSelection, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: 'Toolbar menu', - child: Text('Toolbar menu'), - ), - const PopupMenuItem( - value: 'Right here', - child: Text('Right here'), - ), - const PopupMenuItem( - value: 'Hooray!', - child: Text('Hooray!'), - ), - ], - ), - ], - ), - body: ListView( - padding: kMaterialListPadding, - children: [ - // Pressing the PopupMenuButton on the right of this item shows - // a simple menu with one disabled item. Typically the contents - // of this "contextual menu" would reflect the app's state. - ListTile( - title: const Text('An item with a context menu button'), - trailing: PopupMenuButton( - padding: EdgeInsets.zero, - onSelected: showMenuSelection, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: _simpleValue1, - child: const Text('Context menu item one'), - ), - const PopupMenuItem( - enabled: false, - child: Text('A disabled menu item'), - ), - PopupMenuItem( - value: _simpleValue3, - child: const Text('Context menu item three'), - ), - ], - ), - ), - // Pressing the PopupMenuButton on the right of this item shows - // a menu whose items have text labels and icons and a divider - // That separates the first three items from the last one. - ListTile( - title: const Text('An item with a sectioned menu'), - trailing: PopupMenuButton( - padding: EdgeInsets.zero, - onSelected: showMenuSelection, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: 'Preview', - child: ListTile( - leading: Icon(Icons.visibility), - title: Text('Preview'), - ), - ), - const PopupMenuItem( - value: 'Share', - child: ListTile( - leading: Icon(Icons.person_add), - title: Text('Share'), - ), - ), - const PopupMenuItem( - value: 'Get Link', - child: ListTile( - leading: Icon(Icons.link), - title: Text('Get link'), - ), - ), - const PopupMenuDivider(), - const PopupMenuItem( - value: 'Remove', - child: ListTile( - leading: Icon(Icons.delete), - title: Text('Remove'), - ), - ), - ], - ), - ), - // This entire list item is a PopupMenuButton. Tapping anywhere shows - // a menu whose current value is highlighted and aligned over the - // list item's center line. - PopupMenuButton( - padding: EdgeInsets.zero, - initialValue: _simpleValue, - onSelected: showMenuSelection, - child: ListTile( - title: const Text('An item with a simple menu'), - subtitle: Text(_simpleValue), - ), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: _simpleValue1, - child: Text(_simpleValue1), - ), - PopupMenuItem( - value: _simpleValue2, - child: Text(_simpleValue2), - ), - PopupMenuItem( - value: _simpleValue3, - child: Text(_simpleValue3), - ), - ], - ), - // Pressing the PopupMenuButton on the right of this item shows a menu - // whose items have checked icons that reflect this app's state. - ListTile( - title: const Text('An item with a checklist menu'), - trailing: PopupMenuButton( - padding: EdgeInsets.zero, - onSelected: showCheckedMenuSelections, - itemBuilder: (BuildContext context) => >[ - CheckedPopupMenuItem( - value: _checkedValue1, - checked: isChecked(_checkedValue1), - child: Text(_checkedValue1), - ), - CheckedPopupMenuItem( - value: _checkedValue2, - enabled: false, - checked: isChecked(_checkedValue2), - child: Text(_checkedValue2), - ), - CheckedPopupMenuItem( - value: _checkedValue3, - checked: isChecked(_checkedValue3), - child: Text(_checkedValue3), - ), - CheckedPopupMenuItem( - value: _checkedValue4, - checked: isChecked(_checkedValue4), - child: Text(_checkedValue4), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/modal_bottom_sheet_demo.dart b/web/gallery/lib/demo/material/modal_bottom_sheet_demo.dart deleted file mode 100644 index 578f52637..000000000 --- a/web/gallery/lib/demo/material/modal_bottom_sheet_demo.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -class ModalBottomSheetDemo extends StatelessWidget { - static const String routeName = '/material/modal-bottom-sheet'; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Modal bottom sheet'), - actions: [MaterialDemoDocumentationButton(routeName)], - ), - body: Center( - child: RaisedButton( - child: const Text('SHOW BOTTOM SHEET'), - onPressed: () { - showModalBottomSheet(context: context, builder: (BuildContext context) { - return Container( - child: Padding( - padding: const EdgeInsets.all(32.0), - child: Text('This is the modal bottom sheet. Slide down to dismiss.', - textAlign: TextAlign.center, - style: TextStyle( - color: Theme.of(context).accentColor, - fontSize: 24.0, - ), - ), - ), - ); - }); - }, - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/overscroll_demo.dart b/web/gallery/lib/demo/material/overscroll_demo.dart deleted file mode 100644 index cb9ebfc26..000000000 --- a/web/gallery/lib/demo/material/overscroll_demo.dart +++ /dev/null @@ -1,83 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -enum IndicatorType { overscroll, refresh } - -class OverscrollDemo extends StatefulWidget { - const OverscrollDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/overscroll'; - - @override - OverscrollDemoState createState() => OverscrollDemoState(); -} - -class OverscrollDemoState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - final GlobalKey _refreshIndicatorKey = GlobalKey(); - static final List _items = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - ]; - - Future _handleRefresh() { - final Completer completer = Completer(); - Timer(const Duration(seconds: 3), () { completer.complete(); }); - return completer.future.then((_) { - _scaffoldKey.currentState?.showSnackBar(SnackBar( - content: const Text('Refresh complete'), - action: SnackBarAction( - label: 'RETRY', - onPressed: () { - _refreshIndicatorKey.currentState.show(); - }, - ), - )); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Pull to refresh'), - actions: [ - MaterialDemoDocumentationButton(OverscrollDemo.routeName), - IconButton( - icon: const Icon(Icons.refresh), - tooltip: 'Refresh', - onPressed: () { - _refreshIndicatorKey.currentState.show(); - }, - ), - ], - ), - body: RefreshIndicator( - key: _refreshIndicatorKey, - onRefresh: _handleRefresh, - child: Scrollbar( - child: ListView.builder( - padding: kMaterialListPadding, - itemCount: _items.length, - itemBuilder: (BuildContext context, int index) { - final String item = _items[index]; - return ListTile( - isThreeLine: true, - leading: CircleAvatar(child: Text(item)), - title: Text('This item represents $item.'), - subtitle: const Text('Even more additional list item information appears on line three.'), - ); - }, - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/page_selector_demo.dart b/web/gallery/lib/demo/material/page_selector_demo.dart deleted file mode 100644 index f18d1d921..000000000 --- a/web/gallery/lib/demo/material/page_selector_demo.dart +++ /dev/null @@ -1,100 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -class _PageSelector extends StatelessWidget { - const _PageSelector({ this.icons }); - - final List icons; - - void _handleArrowButtonPress(BuildContext context, int delta) { - final TabController controller = DefaultTabController.of(context); - if (!controller.indexIsChanging) - controller.animateTo((controller.index + delta).clamp(0, icons.length - 1)); - } - - @override - Widget build(BuildContext context) { - final TabController controller = DefaultTabController.of(context); - final Color color = Theme.of(context).accentColor; - return SafeArea( - top: false, - bottom: false, - child: Column( - children: [ - Container( - margin: const EdgeInsets.only(top: 16.0), - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.chevron_left), - color: color, - onPressed: () { _handleArrowButtonPress(context, -1); }, - tooltip: 'Page back', - ), - TabPageSelector(controller: controller), - IconButton( - icon: const Icon(Icons.chevron_right), - color: color, - onPressed: () { _handleArrowButtonPress(context, 1); }, - tooltip: 'Page forward', - ), - ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, - ), - ), - Expanded( - child: IconTheme( - data: IconThemeData( - size: 128.0, - color: color, - ), - child: TabBarView( - children: icons.map((Icon icon) { - return Container( - padding: const EdgeInsets.all(12.0), - child: Card( - child: Center( - child: icon, - ), - ), - ); - }).toList(), - ), - ), - ), - ], - ), - ); - } -} - -class PageSelectorDemo extends StatelessWidget { - static const String routeName = '/material/page-selector'; - static final List icons = [ - const Icon(Icons.event, semanticLabel: 'Event'), - const Icon(Icons.home, semanticLabel: 'Home'), - const Icon(Icons.android, semanticLabel: 'Android'), - const Icon(Icons.alarm, semanticLabel: 'Alarm'), - const Icon(Icons.face, semanticLabel: 'Face'), - const Icon(Icons.language, semanticLabel: 'Language'), - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Page selector'), - actions: [MaterialDemoDocumentationButton(routeName)], - ), - body: DefaultTabController( - length: icons.length, - child: _PageSelector(icons: icons), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/persistent_bottom_sheet_demo.dart b/web/gallery/lib/demo/material/persistent_bottom_sheet_demo.dart deleted file mode 100644 index 7771c9d4f..000000000 --- a/web/gallery/lib/demo/material/persistent_bottom_sheet_demo.dart +++ /dev/null @@ -1,103 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -class PersistentBottomSheetDemo extends StatefulWidget { - static const String routeName = '/material/persistent-bottom-sheet'; - - @override - _PersistentBottomSheetDemoState createState() => _PersistentBottomSheetDemoState(); -} - -class _PersistentBottomSheetDemoState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - VoidCallback _showBottomSheetCallback; - - @override - void initState() { - super.initState(); - _showBottomSheetCallback = _showBottomSheet; - } - - void _showBottomSheet() { - setState(() { // disable the button - _showBottomSheetCallback = null; - }); - _scaffoldKey.currentState.showBottomSheet((BuildContext context) { - final ThemeData themeData = Theme.of(context); - return Container( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: themeData.disabledColor)) - ), - child: Padding( - padding: const EdgeInsets.all(32.0), - child: Text('This is a Material persistent bottom sheet. Drag downwards to dismiss it.', - textAlign: TextAlign.center, - style: TextStyle( - color: themeData.accentColor, - fontSize: 24.0, - ), - ), - ), - ); - }) - .closed.whenComplete(() { - if (mounted) { - setState(() { // re-enable the button - _showBottomSheetCallback = _showBottomSheet; - }); - } - }); - } - - void _showMessage() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: const Text('You tapped the floating action button.'), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text('OK'), - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Persistent bottom sheet'), - actions: [ - MaterialDemoDocumentationButton(PersistentBottomSheetDemo.routeName), - ], - ), - floatingActionButton: FloatingActionButton( - onPressed: _showMessage, - backgroundColor: Colors.redAccent, - child: const Icon( - Icons.add, - semanticLabel: 'Add', - ), - ), - body: Center( - child: RaisedButton( - onPressed: _showBottomSheetCallback, - child: const Text('SHOW BOTTOM SHEET'), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/progress_indicator_demo.dart b/web/gallery/lib/demo/material/progress_indicator_demo.dart deleted file mode 100644 index ae80842f2..000000000 --- a/web/gallery/lib/demo/material/progress_indicator_demo.dart +++ /dev/null @@ -1,133 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -class ProgressIndicatorDemo extends StatefulWidget { - static const String routeName = '/material/progress-indicator'; - - @override - _ProgressIndicatorDemoState createState() => _ProgressIndicatorDemoState(); -} - -class _ProgressIndicatorDemoState extends State with SingleTickerProviderStateMixin { - AnimationController _controller; - Animation _animation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 1500), - vsync: this, - animationBehavior: AnimationBehavior.preserve, - )..forward(); - - _animation = CurvedAnimation( - parent: _controller, - curve: const Interval(0.0, 0.9, curve: Curves.fastOutSlowIn), - reverseCurve: Curves.fastOutSlowIn, - )..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.dismissed) - _controller.forward(); - else if (status == AnimationStatus.completed) - _controller.reverse(); - }); - } - - @override - void dispose() { - _controller.stop(); - super.dispose(); - } - - void _handleTap() { - setState(() { - // valueAnimation.isAnimating is part of our build state - if (_controller.isAnimating) { - _controller.stop(); - } else { - switch (_controller.status) { - case AnimationStatus.dismissed: - case AnimationStatus.forward: - _controller.forward(); - break; - case AnimationStatus.reverse: - case AnimationStatus.completed: - _controller.reverse(); - break; - } - } - }); - } - - Widget _buildIndicators(BuildContext context, Widget child) { - final List indicators = [ - const SizedBox( - width: 200.0, - child: LinearProgressIndicator(), - ), - const LinearProgressIndicator(), - const LinearProgressIndicator(), - LinearProgressIndicator(value: _animation.value), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const CircularProgressIndicator(), - SizedBox( - width: 20.0, - height: 20.0, - child: CircularProgressIndicator(value: _animation.value), - ), - SizedBox( - width: 100.0, - height: 20.0, - child: Text('${(_animation.value * 100.0).toStringAsFixed(1)}%', - textAlign: TextAlign.right, - ), - ), - ], - ), - ]; - return Column( - children: indicators - .map((Widget c) => Container(child: c, margin: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0))) - .toList(), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Progress indicators'), - actions: [MaterialDemoDocumentationButton(ProgressIndicatorDemo.routeName)], - ), - body: Center( - child: SingleChildScrollView( - child: DefaultTextStyle( - style: Theme.of(context).textTheme.title, - child: GestureDetector( - onTap: _handleTap, - behavior: HitTestBehavior.opaque, - child: SafeArea( - top: false, - bottom: false, - child: Container( - padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0), - child: AnimatedBuilder( - animation: _animation, - builder: _buildIndicators, - ), - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/reorderable_list_demo.dart b/web/gallery/lib/demo/material/reorderable_list_demo.dart deleted file mode 100644 index 79b17be1d..000000000 --- a/web/gallery/lib/demo/material/reorderable_list_demo.dart +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2018 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/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -import '../../gallery/demo.dart'; - -enum _ReorderableListType { - /// A list tile that contains a [CircleAvatar]. - horizontalAvatar, - - /// A list tile that contains a [CircleAvatar]. - verticalAvatar, - - /// A list tile that contains three lines of text and a checkbox. - threeLine, -} - -class ReorderableListDemo extends StatefulWidget { - const ReorderableListDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/reorderable-list'; - - @override - _ListDemoState createState() => _ListDemoState(); -} - -class _ListItem { - _ListItem(this.value, this.checkState); - - final String value; - - bool checkState; -} - -class _ListDemoState extends State { - static final GlobalKey scaffoldKey = GlobalKey(); - - PersistentBottomSheetController _bottomSheet; - _ReorderableListType _itemType = _ReorderableListType.threeLine; - bool _reverse = false; - bool _reverseSort = false; - final List<_ListItem> _items = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - ].map<_ListItem>((String item) => _ListItem(item, false)).toList(); - - void changeItemType(_ReorderableListType type) { - setState(() { - _itemType = type; - }); - // Rebuild the bottom sheet to reflect the selected list view. - _bottomSheet?.setState(() { - // Trigger a rebuild. - }); - // Close the bottom sheet to give the user a clear view of the list. - _bottomSheet?.close(); - } - - void changeReverse(bool newValue) { - setState(() { - _reverse = newValue; - }); - // Rebuild the bottom sheet to reflect the selected list view. - _bottomSheet?.setState(() { - // Trigger a rebuild. - }); - // Close the bottom sheet to give the user a clear view of the list. - _bottomSheet?.close(); - } - - void _showConfigurationSheet() { - setState(() { - _bottomSheet = scaffoldKey.currentState.showBottomSheet((BuildContext bottomSheetContext) { - return DecoratedBox( - decoration: const BoxDecoration( - border: Border(top: BorderSide(color: Colors.black26)), - ), - child: ListView( - shrinkWrap: true, - primary: false, - children: [ - CheckboxListTile( - dense: true, - title: const Text('Reverse'), - value: _reverse, - onChanged: changeReverse, - ), - RadioListTile<_ReorderableListType>( - dense: true, - title: const Text('Horizontal Avatars'), - value: _ReorderableListType.horizontalAvatar, - groupValue: _itemType, - onChanged: changeItemType, - ), - RadioListTile<_ReorderableListType>( - dense: true, - title: const Text('Vertical Avatars'), - value: _ReorderableListType.verticalAvatar, - groupValue: _itemType, - onChanged: changeItemType, - ), - RadioListTile<_ReorderableListType>( - dense: true, - title: const Text('Three-line'), - value: _ReorderableListType.threeLine, - groupValue: _itemType, - onChanged: changeItemType, - ), - ], - ), - ); - }); - - // Garbage collect the bottom sheet when it closes. - _bottomSheet.closed.whenComplete(() { - if (mounted) { - setState(() { - _bottomSheet = null; - }); - } - }); - }); - } - - Widget buildListTile(_ListItem item) { - const Widget secondary = Text( - 'Even more additional list item information appears on line three.', - ); - Widget listTile; - switch (_itemType) { - case _ReorderableListType.threeLine: - listTile = CheckboxListTile( - key: Key(item.value), - isThreeLine: true, - value: item.checkState ?? false, - onChanged: (bool newValue) { - setState(() { - item.checkState = newValue; - }); - }, - title: Text('This item represents ${item.value}.'), - subtitle: secondary, - secondary: const Icon(Icons.drag_handle), - ); - break; - case _ReorderableListType.horizontalAvatar: - case _ReorderableListType.verticalAvatar: - listTile = Container( - key: Key(item.value), - height: 100.0, - width: 100.0, - child: CircleAvatar(child: Text(item.value), - backgroundColor: Colors.green, - ), - ); - break; - } - - return listTile; - } - - void _onReorder(int oldIndex, int newIndex) { - setState(() { - if (newIndex > oldIndex) { - newIndex -= 1; - } - final _ListItem item = _items.removeAt(oldIndex); - _items.insert(newIndex, item); - }); - } - - - @override - Widget build(BuildContext context) { - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: const Text('Reorderable list'), - actions: [ - MaterialDemoDocumentationButton(ReorderableListDemo.routeName), - IconButton( - icon: const Icon(Icons.sort_by_alpha), - tooltip: 'Sort', - onPressed: () { - setState(() { - _reverseSort = !_reverseSort; - _items.sort((_ListItem a, _ListItem b) => _reverseSort ? b.value.compareTo(a.value) : a.value.compareTo(b.value)); - }); - }, - ), - IconButton( - icon: Icon( - Theme.of(context).platform == TargetPlatform.iOS - ? Icons.more_horiz - : Icons.more_vert, - ), - tooltip: 'Show menu', - onPressed: _bottomSheet == null ? _showConfigurationSheet : null, - ), - ], - ), - body: Scrollbar( - child: ReorderableListView( - header: _itemType != _ReorderableListType.threeLine - ? Padding( - padding: const EdgeInsets.all(8.0), - child: Text('Header of the list', style: Theme.of(context).textTheme.headline)) - : null, - onReorder: _onReorder, - reverse: _reverse, - scrollDirection: _itemType == _ReorderableListType.horizontalAvatar ? Axis.horizontal : Axis.vertical, - padding: const EdgeInsets.symmetric(vertical: 8.0), - children: _items.map(buildListTile).toList(), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/scrollable_tabs_demo.dart b/web/gallery/lib/demo/material/scrollable_tabs_demo.dart deleted file mode 100644 index 7e32cb15f..000000000 --- a/web/gallery/lib/demo/material/scrollable_tabs_demo.dart +++ /dev/null @@ -1,200 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -enum TabsDemoStyle { - iconsAndText, - iconsOnly, - textOnly -} - -class _Page { - const _Page({ this.icon, this.text }); - final IconData icon; - final String text; -} - -const List<_Page> _allPages = <_Page>[ - _Page(icon: Icons.grade, text: 'TRIUMPH'), - _Page(icon: Icons.playlist_add, text: 'NOTE'), - _Page(icon: Icons.check_circle, text: 'SUCCESS'), - _Page(icon: Icons.question_answer, text: 'OVERSTATE'), - _Page(icon: Icons.sentiment_very_satisfied, text: 'SATISFACTION'), - _Page(icon: Icons.camera, text: 'APERTURE'), - _Page(icon: Icons.assignment_late, text: 'WE MUST'), - _Page(icon: Icons.assignment_turned_in, text: 'WE CAN'), - _Page(icon: Icons.group, text: 'ALL'), - _Page(icon: Icons.block, text: 'EXCEPT'), - _Page(icon: Icons.sentiment_very_dissatisfied, text: 'CRYING'), - _Page(icon: Icons.error, text: 'MISTAKE'), - _Page(icon: Icons.loop, text: 'TRYING'), - _Page(icon: Icons.cake, text: 'CAKE'), -]; - -class ScrollableTabsDemo extends StatefulWidget { - static const String routeName = '/material/scrollable-tabs'; - - @override - ScrollableTabsDemoState createState() => ScrollableTabsDemoState(); -} - -class ScrollableTabsDemoState extends State with SingleTickerProviderStateMixin { - TabController _controller; - TabsDemoStyle _demoStyle = TabsDemoStyle.iconsAndText; - bool _customIndicator = false; - - @override - void initState() { - super.initState(); - _controller = TabController(vsync: this, length: _allPages.length); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void changeDemoStyle(TabsDemoStyle style) { - setState(() { - _demoStyle = style; - }); - } - - Decoration getIndicator() { - if (!_customIndicator) - return const UnderlineTabIndicator(); - - switch(_demoStyle) { - case TabsDemoStyle.iconsAndText: - return ShapeDecoration( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4.0)), - side: BorderSide( - color: Colors.white24, - width: 2.0, - ), - ) + const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4.0)), - side: BorderSide( - color: Colors.transparent, - width: 4.0, - ), - ), - ); - - case TabsDemoStyle.iconsOnly: - return ShapeDecoration( - shape: const CircleBorder( - side: BorderSide( - color: Colors.white24, - width: 4.0, - ), - ) + const CircleBorder( - side: BorderSide( - color: Colors.transparent, - width: 4.0, - ), - ), - ); - - case TabsDemoStyle.textOnly: - return ShapeDecoration( - shape: const StadiumBorder( - side: BorderSide( - color: Colors.white24, - width: 2.0, - ), - ) + const StadiumBorder( - side: BorderSide( - color: Colors.transparent, - width: 4.0, - ), - ), - ); - } - return null; - } - - @override - Widget build(BuildContext context) { - final Color iconColor = Theme.of(context).accentColor; - return Scaffold( - appBar: AppBar( - title: const Text('Scrollable tabs'), - actions: [ - MaterialDemoDocumentationButton(ScrollableTabsDemo.routeName), - IconButton( - icon: const Icon(Icons.sentiment_very_satisfied), - onPressed: () { - setState(() { - _customIndicator = !_customIndicator; - }); - }, - ), - PopupMenuButton( - onSelected: changeDemoStyle, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: TabsDemoStyle.iconsAndText, - child: Text('Icons and text'), - ), - const PopupMenuItem( - value: TabsDemoStyle.iconsOnly, - child: Text('Icons only'), - ), - const PopupMenuItem( - value: TabsDemoStyle.textOnly, - child: Text('Text only'), - ), - ], - ), - ], - bottom: TabBar( - controller: _controller, - isScrollable: true, - indicator: getIndicator(), - tabs: _allPages.map((_Page page) { - assert(_demoStyle != null); - switch (_demoStyle) { - case TabsDemoStyle.iconsAndText: - return Tab(text: page.text, icon: Icon(page.icon)); - case TabsDemoStyle.iconsOnly: - return Tab(icon: Icon(page.icon)); - case TabsDemoStyle.textOnly: - return Tab(text: page.text); - } - return null; - }).toList(), - ), - ), - body: TabBarView( - controller: _controller, - children: _allPages.map((_Page page) { - return SafeArea( - top: false, - bottom: false, - child: Container( - key: ObjectKey(page.icon), - padding: const EdgeInsets.all(12.0), - child: Card( - child: Center( - child: Icon( - page.icon, - color: iconColor, - size: 128.0, - semanticLabel: 'Placeholder for ${page.text} tab', - ), - ), - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/search_demo.dart b/web/gallery/lib/demo/material/search_demo.dart deleted file mode 100644 index bf3357363..000000000 --- a/web/gallery/lib/demo/material/search_demo.dart +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2018 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 '../../gallery/demo.dart'; - -class SearchDemo extends StatefulWidget { - static const String routeName = '/material/search'; - - @override - _SearchDemoState createState() => _SearchDemoState(); -} - -class _SearchDemoState extends State { - final _SearchDemoSearchDelegate _delegate = _SearchDemoSearchDelegate(); - final GlobalKey _scaffoldKey = GlobalKey(); - - int _lastIntegerSelected; - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - leading: IconButton( - tooltip: 'Navigation menu', - icon: AnimatedIcon( - icon: AnimatedIcons.menu_arrow, - color: Colors.white, - progress: _delegate.transitionAnimation, - ), - onPressed: () { - _scaffoldKey.currentState.openDrawer(); - }, - ), - title: const Text('Numbers'), - actions: [ - IconButton( - tooltip: 'Search', - icon: const Icon(Icons.search), - onPressed: () async { - final int selected = await showSearch( - context: context, - delegate: _delegate, - ); - if (selected != null && selected != _lastIntegerSelected) { - setState(() { - _lastIntegerSelected = selected; - }); - } - }, - ), - MaterialDemoDocumentationButton(SearchDemo.routeName), - IconButton( - tooltip: 'More (not implemented)', - icon: Icon( - Theme.of(context).platform == TargetPlatform.iOS - ? Icons.more_horiz - : Icons.more_vert, - ), - onPressed: () { }, - ), - ], - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - MergeSemantics( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Text('Press the '), - Tooltip( - message: 'search', - child: Icon( - Icons.search, - size: 18.0, - ), - ), - Text(' icon in the AppBar'), - ], - ), - const Text('and search for an integer between 0 and 100,000.'), - ], - ), - ), - const SizedBox(height: 64.0), - Text('Last selected integer: ${_lastIntegerSelected ?? 'NONE' }.'), - ], - ), - ), - floatingActionButton: FloatingActionButton.extended( - tooltip: 'Back', // Tests depend on this label to exit the demo. - onPressed: () { - Navigator.of(context).pop(); - }, - label: const Text('Close demo'), - icon: const Icon(Icons.close), - ), - drawer: Drawer( - child: Column( - children: [ - const UserAccountsDrawerHeader( - accountName: Text('Peter Widget'), - accountEmail: Text('peter.widget@example.com'), - currentAccountPicture: CircleAvatar( - backgroundImage: AssetImage( - 'people/square/peter.png', - package: 'flutter_gallery_assets', - ), - ), - margin: EdgeInsets.zero, - ), - MediaQuery.removePadding( - context: context, - // DrawerHeader consumes top MediaQuery padding. - removeTop: true, - child: const ListTile( - leading: Icon(Icons.payment), - title: Text('Placeholder'), - ), - ), - ], - ), - ), - ); - } -} - -class _SearchDemoSearchDelegate extends SearchDelegate { - final List _data = List.generate(100001, (int i) => i).reversed.toList(); - final List _history = [42607, 85604, 66374, 44, 174]; - - @override - Widget buildLeading(BuildContext context) { - return IconButton( - tooltip: 'Back', - icon: AnimatedIcon( - icon: AnimatedIcons.menu_arrow, - progress: transitionAnimation, - ), - onPressed: () { - close(context, null); - }, - ); - } - - @override - Widget buildSuggestions(BuildContext context) { - - final Iterable suggestions = query.isEmpty - ? _history - : _data.where((int i) => '$i'.startsWith(query)); - - return _SuggestionList( - query: query, - suggestions: suggestions.map((int i) => '$i').toList(), - onSelected: (String suggestion) { - query = suggestion; - showResults(context); - }, - ); - } - - @override - Widget buildResults(BuildContext context) { - final int searched = int.tryParse(query); - if (searched == null || !_data.contains(searched)) { - return Center( - child: Text( - '"$query"\n is not a valid integer between 0 and 100,000.\nTry again.', - textAlign: TextAlign.center, - ), - ); - } - - return ListView( - children: [ - _ResultCard( - title: 'This integer', - integer: searched, - searchDelegate: this, - ), - _ResultCard( - title: 'Next integer', - integer: searched + 1, - searchDelegate: this, - ), - _ResultCard( - title: 'Previous integer', - integer: searched - 1, - searchDelegate: this, - ), - ], - ); - } - - @override - List buildActions(BuildContext context) { - return [ - if (query.isEmpty) - IconButton( - tooltip: 'Voice Search', - icon: const Icon(Icons.mic), - onPressed: () { - query = 'TODO: implement voice input'; - }, - ) - else - IconButton( - tooltip: 'Clear', - icon: const Icon(Icons.clear), - onPressed: () { - query = ''; - showSuggestions(context); - }, - ), - ]; - } -} - -class _ResultCard extends StatelessWidget { - const _ResultCard({this.integer, this.title, this.searchDelegate}); - - final int integer; - final String title; - final SearchDelegate searchDelegate; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return GestureDetector( - onTap: () { - searchDelegate.close(context, integer); - }, - child: Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Text(title), - Text( - '$integer', - style: theme.textTheme.headline.copyWith(fontSize: 72.0), - ), - ], - ), - ), - ), - ); - } -} - -class _SuggestionList extends StatelessWidget { - const _SuggestionList({this.suggestions, this.query, this.onSelected}); - - final List suggestions; - final String query; - final ValueChanged onSelected; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return ListView.builder( - itemCount: suggestions.length, - itemBuilder: (BuildContext context, int i) { - final String suggestion = suggestions[i]; - return ListTile( - leading: query.isEmpty ? const Icon(Icons.history) : const Icon(null), - title: RichText( - text: TextSpan( - text: suggestion.substring(0, query.length), - style: theme.textTheme.subhead.copyWith(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: suggestion.substring(query.length), - style: theme.textTheme.subhead, - ), - ], - ), - ), - onTap: () { - onSelected(suggestion); - }, - ); - }, - ); - } -} diff --git a/web/gallery/lib/demo/material/selection_controls_demo.dart b/web/gallery/lib/demo/material/selection_controls_demo.dart deleted file mode 100644 index 531ca2924..000000000 --- a/web/gallery/lib/demo/material/selection_controls_demo.dart +++ /dev/null @@ -1,205 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const String _checkboxText = - 'Checkboxes allow the user to select multiple options from a set. ' - 'A normal checkbox\'s value is true or false and a tristate checkbox\'s ' - 'value can also be null.'; - -const String _checkboxCode = 'selectioncontrols_checkbox'; - -const String _radioText = - 'Radio buttons allow the user to select one option from a set. Use radio ' - 'buttons for exclusive selection if you think that the user needs to see ' - 'all available options side-by-side.'; - -const String _radioCode = 'selectioncontrols_radio'; - -const String _switchText = - 'On/off switches toggle the state of a single settings option. The option ' - 'that the switch controls, as well as the state it’s in, should be made ' - 'clear from the corresponding inline label.'; - -const String _switchCode = 'selectioncontrols_switch'; - -class SelectionControlsDemo extends StatefulWidget { - static const String routeName = '/material/selection-controls'; - - @override - _SelectionControlsDemoState createState() => _SelectionControlsDemoState(); -} - -class _SelectionControlsDemoState extends State { - @override - Widget build(BuildContext context) { - final List demos = [ - ComponentDemoTabData( - tabName: 'CHECKBOX', - description: _checkboxText, - demoWidget: buildCheckbox(), - exampleCodeTag: _checkboxCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/Checkbox-class.html', - ), - ComponentDemoTabData( - tabName: 'RADIO', - description: _radioText, - demoWidget: buildRadio(), - exampleCodeTag: _radioCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/Radio-class.html', - ), - ComponentDemoTabData( - tabName: 'SWITCH', - description: _switchText, - demoWidget: buildSwitch(), - exampleCodeTag: _switchCode, - documentationUrl: 'https://docs.flutter.io/flutter/material/Switch-class.html', - ), - ]; - - return TabbedComponentDemoScaffold( - title: 'Selection controls', - demos: demos, - ); - } - - bool checkboxValueA = true; - bool checkboxValueB = false; - bool checkboxValueC; - int radioValue = 0; - bool switchValue = false; - - void handleRadioValueChanged(int value) { - setState(() { - radioValue = value; - }); - } - - Widget buildCheckbox() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Checkbox( - value: checkboxValueA, - onChanged: (bool value) { - setState(() { - checkboxValueA = value; - }); - }, - ), - Checkbox( - value: checkboxValueB, - onChanged: (bool value) { - setState(() { - checkboxValueB = value; - }); - }, - ), - Checkbox( - value: checkboxValueC, - tristate: true, - onChanged: (bool value) { - setState(() { - checkboxValueC = value; - }); - }, - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: const [ - // Disabled checkboxes - Checkbox(value: true, onChanged: null), - Checkbox(value: false, onChanged: null), - Checkbox(value: null, tristate: true, onChanged: null), - ], - ), - ], - ), - ); - } - - Widget buildRadio() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Radio( - value: 0, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - Radio( - value: 1, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - Radio( - value: 2, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - ], - ), - // Disabled radio buttons - Row( - mainAxisSize: MainAxisSize.min, - children: const [ - Radio( - value: 0, - groupValue: 0, - onChanged: null, - ), - Radio( - value: 1, - groupValue: 0, - onChanged: null, - ), - Radio( - value: 2, - groupValue: 0, - onChanged: null, - ), - ], - ), - ], - ), - ); - } - - Widget buildSwitch() { - return Align( - alignment: const Alignment(0.0, -0.2), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Switch.adaptive( - value: switchValue, - onChanged: (bool value) { - setState(() { - switchValue = value; - }); - }, - ), - // Disabled switches - const Switch.adaptive(value: true, onChanged: null), - const Switch.adaptive(value: false, onChanged: null), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/slider_demo.dart b/web/gallery/lib/demo/material/slider_demo.dart deleted file mode 100644 index 3ba93ecc0..000000000 --- a/web/gallery/lib/demo/material/slider_demo.dart +++ /dev/null @@ -1,441 +0,0 @@ -// 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 'package:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -class SliderDemo extends StatefulWidget { - static const String routeName = '/material/slider'; - - @override - _SliderDemoState createState() => _SliderDemoState(); -} - -Path _downTriangle(double size, Offset thumbCenter, { bool invert = false }) { - final Path thumbPath = Path(); - final double height = math.sqrt(3.0) / 2.0; - final double centerHeight = size * height / 3.0; - final double halfSize = size / 2.0; - final double sign = invert ? -1.0 : 1.0; - thumbPath.moveTo(thumbCenter.dx - halfSize, thumbCenter.dy + sign * centerHeight); - thumbPath.lineTo(thumbCenter.dx, thumbCenter.dy - 2.0 * sign * centerHeight); - thumbPath.lineTo(thumbCenter.dx + halfSize, thumbCenter.dy + sign * centerHeight); - thumbPath.close(); - return thumbPath; -} - -Path _rightTriangle(double size, Offset thumbCenter, { bool invert = false }) { - final Path thumbPath = Path(); - final double halfSize = size / 2.0; - final double sign = invert ? -1.0 : 1.0; - thumbPath.moveTo(thumbCenter.dx + halfSize * sign, thumbCenter.dy); - thumbPath.lineTo(thumbCenter.dx - halfSize * sign, thumbCenter.dy - size); - thumbPath.lineTo(thumbCenter.dx - halfSize * sign, thumbCenter.dy + size); - thumbPath.close(); - return thumbPath; -} - -Path _upTriangle(double size, Offset thumbCenter) => _downTriangle(size, thumbCenter, invert: true); - -Path _leftTriangle(double size, Offset thumbCenter) => _rightTriangle(size, thumbCenter, invert: true); - -class _CustomRangeThumbShape extends RangeSliderThumbShape { - static const double _thumbSize = 4.0; - static const double _disabledThumbSize = 3.0; - - @override - Size getPreferredSize(bool isEnabled, bool isDiscrete) { - return isEnabled ? const Size.fromRadius(_thumbSize) : const Size.fromRadius(_disabledThumbSize); - } - - static final Animatable sizeTween = Tween( - begin: _disabledThumbSize, - end: _thumbSize, - ); - - @override - void paint( - PaintingContext context, - Offset center, { - @required Animation activationAnimation, - @required Animation enableAnimation, - bool isDiscrete = false, - bool isEnabled = false, - bool isOnTop, - @required SliderThemeData sliderTheme, - TextDirection textDirection, - Thumb thumb, - }) { - final Canvas canvas = context.canvas; - final ColorTween colorTween = ColorTween( - begin: sliderTheme.disabledThumbColor, - end: sliderTheme.thumbColor, - ); - - final double size = _thumbSize * sizeTween.evaluate(enableAnimation); - Path thumbPath; - switch (textDirection) { - case TextDirection.rtl: - switch (thumb) { - case Thumb.start: - thumbPath = _rightTriangle(size, center); - break; - case Thumb.end: - thumbPath = _leftTriangle(size, center); - break; - } - break; - case TextDirection.ltr: - switch (thumb) { - case Thumb.start: - thumbPath = _leftTriangle(size, center); - break; - case Thumb.end: - thumbPath = _rightTriangle(size, center); - break; - } - break; - } - canvas.drawPath(thumbPath, Paint()..color = colorTween.evaluate(enableAnimation)); - } -} - -class _CustomThumbShape extends SliderComponentShape { - static const double _thumbSize = 4.0; - static const double _disabledThumbSize = 3.0; - - @override - Size getPreferredSize(bool isEnabled, bool isDiscrete) { - return isEnabled ? const Size.fromRadius(_thumbSize) : const Size.fromRadius(_disabledThumbSize); - } - - static final Animatable sizeTween = Tween( - begin: _disabledThumbSize, - end: _thumbSize, - ); - - @override - void paint( - PaintingContext context, - Offset thumbCenter, { - Animation activationAnimation, - Animation enableAnimation, - bool isDiscrete, - TextPainter labelPainter, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, - }) { - final Canvas canvas = context.canvas; - final ColorTween colorTween = ColorTween( - begin: sliderTheme.disabledThumbColor, - end: sliderTheme.thumbColor, - ); - final double size = _thumbSize * sizeTween.evaluate(enableAnimation); - final Path thumbPath = _downTriangle(size, thumbCenter); - canvas.drawPath(thumbPath, Paint()..color = colorTween.evaluate(enableAnimation)); - } -} - -class _CustomValueIndicatorShape extends SliderComponentShape { - static const double _indicatorSize = 4.0; - static const double _disabledIndicatorSize = 3.0; - static const double _slideUpHeight = 40.0; - - @override - Size getPreferredSize(bool isEnabled, bool isDiscrete) { - return Size.fromRadius(isEnabled ? _indicatorSize : _disabledIndicatorSize); - } - - static final Animatable sizeTween = Tween( - begin: _disabledIndicatorSize, - end: _indicatorSize, - ); - - @override - void paint( - PaintingContext context, - Offset thumbCenter, { - Animation activationAnimation, - Animation enableAnimation, - bool isDiscrete, - TextPainter labelPainter, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, - }) { - final Canvas canvas = context.canvas; - final ColorTween enableColor = ColorTween( - begin: sliderTheme.disabledThumbColor, - end: sliderTheme.valueIndicatorColor, - ); - final Tween slideUpTween = Tween( - begin: 0.0, - end: _slideUpHeight, - ); - final double size = _indicatorSize * sizeTween.evaluate(enableAnimation); - final Offset slideUpOffset = Offset(0.0, -slideUpTween.evaluate(activationAnimation)); - final Path thumbPath = _upTriangle(size, thumbCenter + slideUpOffset); - final Color paintColor = enableColor.evaluate(enableAnimation).withAlpha((255.0 * activationAnimation.value).round()); - canvas.drawPath( - thumbPath, - Paint()..color = paintColor, - ); - canvas.drawLine( - thumbCenter, - thumbCenter + slideUpOffset, - Paint() - ..color = paintColor - ..style = PaintingStyle.stroke - ..strokeWidth = 2.0); - labelPainter.paint(canvas, thumbCenter + slideUpOffset + Offset(-labelPainter.width / 2.0, -labelPainter.height - 4.0)); - } -} - -class _SliderDemoState extends State { - @override - Widget build(BuildContext context) { - final List demos = [ - ComponentDemoTabData( - tabName: 'SINGLE', - description: 'Sliders containing 1 thumb', - demoWidget: _Sliders(), - documentationUrl: 'https://docs.flutter.io/flutter/material/Slider-class.html', - ), - ComponentDemoTabData( - tabName: 'RANGE', - description: 'Sliders containing 2 thumbs', - demoWidget: _RangeSliders(), - documentationUrl: 'https://docs.flutter.io/flutter/material/RangeSlider-class.html', - ), - ]; - - return TabbedComponentDemoScaffold( - title: 'Sliders', - demos: demos, - isScrollable: false, - showExampleCodeAction: false, - ); - } -} - -class _Sliders extends StatefulWidget { - @override - _SlidersState createState() => _SlidersState(); -} - -class _SlidersState extends State<_Sliders> { - double _continuousValue = 25.0; - double _discreteValue = 20.0; - double _discreteCustomValue = 25.0; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Semantics( - label: 'Editable numerical value', - child: SizedBox( - width: 64, - height: 48, - child: TextField( - textAlign: TextAlign.center, - onSubmitted: (String value) { - final double newValue = double.tryParse(value); - if (newValue != null && newValue != _continuousValue) { - setState(() { - _continuousValue = newValue.clamp(0, 100); - }); - } - }, - keyboardType: TextInputType.number, - controller: TextEditingController( - text: _continuousValue.toStringAsFixed(0), - ), - ), - ), - ), - Slider.adaptive( - value: _continuousValue, - min: 0.0, - max: 100.0, - onChanged: (double value) { - setState(() { - _continuousValue = value; - }); - }, - ), - const Text('Continuous with Editable Numerical Value'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: const [ - Slider.adaptive(value: 0.25, onChanged: null), - Text('Disabled'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Slider.adaptive( - value: _discreteValue, - min: 0.0, - max: 200.0, - divisions: 5, - label: '${_discreteValue.round()}', - onChanged: (double value) { - setState(() { - _discreteValue = value; - }); - }, - ), - const Text('Discrete'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - SliderTheme( - data: theme.sliderTheme.copyWith( - activeTrackColor: Colors.deepPurple, - inactiveTrackColor: theme.colorScheme.onSurface.withOpacity(0.5), - activeTickMarkColor: theme.colorScheme.onSurface.withOpacity(0.7), - inactiveTickMarkColor: theme.colorScheme.surface.withOpacity(0.7), - overlayColor: theme.colorScheme.onSurface.withOpacity(0.12), - thumbColor: Colors.deepPurple, - valueIndicatorColor: Colors.deepPurpleAccent, - thumbShape: _CustomThumbShape(), - valueIndicatorShape: _CustomValueIndicatorShape(), - valueIndicatorTextStyle: theme.accentTextTheme.body2.copyWith(color: theme.colorScheme.onSurface), - ), - child: Slider( - value: _discreteCustomValue, - min: 0.0, - max: 200.0, - divisions: 5, - semanticFormatterCallback: (double value) => value.round().toString(), - label: '${_discreteCustomValue.round()}', - onChanged: (double value) { - setState(() { - _discreteCustomValue = value; - }); - }, - ), - ), - const Text('Discrete with Custom Theme'), - ], - ), - ], - ), - ); - } -} - -class _RangeSliders extends StatefulWidget { - @override - _RangeSlidersState createState() => _RangeSlidersState(); -} - -class _RangeSlidersState extends State<_RangeSliders> { - RangeValues _continuousValues = const RangeValues(25.0, 75.0); - RangeValues _discreteValues = const RangeValues(40.0, 120.0); - RangeValues _discreteCustomValues = const RangeValues(40.0, 160.0); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - RangeSlider( - values: _continuousValues, - min: 0.0, - max: 100.0, - onChanged: (RangeValues values) { - setState(() { - _continuousValues = values; - }); - }, - ), - const Text('Continuous'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - RangeSlider(values: const RangeValues(0.25, 0.75), onChanged: null), - const Text('Disabled'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - RangeSlider( - values: _discreteValues, - min: 0.0, - max: 200.0, - divisions: 5, - labels: RangeLabels('${_discreteValues.start.round()}', '${_discreteValues.end.round()}'), - onChanged: (RangeValues values) { - setState(() { - _discreteValues = values; - }); - }, - ), - const Text('Discrete'), - ], - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - SliderTheme( - data: SliderThemeData( - activeTrackColor: Colors.deepPurple, - inactiveTrackColor: Colors.black26, - activeTickMarkColor: Colors.white70, - inactiveTickMarkColor: Colors.black, - overlayColor: Colors.black12, - thumbColor: Colors.deepPurple, - rangeThumbShape: _CustomRangeThumbShape(), - showValueIndicator: ShowValueIndicator.never, - ), - child: RangeSlider( - values: _discreteCustomValues, - min: 0.0, - max: 200.0, - divisions: 5, - labels: RangeLabels('${_discreteCustomValues.start.round()}', '${_discreteCustomValues.end.round()}'), - onChanged: (RangeValues values) { - setState(() { - _discreteCustomValues = values; - }); - }, - ), - ), - const Text('Discrete with Custom Theme'), - ], - ), - ], - ), - ); - } -} - diff --git a/web/gallery/lib/demo/material/snack_bar_demo.dart b/web/gallery/lib/demo/material/snack_bar_demo.dart deleted file mode 100644 index 891d8d757..000000000 --- a/web/gallery/lib/demo/material/snack_bar_demo.dart +++ /dev/null @@ -1,95 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -const String _text1 = - 'Snackbars provide lightweight feedback about an operation by ' - 'showing a brief message at the bottom of the screen. Snackbars ' - 'can contain an action.'; - -const String _text2 = - 'Snackbars should contain a single line of text directly related ' - 'to the operation performed. They cannot contain icons.'; - -const String _text3 = - 'By default snackbars automatically disappear after a few seconds '; - -class SnackBarDemo extends StatefulWidget { - const SnackBarDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/snack-bar'; - - @override - _SnackBarDemoState createState() => _SnackBarDemoState(); -} - -class _SnackBarDemoState extends State { - int _snackBarIndex = 1; - - Widget buildBody(BuildContext context) { - return SafeArea( - top: false, - bottom: false, - child: ListView( - padding: const EdgeInsets.all(24.0), - children: [ - const Text(_text1), - const Text(_text2), - Center( - child: RaisedButton( - child: const Text('SHOW A SNACKBAR'), - onPressed: () { - final int thisSnackBarIndex = _snackBarIndex++; - Scaffold.of(context).showSnackBar(SnackBar( - content: Text('This is snackbar #$thisSnackBarIndex.'), - action: SnackBarAction( - label: 'ACTION', - onPressed: () { - Scaffold.of(context).showSnackBar(SnackBar( - content: Text('You pressed snackbar $thisSnackBarIndex\'s action.'), - )); - }, - ), - )); - }, - ), - ), - const Text(_text3), - ] - .map((Widget child) { - return Container( - margin: const EdgeInsets.symmetric(vertical: 12.0), - child: child, - ); - }) - .toList(), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Snackbar'), - actions: [MaterialDemoDocumentationButton(SnackBarDemo.routeName)], - ), - body: Builder( - // Create an inner BuildContext so that the snackBar onPressed methods - // can refer to the Scaffold with Scaffold.of(). - builder: buildBody - ), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.add), - tooltip: 'Create', - onPressed: () { - print('Floating Action Button was pressed'); - }, - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/tabs_demo.dart b/web/gallery/lib/demo/material/tabs_demo.dart deleted file mode 100644 index a9064b151..000000000 --- a/web/gallery/lib/demo/material/tabs_demo.dart +++ /dev/null @@ -1,216 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -// Each TabBarView contains a _Page and for each _Page there is a list -// of _CardData objects. Each _CardData object is displayed by a _CardItem. - -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; - -class _Page { - _Page({ this.label }); - final String label; - String get id => label[0]; - @override - String toString() => '$runtimeType("$label")'; -} - -class _CardData { - const _CardData({ this.title, this.imageAsset, this.imageAssetPackage }); - final String title; - final String imageAsset; - final String imageAssetPackage; -} - -final Map<_Page, List<_CardData>> _allPages = <_Page, List<_CardData>>{ - _Page(label: 'HOME'): <_CardData>[ - const _CardData( - title: 'Flatwear', - imageAsset: 'products/flatwear.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Pine Table', - imageAsset: 'products/table.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Blue Cup', - imageAsset: 'products/cup.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Tea Set', - imageAsset: 'products/teaset.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Desk Set', - imageAsset: 'products/deskset.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Blue Linen Napkins', - imageAsset: 'products/napkins.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Planters', - imageAsset: 'products/planters.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Kitchen Quattro', - imageAsset: 'products/kitchen_quattro.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Platter', - imageAsset: 'products/platter.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - ], - _Page(label: 'APPAREL'): <_CardData>[ - const _CardData( - title: 'Cloud-White Dress', - imageAsset: 'products/dress.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Ginger Scarf', - imageAsset: 'products/scarf.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - const _CardData( - title: 'Blush Sweats', - imageAsset: 'products/sweats.png', - imageAssetPackage: _kGalleryAssetsPackage, - ), - ], -}; - -class _CardDataItem extends StatelessWidget { - const _CardDataItem({ this.page, this.data }); - - static const double height = 272.0; - final _Page page; - final _CardData data; - - @override - Widget build(BuildContext context) { - return Card( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Align( - alignment: page.id == 'H' - ? Alignment.centerLeft - : Alignment.centerRight, - child: CircleAvatar(child: Text('${page.id}')), - ), - SizedBox( - width: 144.0, - height: 144.0, - child: Image.asset( - data.imageAsset, - package: data.imageAssetPackage, - fit: BoxFit.contain, - ), - ), - Center( - child: Text( - data.title, - style: Theme.of(context).textTheme.title, - ), - ), - ], - ), - ), - ); - } -} - -class TabsDemo extends StatelessWidget { - static const String routeName = '/material/tabs'; - - @override - Widget build(BuildContext context) { - return DefaultTabController( - length: _allPages.length, - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - child: SliverAppBar( - title: const Text('Tabs and scrolling'), - actions: [MaterialDemoDocumentationButton(routeName)], - pinned: true, - expandedHeight: 150.0, - forceElevated: innerBoxIsScrolled, - bottom: TabBar( - tabs: _allPages.keys.map( - (_Page page) => Tab(text: page.label), - ).toList(), - ), - ), - ), - ]; - }, - body: TabBarView( - children: _allPages.keys.map((_Page page) { - return SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (BuildContext context) { - return CustomScrollView( - key: PageStorageKey<_Page>(page), - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - SliverPadding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - sliver: SliverFixedExtentList( - itemExtent: _CardDataItem.height, - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - final _CardData data = _allPages[page][index]; - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - ), - child: _CardDataItem( - page: page, - data: data, - ), - ); - }, - childCount: _allPages[page].length, - ), - ), - ), - ], - ); - }, - ), - ); - }).toList(), - ), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/tabs_fab_demo.dart b/web/gallery/lib/demo/material/tabs_fab_demo.dart deleted file mode 100644 index 51a2e2fb8..000000000 --- a/web/gallery/lib/demo/material/tabs_fab_demo.dart +++ /dev/null @@ -1,160 +0,0 @@ -// 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:flutter/material.dart'; - -import '../../gallery/demo.dart'; - -const String _explanatoryText = - "When the Scaffold's floating action button changes, the new button fades and " - 'turns into view. In this demo, changing tabs can cause the app to be rebuilt ' - 'with a FloatingActionButton that the Scaffold distinguishes from the others ' - 'by its key.'; - -class _Page { - _Page({ this.label, this.colors, this.icon }); - - final String label; - final MaterialColor colors; - final IconData icon; - - Color get labelColor => colors != null ? colors.shade300 : Colors.grey.shade300; - bool get fabDefined => colors != null && icon != null; - Color get fabColor => colors.shade400; - Icon get fabIcon => Icon(icon); - Key get fabKey => ValueKey(fabColor); -} - -final List<_Page> _allPages = <_Page>[ - _Page(label: 'Blue', colors: Colors.indigo, icon: Icons.add), - _Page(label: 'Eco', colors: Colors.green, icon: Icons.create), - _Page(label: 'No'), - _Page(label: 'Teal', colors: Colors.teal, icon: Icons.add), - _Page(label: 'Red', colors: Colors.red, icon: Icons.create), -]; - -class TabsFabDemo extends StatefulWidget { - static const String routeName = '/material/tabs-fab'; - - @override - _TabsFabDemoState createState() => _TabsFabDemoState(); -} - -class _TabsFabDemoState extends State with SingleTickerProviderStateMixin { - final GlobalKey _scaffoldKey = GlobalKey(); - - TabController _controller; - _Page _selectedPage; - bool _extendedButtons = false; - - @override - void initState() { - super.initState(); - _controller = TabController(vsync: this, length: _allPages.length); - _controller.addListener(_handleTabSelection); - _selectedPage = _allPages[0]; - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _handleTabSelection() { - setState(() { - _selectedPage = _allPages[_controller.index]; - }); - } - - void _showExplanatoryText() { - _scaffoldKey.currentState.showBottomSheet((BuildContext context) { - return Container( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Theme.of(context).dividerColor)) - ), - child: Padding( - padding: const EdgeInsets.all(32.0), - child: Text(_explanatoryText, style: Theme.of(context).textTheme.subhead), - ), - ); - }); - } - - Widget buildTabView(_Page page) { - return Builder( - builder: (BuildContext context) { - return Container( - key: ValueKey(page.label), - padding: const EdgeInsets.fromLTRB(48.0, 48.0, 48.0, 96.0), - child: Card( - child: Center( - child: Text(page.label, - style: TextStyle( - color: page.labelColor, - fontSize: 32.0, - ), - textAlign: TextAlign.center, - ), - ), - ), - ); - } - ); - } - - Widget buildFloatingActionButton(_Page page) { - if (!page.fabDefined) - return null; - - if (_extendedButtons) { - return FloatingActionButton.extended( - key: ValueKey(page.fabKey), - tooltip: 'Show explanation', - backgroundColor: page.fabColor, - icon: page.fabIcon, - label: Text(page.label.toUpperCase()), - onPressed: _showExplanatoryText, - ); - } - - return FloatingActionButton( - key: page.fabKey, - tooltip: 'Show explanation', - backgroundColor: page.fabColor, - child: page.fabIcon, - onPressed: _showExplanatoryText, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: AppBar( - title: const Text('FAB per tab'), - bottom: TabBar( - controller: _controller, - tabs: _allPages.map((_Page page) => Tab(text: page.label.toUpperCase())).toList(), - ), - actions: [ - MaterialDemoDocumentationButton(TabsFabDemo.routeName), - IconButton( - icon: const Icon(Icons.sentiment_very_satisfied, semanticLabel: 'Toggle extended buttons'), - onPressed: () { - setState(() { - _extendedButtons = !_extendedButtons; - }); - }, - ), - ], - ), - floatingActionButton: buildFloatingActionButton(_selectedPage), - body: TabBarView( - controller: _controller, - children: _allPages.map(buildTabView).toList(), - ), - ); - } -} diff --git a/web/gallery/lib/demo/material/text_form_field_demo.dart b/web/gallery/lib/demo/material/text_form_field_demo.dart deleted file mode 100644 index d69e9313b..000000000 --- a/web/gallery/lib/demo/material/text_form_field_demo.dart +++ /dev/null @@ -1,344 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/gestures.dart' show DragStartBehavior; - -import '../../gallery/demo.dart'; - -class TextFormFieldDemo extends StatefulWidget { - const TextFormFieldDemo({ Key key }) : super(key: key); - - static const String routeName = '/material/text-form-field'; - - @override - TextFormFieldDemoState createState() => TextFormFieldDemoState(); -} - -class PersonData { - String name = ''; - String phoneNumber = ''; - String email = ''; - String password = ''; -} - -class PasswordField extends StatefulWidget { - const PasswordField({ - this.fieldKey, - this.hintText, - this.labelText, - this.helperText, - this.onSaved, - this.validator, - this.onFieldSubmitted, - }); - - final Key fieldKey; - final String hintText; - final String labelText; - final String helperText; - final FormFieldSetter onSaved; - final FormFieldValidator validator; - final ValueChanged onFieldSubmitted; - - @override - _PasswordFieldState createState() => _PasswordFieldState(); -} - -class _PasswordFieldState extends State { - bool _obscureText = true; - - @override - Widget build(BuildContext context) { - return TextFormField( - key: widget.fieldKey, - obscureText: _obscureText, - maxLength: 8, - onSaved: widget.onSaved, - validator: widget.validator, - onFieldSubmitted: widget.onFieldSubmitted, - decoration: InputDecoration( - border: const UnderlineInputBorder(), - filled: true, - hintText: widget.hintText, - labelText: widget.labelText, - helperText: widget.helperText, - suffixIcon: GestureDetector( - dragStartBehavior: DragStartBehavior.down, - onTap: () { - setState(() { - _obscureText = !_obscureText; - }); - }, - child: Icon( - _obscureText ? Icons.visibility : Icons.visibility_off, - semanticLabel: _obscureText ? 'show password' : 'hide password', - ), - ), - ), - ); - } -} - -class TextFormFieldDemoState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - PersonData person = PersonData(); - - void showInSnackBar(String value) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - content: Text(value), - )); - } - - bool _autovalidate = false; - bool _formWasEdited = false; - - final GlobalKey _formKey = GlobalKey(); - final GlobalKey> _passwordFieldKey = GlobalKey>(); - final _UsNumberTextInputFormatter _phoneNumberFormatter = _UsNumberTextInputFormatter(); - void _handleSubmitted() { - final FormState form = _formKey.currentState; - if (!form.validate()) { - _autovalidate = true; // Start validating on every change. - showInSnackBar('Please fix the errors in red before submitting.'); - } else { - form.save(); - showInSnackBar('${person.name}\'s phone number is ${person.phoneNumber}'); - } - } - - String _validateName(String value) { - _formWasEdited = true; - if (value.isEmpty) - return 'Name is required.'; - final RegExp nameExp = RegExp(r'^[A-Za-z ]+$'); - if (!nameExp.hasMatch(value)) - return 'Please enter only alphabetical characters.'; - return null; - } - - String _validatePhoneNumber(String value) { - _formWasEdited = true; - final RegExp phoneExp = RegExp(r'^\(\d\d\d\) \d\d\d\-\d\d\d\d$'); - if (!phoneExp.hasMatch(value)) - return '(###) ###-#### - Enter a US phone number.'; - return null; - } - - String _validatePassword(String value) { - _formWasEdited = true; - final FormFieldState passwordField = _passwordFieldKey.currentState; - if (passwordField.value == null || passwordField.value.isEmpty) - return 'Please enter a password.'; - if (passwordField.value != value) - return 'The passwords don\'t match'; - return null; - } - - Future _warnUserAboutInvalidData() async { - final FormState form = _formKey.currentState; - if (form == null || !_formWasEdited || form.validate()) - return true; - - return await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('This form has errors'), - content: const Text('Really leave this form?'), - actions: [ - FlatButton( - child: const Text('YES'), - onPressed: () { Navigator.of(context).pop(true); }, - ), - FlatButton( - child: const Text('NO'), - onPressed: () { Navigator.of(context).pop(false); }, - ), - ], - ); - }, - ) ?? false; - } - - @override - Widget build(BuildContext context) { - return Scaffold( - drawerDragStartBehavior: DragStartBehavior.down, - key: _scaffoldKey, - appBar: AppBar( - title: const Text('Text fields'), - actions: [MaterialDemoDocumentationButton(TextFormFieldDemo.routeName)], - ), - body: SafeArea( - top: false, - bottom: false, - child: Form( - key: _formKey, - autovalidate: _autovalidate, - onWillPop: _warnUserAboutInvalidData, - child: Scrollbar( - child: SingleChildScrollView( - dragStartBehavior: DragStartBehavior.down, - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const SizedBox(height: 24.0), - TextFormField( - textCapitalization: TextCapitalization.words, - decoration: const InputDecoration( - border: UnderlineInputBorder(), - filled: true, - icon: Icon(Icons.person), - hintText: 'What do people call you?', - labelText: 'Name *', - ), - onSaved: (String value) { person.name = value; }, - validator: _validateName, - ), - const SizedBox(height: 24.0), - TextFormField( - decoration: const InputDecoration( - border: UnderlineInputBorder(), - filled: true, - icon: Icon(Icons.phone), - hintText: 'Where can we reach you?', - labelText: 'Phone Number *', - prefixText: '+1', - ), - keyboardType: TextInputType.phone, - onSaved: (String value) { person.phoneNumber = value; }, - validator: _validatePhoneNumber, - // TextInputFormatters are applied in sequence. - inputFormatters: [ - WhitelistingTextInputFormatter.digitsOnly, - // Fit the validating format. - _phoneNumberFormatter, - ], - ), - const SizedBox(height: 24.0), - TextFormField( - decoration: const InputDecoration( - border: UnderlineInputBorder(), - filled: true, - icon: Icon(Icons.email), - hintText: 'Your email address', - labelText: 'E-mail', - ), - keyboardType: TextInputType.emailAddress, - onSaved: (String value) { person.email = value; }, - ), - const SizedBox(height: 24.0), - TextFormField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Tell us about yourself (e.g., write down what you do or what hobbies you have)', - helperText: 'Keep it short, this is just a demo.', - labelText: 'Life story', - ), - maxLines: 3, - ), - const SizedBox(height: 24.0), - TextFormField( - keyboardType: TextInputType.number, - decoration: const InputDecoration( - border: OutlineInputBorder(), - labelText: 'Salary', - prefixText: '\$', - suffixText: 'USD', - suffixStyle: TextStyle(color: Colors.green), - ), - maxLines: 1, - ), - const SizedBox(height: 24.0), - PasswordField( - fieldKey: _passwordFieldKey, - helperText: 'No more than 8 characters.', - labelText: 'Password *', - onFieldSubmitted: (String value) { - setState(() { - person.password = value; - }); - }, - ), - const SizedBox(height: 24.0), - TextFormField( - enabled: person.password != null && person.password.isNotEmpty, - decoration: const InputDecoration( - border: UnderlineInputBorder(), - filled: true, - labelText: 'Re-type password', - ), - maxLength: 8, - obscureText: true, - validator: _validatePassword, - ), - const SizedBox(height: 24.0), - Center( - child: RaisedButton( - child: const Text('SUBMIT'), - onPressed: _handleSubmitted, - ), - ), - const SizedBox(height: 24.0), - Text( - '* indicates required field', - style: Theme.of(context).textTheme.caption, - ), - const SizedBox(height: 24.0), - ], - ), - ), - ), - ), - ), - ); - } -} - -/// Format incoming numeric text to fit the format of (###) ###-#### ##... -class _UsNumberTextInputFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, - TextEditingValue newValue, - ) { - final int newTextLength = newValue.text.length; - int selectionIndex = newValue.selection.end; - int usedSubstringIndex = 0; - final StringBuffer newText = StringBuffer(); - if (newTextLength >= 1) { - newText.write('('); - if (newValue.selection.end >= 1) - selectionIndex++; - } - if (newTextLength >= 4) { - newText.write(newValue.text.substring(0, usedSubstringIndex = 3) + ') '); - if (newValue.selection.end >= 3) - selectionIndex += 2; - } - if (newTextLength >= 7) { - newText.write(newValue.text.substring(3, usedSubstringIndex = 6) + '-'); - if (newValue.selection.end >= 6) - selectionIndex++; - } - if (newTextLength >= 11) { - newText.write(newValue.text.substring(6, usedSubstringIndex = 10) + ' '); - if (newValue.selection.end >= 10) - selectionIndex++; - } - // Dump the rest. - if (newTextLength >= usedSubstringIndex) - newText.write(newValue.text.substring(usedSubstringIndex)); - return TextEditingValue( - text: newText.toString(), - selection: TextSelection.collapsed(offset: selectionIndex), - ); - } -} diff --git a/web/gallery/lib/demo/material/tooltip_demo.dart b/web/gallery/lib/demo/material/tooltip_demo.dart deleted file mode 100644 index 40974a176..000000000 --- a/web/gallery/lib/demo/material/tooltip_demo.dart +++ /dev/null @@ -1,75 +0,0 @@ -// 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 '../../gallery/demo.dart'; - -const String _introText = - 'Tooltips are short identifying messages that briefly appear in response to ' - 'a long press. Tooltip messages are also used by services that make Flutter ' - 'apps accessible, like screen readers.'; - -class TooltipDemo extends StatelessWidget { - - static const String routeName = '/material/tooltips'; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return Scaffold( - appBar: AppBar( - title: const Text('Tooltips'), - actions: [MaterialDemoDocumentationButton(routeName)], - ), - body: Builder( - builder: (BuildContext context) { - return SafeArea( - top: false, - bottom: false, - child: ListView( - children: [ - Text(_introText, style: theme.textTheme.subhead), - Row( - children: [ - Text('Long press the ', style: theme.textTheme.subhead), - Tooltip( - message: 'call icon', - child: Icon( - Icons.call, - size: 18.0, - color: theme.iconTheme.color, - ), - ), - Text(' icon.', style: theme.textTheme.subhead), - ], - ), - Center( - child: IconButton( - iconSize: 48.0, - icon: const Icon(Icons.call), - color: theme.iconTheme.color, - tooltip: 'Place a phone call', - onPressed: () { - Scaffold.of(context).showSnackBar(const SnackBar( - content: Text('That was an ordinary tap.'), - )); - }, - ), - ), - ] - .map((Widget widget) { - return Padding( - padding: const EdgeInsets.only(top: 16.0, left: 16.0, right: 16.0), - child: widget, - ); - }) - .toList(), - ), - ); - } - ), - ); - } -} diff --git a/web/gallery/lib/demo/pesto_demo.dart b/web/gallery/lib/demo/pesto_demo.dart deleted file mode 100644 index cff30f068..000000000 --- a/web/gallery/lib/demo/pesto_demo.dart +++ /dev/null @@ -1,715 +0,0 @@ -// 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/rendering.dart'; - -class PestoDemo extends StatelessWidget { - const PestoDemo({ Key key }) : super(key: key); - - static const String routeName = '/pesto'; - - @override - Widget build(BuildContext context) => PestoHome(); -} - - -const String _kSmallLogoImage = 'logos/pesto/logo_small.png'; -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; -const double _kAppBarHeight = 128.0; -const double _kFabHalfSize = 28.0; // TODO(mpcomplete): needs to adapt to screen size -const double _kRecipePageMaxWidth = 500.0; - -final Set _favoriteRecipes = {}; - -final ThemeData _kTheme = ThemeData( - brightness: Brightness.light, - primarySwatch: Colors.teal, - accentColor: Colors.redAccent, -); - -class PestoHome extends StatelessWidget { - @override - Widget build(BuildContext context) { - return const RecipeGridPage(recipes: kPestoRecipes); - } -} - -class PestoFavorites extends StatelessWidget { - @override - Widget build(BuildContext context) { - return RecipeGridPage(recipes: _favoriteRecipes.toList()); - } -} - -class PestoStyle extends TextStyle { - const PestoStyle({ - double fontSize = 12.0, - FontWeight fontWeight, - Color color = Colors.black87, - double letterSpacing, - double height, - }) : super( - inherit: false, - color: color, - fontFamily: 'Raleway', - fontSize: fontSize, - fontWeight: fontWeight, - textBaseline: TextBaseline.alphabetic, - letterSpacing: letterSpacing, - height: height, - ); -} - -// Displays a grid of recipe cards. -class RecipeGridPage extends StatefulWidget { - const RecipeGridPage({ Key key, this.recipes }) : super(key: key); - - final List recipes; - - @override - _RecipeGridPageState createState() => _RecipeGridPageState(); -} - -class _RecipeGridPageState extends State { - final GlobalKey scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - final double statusBarHeight = MediaQuery.of(context).padding.top; - return Theme( - data: _kTheme.copyWith(platform: Theme.of(context).platform), - child: Scaffold( - key: scaffoldKey, - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.edit), - onPressed: () { - scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Not supported.'), - )); - }, - ), - body: CustomScrollView( - semanticChildCount: widget.recipes.length, - slivers: [ - _buildAppBar(context, statusBarHeight), - _buildBody(context, statusBarHeight), - ], - ), - ), - ); - } - - Widget _buildAppBar(BuildContext context, double statusBarHeight) { - return SliverAppBar( - pinned: true, - expandedHeight: _kAppBarHeight, - actions: [ - IconButton( - icon: const Icon(Icons.search), - tooltip: 'Search', - onPressed: () { - scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Not supported.'), - )); - }, - ), - ], - flexibleSpace: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - final Size size = constraints.biggest; - final double appBarHeight = size.height - statusBarHeight; - final double t = (appBarHeight - kToolbarHeight) / (_kAppBarHeight - kToolbarHeight); - final double extraPadding = Tween(begin: 10.0, end: 24.0).transform(t); - final double logoHeight = appBarHeight - 1.5 * extraPadding; - return Padding( - padding: EdgeInsets.only( - top: statusBarHeight + 0.5 * extraPadding, - bottom: extraPadding, - ), - child: Center( - child: PestoLogo(height: logoHeight, t: t.clamp(0.0, 1.0)), - ), - ); - }, - ), - ); - } - - Widget _buildBody(BuildContext context, double statusBarHeight) { - final EdgeInsets mediaPadding = MediaQuery.of(context).padding; - final EdgeInsets padding = EdgeInsets.only( - top: 8.0, - left: 8.0 + mediaPadding.left, - right: 8.0 + mediaPadding.right, - bottom: 8.0, - ); - return SliverPadding( - padding: padding, - sliver: SliverGrid( - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: _kRecipePageMaxWidth, - crossAxisSpacing: 8.0, - mainAxisSpacing: 8.0, - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - final Recipe recipe = widget.recipes[index]; - return RecipeCard( - recipe: recipe, - onTap: () { showRecipePage(context, recipe); }, - ); - }, - childCount: widget.recipes.length, - ), - ), - ); - } - - void showFavoritesPage(BuildContext context) { - Navigator.push(context, MaterialPageRoute( - settings: const RouteSettings(name: '/pesto/favorites'), - builder: (BuildContext context) => PestoFavorites(), - )); - } - - void showRecipePage(BuildContext context, Recipe recipe) { - Navigator.push(context, MaterialPageRoute( - settings: const RouteSettings(name: '/pesto/recipe'), - builder: (BuildContext context) { - return Theme( - data: _kTheme.copyWith(platform: Theme.of(context).platform), - child: RecipePage(recipe: recipe), - ); - }, - )); - } -} - -class PestoLogo extends StatefulWidget { - const PestoLogo({this.height, this.t}); - - final double height; - final double t; - - @override - _PestoLogoState createState() => _PestoLogoState(); -} - -class _PestoLogoState extends State { - // Native sizes for logo and its image/text components. - static const double kLogoHeight = 162.0; - static const double kLogoWidth = 220.0; - static const double kImageHeight = 108.0; - static const double kTextHeight = 48.0; - final TextStyle titleStyle = const PestoStyle(fontSize: kTextHeight, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 3.0); - final RectTween _textRectTween = RectTween( - begin: const Rect.fromLTWH(0.0, kLogoHeight, kLogoWidth, kTextHeight), - end: const Rect.fromLTWH(0.0, kImageHeight, kLogoWidth, kTextHeight), - ); - final Curve _textOpacity = const Interval(0.4, 1.0, curve: Curves.easeInOut); - final RectTween _imageRectTween = RectTween( - begin: const Rect.fromLTWH(0.0, 0.0, kLogoWidth, kLogoHeight), - end: const Rect.fromLTWH(0.0, 0.0, kLogoWidth, kImageHeight), - ); - - @override - Widget build(BuildContext context) { - return Semantics( - namesRoute: true, - child: Transform( - transform: Matrix4.identity()..scale(widget.height / kLogoHeight), - alignment: Alignment.topCenter, - child: SizedBox( - width: kLogoWidth, - child: Stack( - overflow: Overflow.visible, - children: [ - Positioned.fromRect( - rect: _imageRectTween.lerp(widget.t), - child: Image.asset( - _kSmallLogoImage, - package: _kGalleryAssetsPackage, - fit: BoxFit.contain, - ), - ), - Positioned.fromRect( - rect: _textRectTween.lerp(widget.t), - child: Opacity( - opacity: _textOpacity.transform(widget.t), - child: Text('PESTO', style: titleStyle, textAlign: TextAlign.center), - ), - ), - ], - ), - ), - ), - ); - } -} - -// A card with the recipe's image, author, and title. -class RecipeCard extends StatelessWidget { - const RecipeCard({ Key key, this.recipe, this.onTap }) : super(key: key); - - final Recipe recipe; - final VoidCallback onTap; - - TextStyle get titleStyle => const PestoStyle(fontSize: 24.0, fontWeight: FontWeight.w600); - TextStyle get authorStyle => const PestoStyle(fontWeight: FontWeight.w500, color: Colors.black54); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Hero( - tag: 'packages/$_kGalleryAssetsPackage/${recipe.imagePath}', - child: AspectRatio( - aspectRatio: 4.0 / 3.0, - child: Image.asset( - recipe.imagePath, - package: recipe.imagePackage, - fit: BoxFit.cover, - semanticLabel: recipe.name, - ), - ), - ), - Expanded( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Image.asset( - recipe.ingredientsImagePath, - package: recipe.ingredientsImagePackage, - width: 48.0, - height: 48.0, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(recipe.name, style: titleStyle, softWrap: false, overflow: TextOverflow.ellipsis), - Text(recipe.author, style: authorStyle), - ], - ), - ), - ], - ), - ), - ], - ), - ), - ); - } -} - -// Displays one recipe. Includes the recipe sheet with a background image. -class RecipePage extends StatefulWidget { - const RecipePage({ Key key, this.recipe }) : super(key: key); - - final Recipe recipe; - - @override - _RecipePageState createState() => _RecipePageState(); -} - -class _RecipePageState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - final TextStyle menuItemStyle = const PestoStyle(fontSize: 15.0, color: Colors.black54, height: 24.0/15.0); - - double _getAppBarHeight(BuildContext context) => MediaQuery.of(context).size.height * 0.3; - - @override - Widget build(BuildContext context) { - // The full page content with the recipe's image behind it. This - // adjusts based on the size of the screen. If the recipe sheet touches - // the edge of the screen, use a slightly different layout. - final double appBarHeight = _getAppBarHeight(context); - final Size screenSize = MediaQuery.of(context).size; - final bool fullWidth = screenSize.width < _kRecipePageMaxWidth; - final bool isFavorite = _favoriteRecipes.contains(widget.recipe); - return Scaffold( - key: _scaffoldKey, - body: Stack( - children: [ - Positioned( - top: 0.0, - left: 0.0, - right: 0.0, - height: appBarHeight + _kFabHalfSize, - child: Hero( - tag: 'packages/$_kGalleryAssetsPackage/${widget.recipe.imagePath}', - child: Image.asset( - widget.recipe.imagePath, - package: widget.recipe.imagePackage, - fit: fullWidth ? BoxFit.fitWidth : BoxFit.cover, - ), - ), - ), - CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: appBarHeight - _kFabHalfSize, - backgroundColor: Colors.transparent, - actions: [ - PopupMenuButton( - onSelected: (String item) { }, - itemBuilder: (BuildContext context) => >[ - _buildMenuItem(Icons.share, 'Tweet recipe'), - _buildMenuItem(Icons.email, 'Email recipe'), - _buildMenuItem(Icons.message, 'Message recipe'), - _buildMenuItem(Icons.people, 'Share on Facebook'), - ], - ), - ], - flexibleSpace: const FlexibleSpaceBar( - background: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment(0.0, -1.0), - end: Alignment(0.0, -0.2), - colors: [Color(0x60000000), Color(0x00000000)], - ), - ), - ), - ), - ), - SliverToBoxAdapter( - child: Stack( - children: [ - Container( - padding: const EdgeInsets.only(top: _kFabHalfSize), - width: fullWidth ? null : _kRecipePageMaxWidth, - child: RecipeSheet(recipe: widget.recipe), - ), - Positioned( - right: 16.0, - child: FloatingActionButton( - child: Icon(isFavorite ? Icons.favorite : Icons.favorite_border), - onPressed: _toggleFavorite, - ), - ), - ], - ), - ), - ], - ), - ], - ), - ); - } - - PopupMenuItem _buildMenuItem(IconData icon, String label) { - return PopupMenuItem( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 24.0), - child: Icon(icon, color: Colors.black54), - ), - Text(label, style: menuItemStyle), - ], - ), - ); - } - - void _toggleFavorite() { - setState(() { - if (_favoriteRecipes.contains(widget.recipe)) - _favoriteRecipes.remove(widget.recipe); - else - _favoriteRecipes.add(widget.recipe); - }); - } -} - -/// Displays the recipe's name and instructions. -class RecipeSheet extends StatelessWidget { - RecipeSheet({ Key key, this.recipe }) : super(key: key); - - final TextStyle titleStyle = const PestoStyle(fontSize: 34.0); - final TextStyle descriptionStyle = const PestoStyle(fontSize: 15.0, color: Colors.black54, height: 24.0/15.0); - final TextStyle itemStyle = const PestoStyle(fontSize: 15.0, height: 24.0/15.0); - final TextStyle itemAmountStyle = PestoStyle(fontSize: 15.0, color: _kTheme.primaryColor, height: 24.0/15.0); - final TextStyle headingStyle = const PestoStyle(fontSize: 16.0, fontWeight: FontWeight.bold, height: 24.0/15.0); - - final Recipe recipe; - - @override - Widget build(BuildContext context) { - return Material( - child: SafeArea( - top: false, - bottom: false, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 40.0), - child: Table( - columnWidths: const { - 0: FixedColumnWidth(64.0), - }, - children: [ - TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Image.asset( - recipe.ingredientsImagePath, - package: recipe.ingredientsImagePackage, - width: 32.0, - height: 32.0, - alignment: Alignment.centerLeft, - fit: BoxFit.scaleDown, - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Text(recipe.name, style: titleStyle), - ), - ] - ), - TableRow( - children: [ - const SizedBox(), - Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 4.0), - child: Text(recipe.description, style: descriptionStyle), - ), - ] - ), - TableRow( - children: [ - const SizedBox(), - Padding( - padding: const EdgeInsets.only(top: 24.0, bottom: 4.0), - child: Text('Ingredients', style: headingStyle), - ), - ] - ), - ...recipe.ingredients.map((RecipeIngredient ingredient) { - return _buildItemRow(ingredient.amount, ingredient.description); - }), - TableRow( - children: [ - const SizedBox(), - Padding( - padding: const EdgeInsets.only(top: 24.0, bottom: 4.0), - child: Text('Steps', style: headingStyle), - ), - ] - ), - ...recipe.steps.map((RecipeStep step) { - return _buildItemRow(step.duration ?? '', step.description); - }), - ], - ), - ), - ), - ); - } - - TableRow _buildItemRow(String left, String right) { - return TableRow( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text(left, style: itemAmountStyle), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text(right, style: itemStyle), - ), - ], - ); - } -} - -class Recipe { - const Recipe({ - this.name, - this.author, - this.description, - this.imagePath, - this.imagePackage, - this.ingredientsImagePath, - this.ingredientsImagePackage, - this.ingredients, - this.steps, - }); - - final String name; - final String author; - final String description; - final String imagePath; - final String imagePackage; - final String ingredientsImagePath; - final String ingredientsImagePackage; - final List ingredients; - final List steps; -} - -class RecipeIngredient { - const RecipeIngredient({this.amount, this.description}); - - final String amount; - final String description; -} - -class RecipeStep { - const RecipeStep({this.duration, this.description}); - - final String duration; - final String description; -} - -const List kPestoRecipes = [ - Recipe( - name: 'Roasted Chicken', - author: 'Peter Carlsson', - ingredientsImagePath: 'food/icons/main.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'The perfect dish to welcome your family and friends with on a crisp autumn night. Pair with roasted veggies to truly impress them.', - imagePath: 'food/roasted_chicken.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '1 whole', description: 'Chicken'), - RecipeIngredient(amount: '1/2 cup', description: 'Butter'), - RecipeIngredient(amount: '1 tbsp', description: 'Onion powder'), - RecipeIngredient(amount: '1 tbsp', description: 'Freshly ground pepper'), - RecipeIngredient(amount: '1 tsp', description: 'Salt'), - ], - steps: [ - RecipeStep(duration: '1 min', description: 'Put in oven'), - RecipeStep(duration: '1hr 45 min', description: 'Cook'), - ], - ), - Recipe( - name: 'Chopped Beet Leaves', - author: 'Trevor Hansen', - ingredientsImagePath: 'food/icons/veggie.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'This vegetable has more to offer than just its root. Beet greens can be tossed into a salad to add some variety or sauteed on its own with some oil and garlic.', - imagePath: 'food/chopped_beet_leaves.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '3 cups', description: 'Beet greens'), - ], - steps: [ - RecipeStep(duration: '5 min', description: 'Chop'), - ], - ), - Recipe( - name: 'Pesto Pasta', - author: 'Ali Connors', - ingredientsImagePath: 'food/icons/main.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'With this pesto recipe, you can quickly whip up a meal to satisfy your savory needs. And if you\'re feeling festive, you can add bacon to taste.', - imagePath: 'food/pesto_pasta.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '1/4 cup ', description: 'Pasta'), - RecipeIngredient(amount: '2 cups', description: 'Fresh basil leaves'), - RecipeIngredient(amount: '1/2 cup', description: 'Parmesan cheese'), - RecipeIngredient(amount: '1/2 cup', description: 'Extra virgin olive oil'), - RecipeIngredient(amount: '1/3 cup', description: 'Pine nuts'), - RecipeIngredient(amount: '1/4 cup', description: 'Lemon juice'), - RecipeIngredient(amount: '3 cloves', description: 'Garlic'), - RecipeIngredient(amount: '1/4 tsp', description: 'Salt'), - RecipeIngredient(amount: '1/8 tsp', description: 'Pepper'), - RecipeIngredient(amount: '3 lbs', description: 'Bacon'), - ], - steps: [ - RecipeStep(duration: '15 min', description: 'Blend'), - ], - ), - Recipe( - name: 'Cherry Pie', - author: 'Sandra Adams', - ingredientsImagePath: 'food/icons/main.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'Sometimes when you\'re craving some cheer in your life you can jumpstart your day with some cherry pie. Dessert for breakfast is perfectly acceptable.', - imagePath: 'food/cherry_pie.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '1', description: 'Pie crust'), - RecipeIngredient(amount: '4 cups', description: 'Fresh or frozen cherries'), - RecipeIngredient(amount: '1 cup', description: 'Granulated sugar'), - RecipeIngredient(amount: '4 tbsp', description: 'Cornstarch'), - RecipeIngredient(amount: '1½ tbsp', description: 'Butter'), - ], - steps: [ - RecipeStep(duration: '15 min', description: 'Mix'), - RecipeStep(duration: '1hr 30 min', description: 'Bake'), - ], - ), - Recipe( - name: 'Spinach Salad', - author: 'Peter Carlsson', - ingredientsImagePath: 'food/icons/spicy.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'Everyone\'s favorite leafy green is back. Paired with fresh sliced onion, it\'s ready to tackle any dish, whether it be a salad or an egg scramble.', - imagePath: 'food/spinach_onion_salad.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '4 cups', description: 'Spinach'), - RecipeIngredient(amount: '1 cup', description: 'Sliced onion'), - ], - steps: [ - RecipeStep(duration: '5 min', description: 'Mix'), - ], - ), - Recipe( - name: 'Butternut Squash Soup', - author: 'Ali Connors', - ingredientsImagePath: 'food/icons/healthy.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'This creamy butternut squash soup will warm you on the chilliest of winter nights and bring a delightful pop of orange to the dinner table.', - imagePath: 'food/butternut_squash_soup.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '1', description: 'Butternut squash'), - RecipeIngredient(amount: '4 cups', description: 'Chicken stock'), - RecipeIngredient(amount: '2', description: 'Potatoes'), - RecipeIngredient(amount: '1', description: 'Onion'), - RecipeIngredient(amount: '1', description: 'Carrot'), - RecipeIngredient(amount: '1', description: 'Celery'), - RecipeIngredient(amount: '1 tsp', description: 'Salt'), - RecipeIngredient(amount: '1 tsp', description: 'Pepper'), - ], - steps: [ - RecipeStep(duration: '10 min', description: 'Prep vegetables'), - RecipeStep(duration: '5 min', description: 'Stir'), - RecipeStep(duration: '1 hr 10 min', description: 'Cook'), - ], - ), - Recipe( - name: 'Spanakopita', - author: 'Trevor Hansen', - ingredientsImagePath: 'food/icons/quick.png', - ingredientsImagePackage: _kGalleryAssetsPackage, - description: 'You \'feta\' believe this is a crowd-pleaser! Flaky phyllo pastry surrounds a delicious mixture of spinach and cheeses to create the perfect appetizer.', - imagePath: 'food/spanakopita.png', - imagePackage: _kGalleryAssetsPackage, - ingredients: [ - RecipeIngredient(amount: '1 lb', description: 'Spinach'), - RecipeIngredient(amount: '½ cup', description: 'Feta cheese'), - RecipeIngredient(amount: '½ cup', description: 'Cottage cheese'), - RecipeIngredient(amount: '2', description: 'Eggs'), - RecipeIngredient(amount: '1', description: 'Onion'), - RecipeIngredient(amount: '½ lb', description: 'Phyllo dough'), - ], - steps: [ - RecipeStep(duration: '5 min', description: 'Sauté vegetables'), - RecipeStep(duration: '3 min', description: 'Stir vegetables and other filling ingredients'), - RecipeStep(duration: '10 min', description: 'Fill phyllo squares half-full with filling and fold.'), - RecipeStep(duration: '40 min', description: 'Bake'), - ], - ), -]; diff --git a/web/gallery/lib/demo/shrine/app.dart b/web/gallery/lib/demo/shrine/app.dart deleted file mode 100644 index cccf58834..000000000 --- a/web/gallery/lib/demo/shrine/app.dart +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; - -import 'package:flutter_gallery/demo/shrine/backdrop.dart'; -import 'package:flutter_gallery/demo/shrine/category_menu_page.dart'; -import 'package:flutter_gallery/demo/shrine/colors.dart'; -import 'package:flutter_gallery/demo/shrine/expanding_bottom_sheet.dart'; -import 'package:flutter_gallery/demo/shrine/home.dart'; -import 'package:flutter_gallery/demo/shrine/login.dart'; -import 'package:flutter_gallery/demo/shrine/supplemental/cut_corners_border.dart'; - -class ShrineApp extends StatefulWidget { - @override - _ShrineAppState createState() => _ShrineAppState(); -} - -class _ShrineAppState extends State with SingleTickerProviderStateMixin { - // Controller to coordinate both the opening/closing of backdrop and sliding - // of expanding bottom sheet - AnimationController _controller; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 450), - value: 1.0, - ); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Shrine', - home: HomePage( - backdrop: Backdrop( - frontLayer: const ProductPage(), - backLayer: CategoryMenuPage(onCategoryTap: () => _controller.forward()), - frontTitle: const Text('SHRINE'), - backTitle: const Text('MENU'), - controller: _controller, - ), - expandingBottomSheet: ExpandingBottomSheet(hideController: _controller), - ), - initialRoute: '/login', - onGenerateRoute: _getRoute, - // Copy the platform from the main theme in order to support platform - // toggling from the Gallery options menu. - theme: _kShrineTheme.copyWith(platform: Theme.of(context).platform), - ); - } -} - -Route _getRoute(RouteSettings settings) { - if (settings.name != '/login') { - return null; - } - - return MaterialPageRoute( - settings: settings, - builder: (BuildContext context) => LoginPage(), - fullscreenDialog: true, - ); -} - -final ThemeData _kShrineTheme = _buildShrineTheme(); - -IconThemeData _customIconTheme(IconThemeData original) { - return original.copyWith(color: kShrineBrown900); -} - -ThemeData _buildShrineTheme() { - final ThemeData base = ThemeData.light(); - return base.copyWith( - colorScheme: kShrineColorScheme, - accentColor: kShrineBrown900, - primaryColor: kShrinePink100, - buttonColor: kShrinePink100, - scaffoldBackgroundColor: kShrineBackgroundWhite, - cardColor: kShrineBackgroundWhite, - textSelectionColor: kShrinePink100, - errorColor: kShrineErrorRed, - buttonTheme: const ButtonThemeData( - colorScheme: kShrineColorScheme, - textTheme: ButtonTextTheme.normal, - ), - primaryIconTheme: _customIconTheme(base.iconTheme), - inputDecorationTheme: const InputDecorationTheme(border: CutCornersBorder()), - textTheme: _buildShrineTextTheme(base.textTheme), - primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme), - accentTextTheme: _buildShrineTextTheme(base.accentTextTheme), - iconTheme: _customIconTheme(base.iconTheme), - ); -} - -TextTheme _buildShrineTextTheme(TextTheme base) { - return base.copyWith( - headline: base.headline.copyWith(fontWeight: FontWeight.w500), - title: base.title.copyWith(fontSize: 18.0), - caption: base.caption.copyWith(fontWeight: FontWeight.w400, fontSize: 14.0), - body2: base.body2.copyWith(fontWeight: FontWeight.w500, fontSize: 16.0), - button: base.button.copyWith(fontWeight: FontWeight.w500, fontSize: 14.0), - ).apply( - fontFamily: 'Raleway', - displayColor: kShrineBrown900, - bodyColor: kShrineBrown900, - ); -} - -const ColorScheme kShrineColorScheme = ColorScheme( - primary: kShrinePink100, - primaryVariant: kShrineBrown900, - secondary: kShrinePink50, - secondaryVariant: kShrineBrown900, - surface: kShrineSurfaceWhite, - background: kShrineBackgroundWhite, - error: kShrineErrorRed, - onPrimary: kShrineBrown900, - onSecondary: kShrineBrown900, - onSurface: kShrineBrown900, - onBackground: kShrineBrown900, - onError: kShrineSurfaceWhite, - brightness: Brightness.light, -); diff --git a/web/gallery/lib/demo/shrine/backdrop.dart b/web/gallery/lib/demo/shrine/backdrop.dart deleted file mode 100644 index 6336b873a..000000000 --- a/web/gallery/lib/demo/shrine/backdrop.dart +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; -import 'package:meta/meta.dart'; - -import 'package:flutter_gallery/demo/shrine/login.dart'; - -const Cubic _kAccelerateCurve = Cubic(0.548, 0.0, 0.757, 0.464); -const Cubic _kDecelerateCurve = Cubic(0.23, 0.94, 0.41, 1.0); -const double _kPeakVelocityTime = 0.248210; -const double _kPeakVelocityProgress = 0.379146; - -class _TappableWhileStatusIs extends StatefulWidget { - const _TappableWhileStatusIs( - this.status, { - Key key, - this.controller, - this.child, - }) : super(key: key); - - final AnimationController controller; - final AnimationStatus status; - final Widget child; - - @override - _TappableWhileStatusIsState createState() => _TappableWhileStatusIsState(); -} - -class _TappableWhileStatusIsState extends State<_TappableWhileStatusIs> { - bool _active; - - @override - void initState() { - super.initState(); - widget.controller.addStatusListener(_handleStatusChange); - _active = widget.controller.status == widget.status; - } - - @override - void dispose() { - widget.controller.removeStatusListener(_handleStatusChange); - super.dispose(); - } - - void _handleStatusChange(AnimationStatus status) { - final bool value = widget.controller.status == widget.status; - if (_active != value) { - setState(() { - _active = value; - }); - } - } - - @override - Widget build(BuildContext context) { - Widget child = AbsorbPointer( - absorbing: !_active, - child: widget.child, - ); - - if (!_active) { - child = FocusScope( - canRequestFocus: false, - debugLabel: '$_TappableWhileStatusIs', - child: child, - ); - } - return child; - } -} - -class _FrontLayer extends StatelessWidget { - const _FrontLayer({ - Key key, - this.onTap, - this.child, - }) : super(key: key); - - final VoidCallback onTap; - final Widget child; - - @override - Widget build(BuildContext context) { - return Material( - elevation: 16.0, - shape: const BeveledRectangleBorder( - borderRadius: BorderRadius.only(topLeft: Radius.circular(46.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: onTap, - child: Container( - height: 40.0, - alignment: AlignmentDirectional.centerStart, - ), - ), - Expanded( - child: child, - ), - ], - ), - ); - } -} - -class _BackdropTitle extends AnimatedWidget { - const _BackdropTitle({ - Key key, - Listenable listenable, - this.onPress, - @required this.frontTitle, - @required this.backTitle, - }) : assert(frontTitle != null), - assert(backTitle != null), - super(key: key, listenable: listenable); - - final Function onPress; - final Widget frontTitle; - final Widget backTitle; - - @override - Widget build(BuildContext context) { - final Animation animation = CurvedAnimation( - parent: listenable, - curve: const Interval(0.0, 0.78), - ); - - return DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.title, - softWrap: false, - overflow: TextOverflow.ellipsis, - child: Row(children: [ - // branded icon - SizedBox( - width: 72.0, - child: IconButton( - padding: const EdgeInsets.only(right: 8.0), - onPressed: onPress, - icon: Stack(children: [ - Opacity( - opacity: animation.value, - child: const ImageIcon(AssetImage('packages/shrine_images/slanted_menu.png')), - ), - FractionalTranslation( - translation: Tween( - begin: Offset.zero, - end: const Offset(1.0, 0.0), - ).evaluate(animation), - child: const ImageIcon(AssetImage('packages/shrine_images/diamond.png')), - ), - ]), - ), - ), - // Here, we do a custom cross fade between backTitle and frontTitle. - // This makes a smooth animation between the two texts. - Stack( - children: [ - Opacity( - opacity: CurvedAnimation( - parent: ReverseAnimation(animation), - curve: const Interval(0.5, 1.0), - ).value, - child: FractionalTranslation( - translation: Tween( - begin: Offset.zero, - end: const Offset(0.5, 0.0), - ).evaluate(animation), - child: backTitle, - ), - ), - Opacity( - opacity: CurvedAnimation( - parent: animation, - curve: const Interval(0.5, 1.0), - ).value, - child: FractionalTranslation( - translation: Tween( - begin: const Offset(-0.25, 0.0), - end: Offset.zero, - ).evaluate(animation), - child: frontTitle, - ), - ), - ], - ), - ]), - ); - } -} - -/// Builds a Backdrop. -/// -/// A Backdrop widget has two layers, front and back. The front layer is shown -/// by default, and slides down to show the back layer, from which a user -/// can make a selection. The user can also configure the titles for when the -/// front or back layer is showing. -class Backdrop extends StatefulWidget { - const Backdrop({ - @required this.frontLayer, - @required this.backLayer, - @required this.frontTitle, - @required this.backTitle, - @required this.controller, - }) : assert(frontLayer != null), - assert(backLayer != null), - assert(frontTitle != null), - assert(backTitle != null), - assert(controller != null); - - final Widget frontLayer; - final Widget backLayer; - final Widget frontTitle; - final Widget backTitle; - final AnimationController controller; - - @override - _BackdropState createState() => _BackdropState(); -} - -class _BackdropState extends State with SingleTickerProviderStateMixin { - final GlobalKey _backdropKey = GlobalKey(debugLabel: 'Backdrop'); - AnimationController _controller; - Animation _layerAnimation; - - @override - void initState() { - super.initState(); - _controller = widget.controller; - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - bool get _frontLayerVisible { - final AnimationStatus status = _controller.status; - return status == AnimationStatus.completed || status == AnimationStatus.forward; - } - - void _toggleBackdropLayerVisibility() { - // Call setState here to update layerAnimation if that's necessary - setState(() { - _frontLayerVisible ? _controller.reverse() : _controller.forward(); - }); - } - - // _layerAnimation animates the front layer between open and close. - // _getLayerAnimation adjusts the values in the TweenSequence so the - // curve and timing are correct in both directions. - Animation _getLayerAnimation(Size layerSize, double layerTop) { - Curve firstCurve; // Curve for first TweenSequenceItem - Curve secondCurve; // Curve for second TweenSequenceItem - double firstWeight; // Weight of first TweenSequenceItem - double secondWeight; // Weight of second TweenSequenceItem - Animation animation; // Animation on which TweenSequence runs - - if (_frontLayerVisible) { - firstCurve = _kAccelerateCurve; - secondCurve = _kDecelerateCurve; - firstWeight = _kPeakVelocityTime; - secondWeight = 1.0 - _kPeakVelocityTime; - animation = CurvedAnimation( - parent: _controller.view, - curve: const Interval(0.0, 0.78), - ); - } else { - // These values are only used when the controller runs from t=1.0 to t=0.0 - firstCurve = _kDecelerateCurve.flipped; - secondCurve = _kAccelerateCurve.flipped; - firstWeight = 1.0 - _kPeakVelocityTime; - secondWeight = _kPeakVelocityTime; - animation = _controller.view; - } - - return TweenSequence( - >[ - TweenSequenceItem( - tween: RelativeRectTween( - begin: RelativeRect.fromLTRB( - 0.0, - layerTop, - 0.0, - layerTop - layerSize.height, - ), - end: RelativeRect.fromLTRB( - 0.0, - layerTop * _kPeakVelocityProgress, - 0.0, - (layerTop - layerSize.height) * _kPeakVelocityProgress, - ), - ).chain(CurveTween(curve: firstCurve)), - weight: firstWeight, - ), - TweenSequenceItem( - tween: RelativeRectTween( - begin: RelativeRect.fromLTRB( - 0.0, - layerTop * _kPeakVelocityProgress, - 0.0, - (layerTop - layerSize.height) * _kPeakVelocityProgress, - ), - end: RelativeRect.fill, - ).chain(CurveTween(curve: secondCurve)), - weight: secondWeight, - ), - ], - ).animate(animation); - } - - Widget _buildStack(BuildContext context, BoxConstraints constraints) { - const double layerTitleHeight = 48.0; - final Size layerSize = constraints.biggest; - final double layerTop = layerSize.height - layerTitleHeight; - - _layerAnimation = _getLayerAnimation(layerSize, layerTop); - - return Stack( - key: _backdropKey, - children: [ - _TappableWhileStatusIs( - AnimationStatus.dismissed, - controller: _controller, - child: widget.backLayer, - ), - PositionedTransition( - rect: _layerAnimation, - child: _FrontLayer( - onTap: _toggleBackdropLayerVisibility, - child: _TappableWhileStatusIs( - AnimationStatus.completed, - controller: _controller, - child: widget.frontLayer, - ), - ), - ), - ], - ); - } - - @override - Widget build(BuildContext context) { - final AppBar appBar = AppBar( - brightness: Brightness.light, - elevation: 0.0, - titleSpacing: 0.0, - title: _BackdropTitle( - listenable: _controller.view, - onPress: _toggleBackdropLayerVisibility, - frontTitle: widget.frontTitle, - backTitle: widget.backTitle, - ), - actions: [ - IconButton( - icon: const Icon(Icons.search, semanticLabel: 'login'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (BuildContext context) => LoginPage()), - ); - }, - ), - IconButton( - icon: const Icon(Icons.tune, semanticLabel: 'login'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (BuildContext context) => LoginPage()), - ); - }, - ), - ], - ); - return Scaffold( - appBar: appBar, - body: LayoutBuilder( - builder: _buildStack, - ), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/category_menu_page.dart b/web/gallery/lib/demo/shrine/category_menu_page.dart deleted file mode 100644 index 1ac62d572..000000000 --- a/web/gallery/lib/demo/shrine/category_menu_page.dart +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/colors.dart'; -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:flutter_gallery/demo/shrine/model/product.dart'; - -class CategoryMenuPage extends StatelessWidget { - const CategoryMenuPage({ - Key key, - this.onCategoryTap, - }) : super(key: key); - - final VoidCallback onCategoryTap; - - Widget _buildCategory(Category category, BuildContext context) { - final String categoryString = category.toString().replaceAll('Category.', '').toUpperCase(); - final ThemeData theme = Theme.of(context); - return ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) => - GestureDetector( - onTap: () { - model.setCategory(category); - if (onCategoryTap != null) { - onCategoryTap(); - } - }, - child: model.selectedCategory == category - ? Column( - children: [ - const SizedBox(height: 16.0), - Text( - categoryString, - style: theme.textTheme.body2, - textAlign: TextAlign.center, - ), - const SizedBox(height: 14.0), - Container( - width: 70.0, - height: 2.0, - color: kShrinePink400, - ), - ], - ) - : Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Text( - categoryString, - style: theme.textTheme.body2.copyWith( - color: kShrineBrown900.withAlpha(153) - ), - textAlign: TextAlign.center, - ), - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Container( - padding: const EdgeInsets.only(top: 40.0), - color: kShrinePink100, - child: ListView( - children: Category.values.map((Category c) => _buildCategory(c, context)).toList(), - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/colors.dart b/web/gallery/lib/demo/shrine/colors.dart deleted file mode 100644 index 66a472861..000000000 --- a/web/gallery/lib/demo/shrine/colors.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; - -const Color kShrinePink50 = Color(0xFFFEEAE6); -const Color kShrinePink100 = Color(0xFFFEDBD0); -const Color kShrinePink300 = Color(0xFFFBB8AC); -const Color kShrinePink400 = Color(0xFFEAA4A4); - -const Color kShrineBrown900 = Color(0xFF442B2D); -const Color kShrineBrown600 = Color(0xFF7D4F52); - -const Color kShrineErrorRed = Color(0xFFC5032B); - -const Color kShrineSurfaceWhite = Color(0xFFFFFBFA); -const Color kShrineBackgroundWhite = Colors.white; diff --git a/web/gallery/lib/demo/shrine/expanding_bottom_sheet.dart b/web/gallery/lib/demo/shrine/expanding_bottom_sheet.dart deleted file mode 100644 index 72047eb68..000000000 --- a/web/gallery/lib/demo/shrine/expanding_bottom_sheet.dart +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:meta/meta.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/colors.dart'; -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:flutter_gallery/demo/shrine/model/product.dart'; -import 'package:flutter_gallery/demo/shrine/shopping_cart.dart'; - -// These curves define the emphasized easing curve. -const Cubic _kAccelerateCurve = Cubic(0.548, 0.0, 0.757, 0.464); -const Cubic _kDecelerateCurve = Cubic(0.23, 0.94, 0.41, 1.0); -// The time at which the accelerate and decelerate curves switch off -const double _kPeakVelocityTime = 0.248210; -// Percent (as a decimal) of animation that should be completed at _peakVelocityTime -const double _kPeakVelocityProgress = 0.379146; -const double _kCartHeight = 56.0; -// Radius of the shape on the top left of the sheet. -const double _kCornerRadius = 24.0; -// Width for just the cart icon and no thumbnails. -const double _kWidthForCartIcon = 64.0; - -class ExpandingBottomSheet extends StatefulWidget { - const ExpandingBottomSheet({Key key, @required this.hideController}) - : assert(hideController != null), - super(key: key); - - final AnimationController hideController; - - @override - _ExpandingBottomSheetState createState() => _ExpandingBottomSheetState(); - - static _ExpandingBottomSheetState of(BuildContext context, {bool isNullOk = false}) { - assert(isNullOk != null); - assert(context != null); - final _ExpandingBottomSheetState result = context.ancestorStateOfType( - const TypeMatcher<_ExpandingBottomSheetState>() - ); - if (isNullOk || result != null) { - return result; - } - throw FlutterError( - 'ExpandingBottomSheet.of() called with a context that does not contain a ExpandingBottomSheet.\n'); - } -} - -// Emphasized Easing is a motion curve that has an organic, exciting feeling. -// It's very fast to begin with and then very slow to finish. Unlike standard -// curves, like [Curves.fastOutSlowIn], it can't be expressed in a cubic bezier -// curve formula. It's quintic, not cubic. But it _can_ be expressed as one -// curve followed by another, which we do here. -Animation _getEmphasizedEasingAnimation({ - @required T begin, - @required T peak, - @required T end, - @required bool isForward, - @required Animation parent, -}) { - Curve firstCurve; - Curve secondCurve; - double firstWeight; - double secondWeight; - - if (isForward) { - firstCurve = _kAccelerateCurve; - secondCurve = _kDecelerateCurve; - firstWeight = _kPeakVelocityTime; - secondWeight = 1.0 - _kPeakVelocityTime; - } else { - firstCurve = _kDecelerateCurve.flipped; - secondCurve = _kAccelerateCurve.flipped; - firstWeight = 1.0 - _kPeakVelocityTime; - secondWeight = _kPeakVelocityTime; - } - - return TweenSequence( - >[ - TweenSequenceItem( - weight: firstWeight, - tween: Tween( - begin: begin, - end: peak, - ).chain(CurveTween(curve: firstCurve)), - ), - TweenSequenceItem( - weight: secondWeight, - tween: Tween( - begin: peak, - end: end, - ).chain(CurveTween(curve: secondCurve)), - ), - ], - ).animate(parent); -} - -// Calculates the value where two double Animations should be joined. Used by -// callers of _getEmphasisedEasing(). -double _getPeakPoint({double begin, double end}) { - return begin + (end - begin) * _kPeakVelocityProgress; -} - -class _ExpandingBottomSheetState extends State with TickerProviderStateMixin { - final GlobalKey _expandingBottomSheetKey = GlobalKey(debugLabel: 'Expanding bottom sheet'); - - // The width of the Material, calculated by _widthFor() & based on the number - // of products in the cart. 64.0 is the width when there are 0 products - // (_kWidthForZeroProducts) - double _width = _kWidthForCartIcon; - - // Controller for the opening and closing of the ExpandingBottomSheet - AnimationController _controller; - - // Animations for the opening and closing of the ExpandingBottomSheet - Animation _widthAnimation; - Animation _heightAnimation; - Animation _thumbnailOpacityAnimation; - Animation _cartOpacityAnimation; - Animation _shapeAnimation; - Animation _slideAnimation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 500), - vsync: this, - ); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - Animation _getWidthAnimation(double screenWidth) { - if (_controller.status == AnimationStatus.forward) { - // Opening animation - return Tween(begin: _width, end: screenWidth).animate( - CurvedAnimation( - parent: _controller.view, - curve: const Interval(0.0, 0.3, curve: Curves.fastOutSlowIn), - ), - ); - } else { - // Closing animation - return _getEmphasizedEasingAnimation( - begin: _width, - peak: _getPeakPoint(begin: _width, end: screenWidth), - end: screenWidth, - isForward: false, - parent: CurvedAnimation(parent: _controller.view, curve: const Interval(0.0, 0.87)), - ); - } - } - - Animation _getHeightAnimation(double screenHeight) { - if (_controller.status == AnimationStatus.forward) { - // Opening animation - - return _getEmphasizedEasingAnimation( - begin: _kCartHeight, - peak: _kCartHeight + (screenHeight - _kCartHeight) * _kPeakVelocityProgress, - end: screenHeight, - isForward: true, - parent: _controller.view, - ); - } else { - // Closing animation - return Tween( - begin: _kCartHeight, - end: screenHeight, - ).animate( - CurvedAnimation( - parent: _controller.view, - curve: const Interval(0.434, 1.0, curve: Curves.linear), // not used - // only the reverseCurve will be used - reverseCurve: Interval(0.434, 1.0, curve: Curves.fastOutSlowIn.flipped), - ), - ); - } - } - - // Animation of the cut corner. It's cut when closed and not cut when open. - Animation _getShapeAnimation() { - if (_controller.status == AnimationStatus.forward) { - return Tween(begin: _kCornerRadius, end: 0.0).animate( - CurvedAnimation( - parent: _controller.view, - curve: const Interval(0.0, 0.3, curve: Curves.fastOutSlowIn), - ), - ); - } else { - return _getEmphasizedEasingAnimation( - begin: _kCornerRadius, - peak: _getPeakPoint(begin: _kCornerRadius, end: 0.0), - end: 0.0, - isForward: false, - parent: _controller.view, - ); - } - } - - Animation _getThumbnailOpacityAnimation() { - return Tween(begin: 1.0, end: 0.0).animate( - CurvedAnimation( - parent: _controller.view, - curve: _controller.status == AnimationStatus.forward - ? const Interval(0.0, 0.3) - : const Interval(0.532, 0.766), - ), - ); - } - - Animation _getCartOpacityAnimation() { - return CurvedAnimation( - parent: _controller.view, - curve: _controller.status == AnimationStatus.forward - ? const Interval(0.3, 0.6) - : const Interval(0.766, 1.0), - ); - } - - // Returns the correct width of the ExpandingBottomSheet based on the number of - // products in the cart. - double _widthFor(int numProducts) { - switch (numProducts) { - case 0: - return _kWidthForCartIcon; - case 1: - return 136.0; - case 2: - return 192.0; - case 3: - return 248.0; - default: - return 278.0; - } - } - - // Returns true if the cart is open or opening and false otherwise. - bool get _isOpen { - final AnimationStatus status = _controller.status; - return status == AnimationStatus.completed || status == AnimationStatus.forward; - } - - // Opens the ExpandingBottomSheet if it's closed, otherwise does nothing. - void open() { - if (!_isOpen) { - _controller.forward(); - } - } - - // Closes the ExpandingBottomSheet if it's open or opening, otherwise does nothing. - void close() { - if (_isOpen) { - _controller.reverse(); - } - } - - // Changes the padding between the start edge of the Material and the cart icon - // based on the number of products in the cart (padding increases when > 0 - // products.) - EdgeInsetsDirectional _cartPaddingFor(int numProducts) { - return (numProducts == 0) - ? const EdgeInsetsDirectional.only(start: 20.0, end: 8.0) - : const EdgeInsetsDirectional.only(start: 32.0, end: 8.0); - } - - bool get _cartIsVisible => _thumbnailOpacityAnimation.value == 0.0; - - Widget _buildThumbnails(int numProducts) { - return ExcludeSemantics( - child: Opacity( - opacity: _thumbnailOpacityAnimation.value, - child: Column( - children: [ - Row( - children: [ - AnimatedPadding( - padding: _cartPaddingFor(numProducts), - child: const Icon(Icons.shopping_cart), - duration: const Duration(milliseconds: 225), - ), - Container( - // Accounts for the overflow number - width: numProducts > 3 ? _width - 94.0 : _width - 64.0, - height: _kCartHeight, - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: ProductThumbnailRow(), - ), - ExtraProductsNumber(), - ], - ), - ], - ), - ), - ); - } - - Widget _buildShoppingCartPage() { - return Opacity( - opacity: _cartOpacityAnimation.value, - child: ShoppingCartPage(), - ); - } - - Widget _buildCart(BuildContext context, Widget child) { - // numProducts is the number of different products in the cart (does not - // include multiples of the same product). - final AppStateModel model = ScopedModel.of(context); - final int numProducts = model.productsInCart.keys.length; - final int totalCartQuantity = model.totalCartQuantity; - final Size screenSize = MediaQuery.of(context).size; - final double screenWidth = screenSize.width; - final double screenHeight = screenSize.height; - - _width = _widthFor(numProducts); - _widthAnimation = _getWidthAnimation(screenWidth); - _heightAnimation = _getHeightAnimation(screenHeight); - _shapeAnimation = _getShapeAnimation(); - _thumbnailOpacityAnimation = _getThumbnailOpacityAnimation(); - _cartOpacityAnimation = _getCartOpacityAnimation(); - - return Semantics( - button: true, - value: 'Shopping cart, $totalCartQuantity items', - child: Container( - width: _widthAnimation.value, - height: _heightAnimation.value, - child: Material( - animationDuration: const Duration(milliseconds: 0), - shape: BeveledRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(_shapeAnimation.value), - ), - ), - elevation: 4.0, - color: kShrinePink50, - child: _cartIsVisible - ? _buildShoppingCartPage() - : _buildThumbnails(numProducts), - ), - ), - ); - } - - // Builder for the hide and reveal animation when the backdrop opens and closes - Widget _buildSlideAnimation(BuildContext context, Widget child) { - _slideAnimation = _getEmphasizedEasingAnimation( - begin: const Offset(1.0, 0.0), - peak: const Offset(_kPeakVelocityProgress, 0.0), - end: const Offset(0.0, 0.0), - isForward: widget.hideController.status == AnimationStatus.forward, - parent: widget.hideController, - ); - - return SlideTransition( - position: _slideAnimation, - child: child, - ); - } - - // Closes the cart if the cart is open, otherwise exits the app (this should - // only be relevant for Android). - Future _onWillPop() async { - if (!_isOpen) { - await SystemNavigator.pop(); - return true; - } - - close(); - return true; - } - - @override - Widget build(BuildContext context) { - return AnimatedSize( - key: _expandingBottomSheetKey, - duration: const Duration(milliseconds: 225), - curve: Curves.easeInOut, - vsync: this, - alignment: FractionalOffset.topLeft, - child: WillPopScope( - onWillPop: _onWillPop, - child: AnimatedBuilder( - animation: widget.hideController, - builder: _buildSlideAnimation, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: open, - child: ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) { - return AnimatedBuilder( - builder: _buildCart, - animation: _controller, - ); - }, - ), - ), - ), - ), - ); - } -} - -class ProductThumbnailRow extends StatefulWidget { - @override - _ProductThumbnailRowState createState() => _ProductThumbnailRowState(); -} - -class _ProductThumbnailRowState extends State { - final GlobalKey _listKey = GlobalKey(); - - // _list represents what's currently on screen. If _internalList updates, - // it will need to be updated to match it. - _ListModel _list; - - // _internalList represents the list as it is updated by the AppStateModel. - List _internalList; - - @override - void initState() { - super.initState(); - _list = _ListModel( - listKey: _listKey, - initialItems: ScopedModel.of(context).productsInCart.keys.toList(), - removedItemBuilder: _buildRemovedThumbnail, - ); - _internalList = List.from(_list.list); - } - - Product _productWithId(int productId) { - final AppStateModel model = ScopedModel.of(context); - final Product product = model.getProductById(productId); - assert(product != null); - return product; - } - - Widget _buildRemovedThumbnail(int item, BuildContext context, Animation animation) { - return ProductThumbnail(animation, animation, _productWithId(item)); - } - - Widget _buildThumbnail(BuildContext context, int index, Animation animation) { - final Animation thumbnailSize = Tween(begin: 0.8, end: 1.0).animate( - CurvedAnimation( - curve: const Interval(0.33, 1.0, curve: Curves.easeIn), - parent: animation, - ), - ); - - final Animation opacity = CurvedAnimation( - curve: const Interval(0.33, 1.0, curve: Curves.linear), - parent: animation, - ); - - return ProductThumbnail(thumbnailSize, opacity, _productWithId(_list[index])); - } - - // If the lists are the same length, assume nothing has changed. - // If the internalList is shorter than the ListModel, an item has been removed. - // If the internalList is longer, then an item has been added. - void _updateLists() { - // Update _internalList based on the model - _internalList = ScopedModel.of(context).productsInCart.keys.toList(); - final Set internalSet = Set.from(_internalList); - final Set listSet = Set.from(_list.list); - - final Set difference = internalSet.difference(listSet); - if (difference.isEmpty) { - return; - } - - for (int product in difference) { - if (_internalList.length < _list.length) { - _list.remove(product); - } else if (_internalList.length > _list.length) { - _list.add(product); - } - } - - while (_internalList.length != _list.length) { - int index = 0; - // Check bounds and that the list elements are the same - while (_internalList.isNotEmpty && - _list.length > 0 && - index < _internalList.length && - index < _list.length && - _internalList[index] == _list[index]) { - index++; - } - } - } - - Widget _buildAnimatedList() { - return AnimatedList( - key: _listKey, - shrinkWrap: true, - itemBuilder: _buildThumbnail, - initialItemCount: _list.length, - scrollDirection: Axis.horizontal, - physics: const NeverScrollableScrollPhysics(), // Cart shouldn't scroll - ); - } - - @override - Widget build(BuildContext context) { - _updateLists(); - return ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) => _buildAnimatedList(), - ); - } -} - -class ExtraProductsNumber extends StatelessWidget { - // Calculates the number to be displayed at the end of the row if there are - // more than three products in the cart. This calculates overflow products, - // including their duplicates (but not duplicates of products shown as - // thumbnails). - int _calculateOverflow(AppStateModel model) { - final Map productMap = model.productsInCart; - // List created to be able to access products by index instead of ID. - // Order is guaranteed because productsInCart returns a LinkedHashMap. - final List products = productMap.keys.toList(); - int overflow = 0; - final int numProducts = products.length; - if (numProducts > 3) { - for (int i = 3; i < numProducts; i++) { - overflow += productMap[products[i]]; - } - } - return overflow; - } - - Widget _buildOverflow(AppStateModel model, BuildContext context) { - if (model.productsInCart.length <= 3) - return Container(); - - final int numOverflowProducts = _calculateOverflow(model); - // Maximum of 99 so padding doesn't get messy. - final int displayedOverflowProducts = numOverflowProducts <= 99 ? numOverflowProducts : 99; - return Container( - child: Text( - '+$displayedOverflowProducts', - style: Theme.of(context).primaryTextTheme.button, - ), - ); - } - - @override - Widget build(BuildContext context) { - return ScopedModelDescendant( - builder: (BuildContext builder, Widget child, AppStateModel model) => _buildOverflow(model, context), - ); - } -} - -class ProductThumbnail extends StatelessWidget { - const ProductThumbnail(this.animation, this.opacityAnimation, this.product); - - final Animation animation; - final Animation opacityAnimation; - final Product product; - - @override - Widget build(BuildContext context) { - return FadeTransition( - opacity: opacityAnimation, - child: ScaleTransition( - scale: animation, - child: Container( - width: 40.0, - height: 40.0, - decoration: BoxDecoration( - image: DecorationImage( - image: ExactAssetImage( - product.assetName, // asset name - package: product.assetPackage, // asset package - ), - fit: BoxFit.cover, - ), - borderRadius: const BorderRadius.all(Radius.circular(10.0)), - ), - margin: const EdgeInsets.only(left: 16.0), - ), - ), - ); - } -} - -// _ListModel manipulates an internal list and an AnimatedList -class _ListModel { - _ListModel({ - @required this.listKey, - @required this.removedItemBuilder, - Iterable initialItems, - }) : assert(listKey != null), - assert(removedItemBuilder != null), - _items = initialItems?.toList() ?? []; - - final GlobalKey listKey; - final dynamic removedItemBuilder; - final List _items; - - AnimatedListState get _animatedList => listKey.currentState; - - void add(int product) { - _insert(_items.length, product); - } - - void _insert(int index, int item) { - _items.insert(index, item); - _animatedList.insertItem(index, duration: const Duration(milliseconds: 225)); - } - - void remove(int product) { - final int index = _items.indexOf(product); - if (index >= 0) { - _removeAt(index); - } - } - - void _removeAt(int index) { - final int removedItem = _items.removeAt(index); - if (removedItem != null) { - _animatedList.removeItem(index, (BuildContext context, Animation animation) { - return removedItemBuilder(removedItem, context, animation); - }); - } - } - - int get length => _items.length; - - int operator [](int index) => _items[index]; - - int indexOf(int item) => _items.indexOf(item); - - List get list => _items; -} diff --git a/web/gallery/lib/demo/shrine/home.dart b/web/gallery/lib/demo/shrine/home.dart deleted file mode 100644 index c180c48bd..000000000 --- a/web/gallery/lib/demo/shrine/home.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/backdrop.dart'; -import 'package:flutter_gallery/demo/shrine/expanding_bottom_sheet.dart'; -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:flutter_gallery/demo/shrine/model/product.dart'; -import 'package:flutter_gallery/demo/shrine/supplemental/asymmetric_view.dart'; - -class ProductPage extends StatelessWidget { - const ProductPage({this.category = Category.all}); - - final Category category; - - @override - Widget build(BuildContext context) { - return ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) { - return AsymmetricView(products: model.getProducts()); - }); - } -} - -class HomePage extends StatelessWidget { - const HomePage({ - this.expandingBottomSheet, - this.backdrop, - Key key, - }) : super(key: key); - - final ExpandingBottomSheet expandingBottomSheet; - final Backdrop backdrop; - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - backdrop, - Align(child: expandingBottomSheet, alignment: Alignment.bottomRight), - ], - ); - } -} diff --git a/web/gallery/lib/demo/shrine/login.dart b/web/gallery/lib/demo/shrine/login.dart deleted file mode 100644 index 23da0668a..000000000 --- a/web/gallery/lib/demo/shrine/login.dart +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; - -import 'package:flutter_gallery/demo/shrine/colors.dart'; - -class LoginPage extends StatefulWidget { - @override - _LoginPageState createState() => _LoginPageState(); -} - -class _LoginPageState extends State { - final TextEditingController _usernameController = TextEditingController(); - final TextEditingController _passwordController = TextEditingController(); - static const ShapeDecoration _decoration = ShapeDecoration( - shape: BeveledRectangleBorder( - side: BorderSide(color: kShrineBrown900, width: 0.5), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - ); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - elevation: 0.0, - backgroundColor: Colors.white, - brightness: Brightness.light, - leading: IconButton( - icon: const BackButtonIcon(), - tooltip: MaterialLocalizations.of(context).backButtonTooltip, - onPressed: () { - // The login screen is immediately displayed on top of the Shrine - // home screen using onGenerateRoute and so rootNavigator must be - // set to true in order to get out of Shrine completely. - Navigator.of(context, rootNavigator: true).pop(); - }, - ), - ), - body: SafeArea( - child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - children: [ - const SizedBox(height: 80.0), - Column( - children: [ - Image.asset('packages/shrine_images/diamond.png'), - const SizedBox(height: 16.0), - Text( - 'SHRINE', - style: Theme.of(context).textTheme.headline, - ), - ], - ), - const SizedBox(height: 120.0), - PrimaryColorOverride( - color: kShrineBrown900, - child: Container( - decoration: _decoration, - child: TextField( - controller: _usernameController, - decoration: const InputDecoration( - labelText: 'Username', - ), - ), - ), - ), - const SizedBox(height: 12.0), - PrimaryColorOverride( - color: kShrineBrown900, - child: Container( - decoration: _decoration, - child: TextField( - controller: _passwordController, - decoration: const InputDecoration( - labelText: 'Password', - ), - ), - ), - ), - Wrap( - children: [ - ButtonBar( - children: [ - FlatButton( - child: const Text('CANCEL'), - shape: const BeveledRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - onPressed: () { - // The login screen is immediately displayed on top of - // the Shrine home screen using onGenerateRoute and so - // rootNavigator must be set to true in order to get out - // of Shrine completely. - Navigator.of(context, rootNavigator: true).pop(); - }, - ), - RaisedButton( - child: const Text('NEXT'), - elevation: 8.0, - shape: const BeveledRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - onPressed: () { - Navigator.pop(context); - }, - ), - ], - ), - ], - ), - ], - ), - ), - ); - } -} - -class PrimaryColorOverride extends StatelessWidget { - const PrimaryColorOverride({Key key, this.color, this.child}) : super(key: key); - - final Color color; - final Widget child; - - @override - Widget build(BuildContext context) { - return Theme( - child: child, - data: Theme.of(context).copyWith(primaryColor: color), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/model/app_state_model.dart b/web/gallery/lib/demo/shrine/model/app_state_model.dart deleted file mode 100644 index 55d4806d8..000000000 --- a/web/gallery/lib/demo/shrine/model/app_state_model.dart +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/model/product.dart'; -import 'package:flutter_gallery/demo/shrine/model/products_repository.dart'; - -double _salesTaxRate = 0.06; -double _shippingCostPerItem = 7.0; - -class AppStateModel extends Model { - // All the available products. - List _availableProducts; - - // The currently selected category of products. - Category _selectedCategory = Category.all; - - // The IDs and quantities of products currently in the cart. - final Map _productsInCart = {}; - - Map get productsInCart => Map.from(_productsInCart); - - // Total number of items in the cart. - int get totalCartQuantity => _productsInCart.values.fold(0, (int v, int e) => v + e); - - Category get selectedCategory => _selectedCategory; - - // Totaled prices of the items in the cart. - double get subtotalCost { - return _productsInCart.keys - .map((int id) => _availableProducts[id].price * _productsInCart[id]) - .fold(0.0, (double sum, int e) => sum + e); - } - - // Total shipping cost for the items in the cart. - double get shippingCost { - return _shippingCostPerItem * _productsInCart.values.fold(0.0, (num sum, int e) => sum + e); - } - - // Sales tax for the items in the cart - double get tax => subtotalCost * _salesTaxRate; - - // Total cost to order everything in the cart. - double get totalCost => subtotalCost + shippingCost + tax; - - // Returns a copy of the list of available products, filtered by category. - List getProducts() { - if (_availableProducts == null) { - return []; - } - - if (_selectedCategory == Category.all) { - return List.from(_availableProducts); - } else { - return _availableProducts - .where((Product p) => p.category == _selectedCategory) - .toList(); - } - } - - // Adds a product to the cart. - void addProductToCart(int productId) { - if (!_productsInCart.containsKey(productId)) { - _productsInCart[productId] = 1; - } else { - _productsInCart[productId]++; - } - - notifyListeners(); - } - - // Removes an item from the cart. - void removeItemFromCart(int productId) { - if (_productsInCart.containsKey(productId)) { - if (_productsInCart[productId] == 1) { - _productsInCart.remove(productId); - } else { - _productsInCart[productId]--; - } - } - - notifyListeners(); - } - - // Returns the Product instance matching the provided id. - Product getProductById(int id) { - return _availableProducts.firstWhere((Product p) => p.id == id); - } - - // Removes everything from the cart. - void clearCart() { - _productsInCart.clear(); - notifyListeners(); - } - - // Loads the list of available products from the repo. - void loadProducts() { - _availableProducts = ProductsRepository.loadProducts(Category.all); - notifyListeners(); - } - - void setCategory(Category newCategory) { - _selectedCategory = newCategory; - notifyListeners(); - } - - @override - String toString() { - return 'AppStateModel(totalCost: $totalCost)'; - } -} diff --git a/web/gallery/lib/demo/shrine/model/product.dart b/web/gallery/lib/demo/shrine/model/product.dart deleted file mode 100644 index c19d4d58f..000000000 --- a/web/gallery/lib/demo/shrine/model/product.dart +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/foundation.dart'; - -enum Category { - all, - accessories, - clothing, - home, -} - -class Product { - const Product({ - @required this.category, - @required this.id, - @required this.isFeatured, - @required this.name, - @required this.price, - }) : assert(category != null), - assert(id != null), - assert(isFeatured != null), - assert(name != null), - assert(price != null); - - final Category category; - final int id; - final bool isFeatured; - final String name; - final int price; - - String get assetName => '$id-0.jpg'; - String get assetPackage => 'shrine_images'; - - @override - String toString() => '$name (id=$id)'; -} diff --git a/web/gallery/lib/demo/shrine/model/products_repository.dart b/web/gallery/lib/demo/shrine/model/products_repository.dart deleted file mode 100644 index 75bf4b3a3..000000000 --- a/web/gallery/lib/demo/shrine/model/products_repository.dart +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter_gallery/demo/shrine/model/product.dart'; - -class ProductsRepository { - static List loadProducts(Category category) { - const List allProducts = [ - Product( - category: Category.accessories, - id: 0, - isFeatured: true, - name: 'Vagabond sack', - price: 120, - ), - Product( - category: Category.accessories, - id: 1, - isFeatured: true, - name: 'Stella sunglasses', - price: 58, - ), - Product( - category: Category.accessories, - id: 2, - isFeatured: false, - name: 'Whitney belt', - price: 35, - ), - Product( - category: Category.accessories, - id: 3, - isFeatured: true, - name: 'Garden strand', - price: 98, - ), - Product( - category: Category.accessories, - id: 4, - isFeatured: false, - name: 'Strut earrings', - price: 34, - ), - Product( - category: Category.accessories, - id: 5, - isFeatured: false, - name: 'Varsity socks', - price: 12, - ), - Product( - category: Category.accessories, - id: 6, - isFeatured: false, - name: 'Weave keyring', - price: 16, - ), - Product( - category: Category.accessories, - id: 7, - isFeatured: true, - name: 'Gatsby hat', - price: 40, - ), - Product( - category: Category.accessories, - id: 8, - isFeatured: true, - name: 'Shrug bag', - price: 198, - ), - Product( - category: Category.home, - id: 9, - isFeatured: true, - name: 'Gilt desk trio', - price: 58, - ), - Product( - category: Category.home, - id: 10, - isFeatured: false, - name: 'Copper wire rack', - price: 18, - ), - Product( - category: Category.home, - id: 11, - isFeatured: false, - name: 'Soothe ceramic set', - price: 28, - ), - Product( - category: Category.home, - id: 12, - isFeatured: false, - name: 'Hurrahs tea set', - price: 34, - ), - Product( - category: Category.home, - id: 13, - isFeatured: true, - name: 'Blue stone mug', - price: 18, - ), - Product( - category: Category.home, - id: 14, - isFeatured: true, - name: 'Rainwater tray', - price: 27, - ), - Product( - category: Category.home, - id: 15, - isFeatured: true, - name: 'Chambray napkins', - price: 16, - ), - Product( - category: Category.home, - id: 16, - isFeatured: true, - name: 'Succulent planters', - price: 16, - ), - Product( - category: Category.home, - id: 17, - isFeatured: false, - name: 'Quartet table', - price: 175, - ), - Product( - category: Category.home, - id: 18, - isFeatured: true, - name: 'Kitchen quattro', - price: 129, - ), - Product( - category: Category.clothing, - id: 19, - isFeatured: false, - name: 'Clay sweater', - price: 48, - ), - Product( - category: Category.clothing, - id: 20, - isFeatured: false, - name: 'Sea tunic', - price: 45, - ), - Product( - category: Category.clothing, - id: 21, - isFeatured: false, - name: 'Plaster tunic', - price: 38, - ), - Product( - category: Category.clothing, - id: 22, - isFeatured: false, - name: 'White pinstripe shirt', - price: 70, - ), - Product( - category: Category.clothing, - id: 23, - isFeatured: false, - name: 'Chambray shirt', - price: 70, - ), - Product( - category: Category.clothing, - id: 24, - isFeatured: true, - name: 'Seabreeze sweater', - price: 60, - ), - Product( - category: Category.clothing, - id: 25, - isFeatured: false, - name: 'Gentry jacket', - price: 178, - ), - Product( - category: Category.clothing, - id: 26, - isFeatured: false, - name: 'Navy trousers', - price: 74, - ), - Product( - category: Category.clothing, - id: 27, - isFeatured: true, - name: 'Walter henley (white)', - price: 38, - ), - Product( - category: Category.clothing, - id: 28, - isFeatured: true, - name: 'Surf and perf shirt', - price: 48, - ), - Product( - category: Category.clothing, - id: 29, - isFeatured: true, - name: 'Ginger scarf', - price: 98, - ), - Product( - category: Category.clothing, - id: 30, - isFeatured: true, - name: 'Ramona crossover', - price: 68, - ), - Product( - category: Category.clothing, - id: 31, - isFeatured: false, - name: 'Chambray shirt', - price: 38, - ), - Product( - category: Category.clothing, - id: 32, - isFeatured: false, - name: 'Classic white collar', - price: 58, - ), - Product( - category: Category.clothing, - id: 33, - isFeatured: true, - name: 'Cerise scallop tee', - price: 42, - ), - Product( - category: Category.clothing, - id: 34, - isFeatured: false, - name: 'Shoulder rolls tee', - price: 27, - ), - Product( - category: Category.clothing, - id: 35, - isFeatured: false, - name: 'Grey slouch tank', - price: 24, - ), - Product( - category: Category.clothing, - id: 36, - isFeatured: false, - name: 'Sunshirt dress', - price: 58, - ), - Product( - category: Category.clothing, - id: 37, - isFeatured: true, - name: 'Fine lines tee', - price: 58, - ), - ]; - if (category == Category.all) { - return allProducts; - } else { - return allProducts.where((Product p) => p.category == category).toList(); - } - } -} diff --git a/web/gallery/lib/demo/shrine/shopping_cart.dart b/web/gallery/lib/demo/shrine/shopping_cart.dart deleted file mode 100644 index 076e6573a..000000000 --- a/web/gallery/lib/demo/shrine/shopping_cart.dart +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/colors.dart'; -import 'package:flutter_gallery/demo/shrine/expanding_bottom_sheet.dart'; -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:flutter_gallery/demo/shrine/model/product.dart'; - -const double _leftColumnWidth = 60.0; - -class ShoppingCartPage extends StatefulWidget { - @override - _ShoppingCartPageState createState() => _ShoppingCartPageState(); -} - -class _ShoppingCartPageState extends State { - List _createShoppingCartRows(AppStateModel model) { - return model.productsInCart.keys - .map((int id) => ShoppingCartRow( - product: model.getProductById(id), - quantity: model.productsInCart[id], - onPressed: () { - model.removeItemFromCart(id); - }, - ), - ) - .toList(); - } - - @override - Widget build(BuildContext context) { - final ThemeData localTheme = Theme.of(context); - - return Scaffold( - backgroundColor: kShrinePink50, - body: SafeArea( - child: Container( - child: ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) { - return Stack( - children: [ - ListView( - children: [ - Row( - children: [ - SizedBox( - width: _leftColumnWidth, - child: IconButton( - icon: const Icon(Icons.keyboard_arrow_down), - onPressed: () => ExpandingBottomSheet.of(context).close(), - ), - ), - Text( - 'CART', - style: localTheme.textTheme.subhead.copyWith(fontWeight: FontWeight.w600), - ), - const SizedBox(width: 16.0), - Text('${model.totalCartQuantity} ITEMS'), - ], - ), - const SizedBox(height: 16.0), - Column( - children: _createShoppingCartRows(model), - ), - ShoppingCartSummary(model: model), - const SizedBox(height: 100.0), - ], - ), - Positioned( - bottom: 16.0, - left: 16.0, - right: 16.0, - child: RaisedButton( - shape: const BeveledRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - color: kShrinePink100, - splashColor: kShrineBrown600, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 12.0), - child: Text('CLEAR CART'), - ), - onPressed: () { - model.clearCart(); - ExpandingBottomSheet.of(context).close(); - }, - ), - ), - ], - ); - }, - ), - ), - ), - ); - } -} - -class ShoppingCartSummary extends StatelessWidget { - const ShoppingCartSummary({this.model}); - - final AppStateModel model; - - @override - Widget build(BuildContext context) { - final TextStyle smallAmountStyle = Theme.of(context).textTheme.body1.copyWith(color: kShrineBrown600); - final TextStyle largeAmountStyle = Theme.of(context).textTheme.display1; - final NumberFormat formatter = NumberFormat.simpleCurrency( - decimalDigits: 2, - locale: Localizations.localeOf(context).toString(), - ); - - return Row( - children: [ - const SizedBox(width: _leftColumnWidth), - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 16.0), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Expanded( - child: Text('TOTAL'), - ), - Text( - formatter.format(model.totalCost), - style: largeAmountStyle, - ), - ], - ), - const SizedBox(height: 16.0), - Row( - children: [ - const Expanded( - child: Text('Subtotal:'), - ), - Text( - formatter.format(model.subtotalCost), - style: smallAmountStyle, - ), - ], - ), - const SizedBox(height: 4.0), - Row( - children: [ - const Expanded( - child: Text('Shipping:'), - ), - Text( - formatter.format(model.shippingCost), - style: smallAmountStyle, - ), - ], - ), - const SizedBox(height: 4.0), - Row( - children: [ - const Expanded( - child: Text('Tax:'), - ), - Text( - formatter.format(model.tax), - style: smallAmountStyle, - ), - ], - ), - ], - ), - ), - ), - ], - ); - } -} - -class ShoppingCartRow extends StatelessWidget { - const ShoppingCartRow({ - @required this.product, - @required this.quantity, - this.onPressed, - }); - - final Product product; - final int quantity; - final VoidCallback onPressed; - - @override - Widget build(BuildContext context) { - final NumberFormat formatter = NumberFormat.simpleCurrency( - decimalDigits: 0, - locale: Localizations.localeOf(context).toString(), - ); - final ThemeData localTheme = Theme.of(context); - - return Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: Row( - key: ValueKey(product.id), - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: _leftColumnWidth, - child: IconButton( - icon: const Icon(Icons.remove_circle_outline), - onPressed: onPressed, - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 16.0), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset( - product.assetName, - package: product.assetPackage, - fit: BoxFit.cover, - width: 75.0, - height: 75.0, - ), - const SizedBox(width: 16.0), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text('Quantity: $quantity'), - ), - Text('x ${formatter.format(product.price)}'), - ], - ), - Text( - product.name, - style: localTheme.textTheme.subhead.copyWith(fontWeight: FontWeight.w600), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16.0), - const Divider( - color: kShrineBrown900, - height: 10.0, - ), - ], - ), - ), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/supplemental/asymmetric_view.dart b/web/gallery/lib/demo/shrine/supplemental/asymmetric_view.dart deleted file mode 100644 index 10922a142..000000000 --- a/web/gallery/lib/demo/shrine/supplemental/asymmetric_view.dart +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; - -import 'package:flutter_gallery/demo/shrine/model/product.dart'; -import 'package:flutter_gallery/demo/shrine/supplemental/product_columns.dart'; - -class AsymmetricView extends StatelessWidget { - const AsymmetricView({Key key, this.products}) : super(key: key); - - final List products; - - List _buildColumns(BuildContext context) { - if (products == null || products.isEmpty) { - return const []; - } - - // This will return a list of columns. It will oscillate between the two - // kinds of columns. Even cases of the index (0, 2, 4, etc) will be - // TwoProductCardColumn and the odd cases will be OneProductCardColumn. - // - // Each pair of columns will advance us 3 products forward (2 + 1). That's - // some kinda awkward math so we use _evenCasesIndex and _oddCasesIndex as - // helpers for creating the index of the product list that will correspond - // to the index of the list of columns. - return List.generate(_listItemCount(products.length), (int index) { - double width = .59 * MediaQuery.of(context).size.width; - Widget column; - if (index % 2 == 0) { - /// Even cases - final int bottom = _evenCasesIndex(index); - column = TwoProductCardColumn( - bottom: products[bottom], - top: products.length - 1 >= bottom + 1 - ? products[bottom + 1] - : null, - ); - width += 32.0; - } else { - /// Odd cases - column = OneProductCardColumn( - product: products[_oddCasesIndex(index)], - ); - } - return Container( - width: width, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: column, - ), - ); - }).toList(); - } - - int _evenCasesIndex(int input) { - // The operator ~/ is a cool one. It's the truncating division operator. It - // divides the number and if there's a remainder / decimal, it cuts it off. - // This is like dividing and then casting the result to int. Also, it's - // functionally equivalent to floor() in this case. - return input ~/ 2 * 3; - } - - int _oddCasesIndex(int input) { - assert(input > 0); - return (input / 2).ceil() * 3 - 1; - } - - int _listItemCount(int totalItems) { - return (totalItems % 3 == 0) - ? totalItems ~/ 3 * 2 - : (totalItems / 3).ceil() * 2 - 1; - } - - @override - Widget build(BuildContext context) { - return ListView( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.fromLTRB(0.0, 34.0, 16.0, 44.0), - children: _buildColumns(context), - physics: const AlwaysScrollableScrollPhysics(), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/supplemental/cut_corners_border.dart b/web/gallery/lib/demo/shrine/supplemental/cut_corners_border.dart deleted file mode 100644 index 96e7e0e4c..000000000 --- a/web/gallery/lib/demo/shrine/supplemental/cut_corners_border.dart +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'dart:ui' show lerpDouble; - -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class CutCornersBorder extends OutlineInputBorder { - const CutCornersBorder({ - BorderSide borderSide = BorderSide.none, - BorderRadius borderRadius = const BorderRadius.all(Radius.circular(2.0)), - this.cut = 7.0, - double gapPadding = 2.0, - }) : super( - borderSide: borderSide, - borderRadius: borderRadius, - gapPadding: gapPadding, - ); - - @override - CutCornersBorder copyWith({ - BorderSide borderSide, - BorderRadius borderRadius, - double gapPadding, - double cut, - }) { - return CutCornersBorder( - borderSide: borderSide ?? this.borderSide, - borderRadius: borderRadius ?? this.borderRadius, - gapPadding: gapPadding ?? this.gapPadding, - cut: cut ?? this.cut, - ); - } - - final double cut; - - @override - ShapeBorder lerpFrom(ShapeBorder a, double t) { - if (a is CutCornersBorder) { - final CutCornersBorder outline = a; - return CutCornersBorder( - borderRadius: BorderRadius.lerp(outline.borderRadius, borderRadius, t), - borderSide: BorderSide.lerp(outline.borderSide, borderSide, t), - cut: cut, - gapPadding: outline.gapPadding, - ); - } - return super.lerpFrom(a, t); - } - - @override - ShapeBorder lerpTo(ShapeBorder b, double t) { - if (b is CutCornersBorder) { - final CutCornersBorder outline = b; - return CutCornersBorder( - borderRadius: BorderRadius.lerp(borderRadius, outline.borderRadius, t), - borderSide: BorderSide.lerp(borderSide, outline.borderSide, t), - cut: cut, - gapPadding: outline.gapPadding, - ); - } - return super.lerpTo(b, t); - } - - Path _notchedCornerPath(Rect center, [double start = 0.0, double extent = 0.0]) { - final Path path = Path(); - if (start > 0.0 || extent > 0.0) { - path.relativeMoveTo(extent + start, center.top); - _notchedSidesAndBottom(center, path); - path..lineTo(center.left + cut, center.top)..lineTo(start, center.top); - } else { - path.moveTo(center.left + cut, center.top); - _notchedSidesAndBottom(center, path); - path.lineTo(center.left + cut, center.top); - } - return path; - } - - Path _notchedSidesAndBottom(Rect center, Path path) { - return path - ..lineTo(center.right - cut, center.top) - ..lineTo(center.right, center.top + cut) - ..lineTo(center.right, center.top + center.height - cut) - ..lineTo(center.right - cut, center.top + center.height) - ..lineTo(center.left + cut, center.top + center.height) - ..lineTo(center.left, center.top + center.height - cut) - ..lineTo(center.left, center.top + cut); - } - - @override - void paint( - Canvas canvas, - Rect rect, { - double gapStart, - double gapExtent = 0.0, - double gapPercentage = 0.0, - TextDirection textDirection, - }) { - assert(gapExtent != null); - assert(gapPercentage >= 0.0 && gapPercentage <= 1.0); - - final Paint paint = borderSide.toPaint(); - final RRect outer = borderRadius.toRRect(rect); - if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) { - canvas.drawPath(_notchedCornerPath(outer.middleRect), paint); - } else { - final double extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage); - switch (textDirection) { - case TextDirection.rtl: { - final Path path = _notchedCornerPath(outer.middleRect, gapStart + gapPadding - extent, extent); - canvas.drawPath(path, paint); - break; - } - case TextDirection.ltr: { - final Path path = _notchedCornerPath(outer.middleRect, gapStart - gapPadding, extent); - canvas.drawPath(path, paint); - break; - } - } - } - } -} diff --git a/web/gallery/lib/demo/shrine/supplemental/product_card.dart b/web/gallery/lib/demo/shrine/supplemental/product_card.dart deleted file mode 100644 index d2a71a310..000000000 --- a/web/gallery/lib/demo/shrine/supplemental/product_card.dart +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:flutter_gallery/demo/shrine/model/product.dart'; - -class ProductCard extends StatelessWidget { - const ProductCard({ this.imageAspectRatio = 33 / 49, this.product }) - : assert(imageAspectRatio == null || imageAspectRatio > 0); - - final double imageAspectRatio; - final Product product; - - static const double kTextBoxHeight = 65.0; - - @override - Widget build(BuildContext context) { - final NumberFormat formatter = NumberFormat.simpleCurrency( - decimalDigits: 0, - locale: Localizations.localeOf(context).toString(), - ); - - final ThemeData theme = Theme.of(context); - - final Image imageWidget = Image.asset( - product.assetName, - package: product.assetPackage, - fit: BoxFit.cover, - ); - - return ScopedModelDescendant( - builder: (BuildContext context, Widget child, AppStateModel model) { - return GestureDetector( - onTap: () { - model.addProductToCart(product.id); - }, - child: child, - ); - }, - child: Stack( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - AspectRatio( - aspectRatio: imageAspectRatio, - child: imageWidget, - ), - SizedBox( - height: kTextBoxHeight * MediaQuery.of(context).textScaleFactor, - width: 121.0, - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - product == null ? '' : product.name, - style: theme.textTheme.button, - softWrap: false, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - const SizedBox(height: 4.0), - Text( - product == null ? '' : formatter.format(product.price), - style: theme.textTheme.caption, - ), - ], - ), - ), - ], - ), - const Padding( - padding: EdgeInsets.all(16.0), - child: Icon(Icons.add_shopping_cart), - ), - ], - ), - ); - } -} diff --git a/web/gallery/lib/demo/shrine/supplemental/product_columns.dart b/web/gallery/lib/demo/shrine/supplemental/product_columns.dart deleted file mode 100644 index 589f9c7e6..000000000 --- a/web/gallery/lib/demo/shrine/supplemental/product_columns.dart +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018-present the Flutter authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import 'package:flutter/material.dart'; - -import 'package:flutter_gallery/demo/shrine/model/product.dart'; -import 'package:flutter_gallery/demo/shrine/supplemental/product_card.dart'; - -class TwoProductCardColumn extends StatelessWidget { - const TwoProductCardColumn({ - @required this.bottom, - this.top, - }) : assert(bottom != null); - - final Product bottom, top; - - @override - Widget build(BuildContext context) { - return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { - const double spacerHeight = 44.0; - - final double heightOfCards = (constraints.biggest.height - spacerHeight) / 2.0; - final double availableHeightForImages = heightOfCards - ProductCard.kTextBoxHeight; - // Ensure the cards take up the available space as long as the screen is - // sufficiently tall, otherwise fallback on a constant aspect ratio. - final double imageAspectRatio = availableHeightForImages >= 0.0 - ? constraints.biggest.width / availableHeightForImages - : 49.0 / 33.0; - - return ListView( - physics: const ClampingScrollPhysics(), - children: [ - Padding( - padding: const EdgeInsetsDirectional.only(start: 28.0), - child: top != null - ? ProductCard( - imageAspectRatio: imageAspectRatio, - product: top, - ) - : SizedBox( - height: heightOfCards > 0 ? heightOfCards : spacerHeight, - ), - ), - const SizedBox(height: spacerHeight), - Padding( - padding: const EdgeInsetsDirectional.only(end: 28.0), - child: ProductCard( - imageAspectRatio: imageAspectRatio, - product: bottom, - ), - ), - ], - ); - }); - } -} - -class OneProductCardColumn extends StatelessWidget { - const OneProductCardColumn({this.product}); - - final Product product; - - @override - Widget build(BuildContext context) { - return ListView( - physics: const ClampingScrollPhysics(), - reverse: true, - children: [ - const SizedBox( - height: 40.0, - ), - ProductCard( - product: product, - ), - ], - ); - } -} diff --git a/web/gallery/lib/demo/shrine_demo.dart b/web/gallery/lib/demo/shrine_demo.dart deleted file mode 100644 index 6c58ecdcd..000000000 --- a/web/gallery/lib/demo/shrine_demo.dart +++ /dev/null @@ -1,15 +0,0 @@ -// 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_gallery/demo/shrine/app.dart'; - -class ShrineDemo extends StatelessWidget { - const ShrineDemo({ Key key }) : super(key: key); - - static const String routeName = '/shrine'; // Used by the Gallery app. - - @override - Widget build(BuildContext context) => ShrineApp(); -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo.dart b/web/gallery/lib/demo/transformations/transformations_demo.dart deleted file mode 100644 index 8c5a5d8c0..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo.dart +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2014 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:ui' show Vertices; -import 'package:flutter/material.dart'; -import 'transformations_demo_board.dart'; -import 'transformations_demo_edit_board_point.dart'; -import 'transformations_demo_gesture_transformable.dart'; - -class TransformationsDemo extends StatefulWidget { - const TransformationsDemo({ Key key }) : super(key: key); - - static const String routeName = '/transformations'; - - @override _TransformationsDemoState createState() => _TransformationsDemoState(); -} -class _TransformationsDemoState extends State { - // The radius of a hexagon tile in pixels. - static const double _kHexagonRadius = 32.0; - // The margin between hexagons. - static const double _kHexagonMargin = 1.0; - // The radius of the entire board in hexagons, not including the center. - static const int _kBoardRadius = 8; - - bool _reset = false; - Board _board = Board( - boardRadius: _kBoardRadius, - hexagonRadius: _kHexagonRadius, - hexagonMargin: _kHexagonMargin, - ); - - @override - Widget build (BuildContext context) { - final BoardPainter painter = BoardPainter( - board: _board, - ); - - // The scene is drawn by a CustomPaint, but user interaction is handled by - // the GestureTransformable parent widget. - return Scaffold( - appBar: AppBar( - title: const Text('2D Tranformations'), - actions: [ - IconButton( - icon: const Icon(Icons.help), - tooltip: 'Help', - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) => instructionDialog, - ); - }, - ), - ], - ), - body: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - // Draw the scene as big as is available, but allow the user to - // translate beyond that to a visibleSize that's a bit bigger. - final Size size = Size(constraints.maxWidth, constraints.maxHeight); - final Size visibleSize = Size(size.width * 3, size.height * 2); - return GestureTransformable( - reset: _reset, - onResetEnd: () { - setState(() { - _reset = false; - }); - }, - child: CustomPaint( - painter: painter, - ), - boundaryRect: Rect.fromLTWH( - -visibleSize.width / 2, - -visibleSize.height / 2, - visibleSize.width, - visibleSize.height, - ), - // Center the board in the middle of the screen. It's drawn centered - // at the origin, which is the top left corner of the - // GestureTransformable. - initialTranslation: Offset(size.width / 2, size.height / 2), - onTapUp: _onTapUp, - size: size, - ); - }, - ), - floatingActionButton: _board.selected == null ? resetButton : editButton, - ); - } - - Widget get instructionDialog { - return AlertDialog( - title: const Text('2D Transformations'), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: const [ - Text('Tap to edit hex tiles, and use gestures to move around the scene:\n'), - Text('- Drag to pan.'), - Text('- Pinch to zoom.'), - Text('- Rotate with two fingers.'), - Text('\nYou can always press the home button to return to the starting orientation!'), - ], - ), - actions: [ - FlatButton( - child: const Text('OK'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - } - - FloatingActionButton get resetButton { - return FloatingActionButton( - onPressed: () { - setState(() { - _reset = true; - }); - }, - tooltip: 'Reset Transform', - backgroundColor: Theme.of(context).primaryColor, - child: const Icon(Icons.home), - ); - } - - FloatingActionButton get editButton { - return FloatingActionButton( - onPressed: () { - if (_board.selected == null) { - return; - } - showModalBottomSheet(context: context, builder: (BuildContext context) { - return Container( - width: double.infinity, - height: 150, - padding: const EdgeInsets.all(12.0), - child: EditBoardPoint( - boardPoint: _board.selected, - onColorSelection: (Color color) { - setState(() { - _board = _board.copyWithBoardPointColor(_board.selected, color); - Navigator.pop(context); - }); - }, - ), - ); - }); - }, - tooltip: 'Edit Tile', - child: const Icon(Icons.edit), - ); - } - - void _onTapUp(TapUpDetails details) { - final Offset scenePoint = details.globalPosition; - final BoardPoint boardPoint = _board.pointToBoardPoint(scenePoint); - setState(() { - _board = _board.copyWithSelected(boardPoint); - }); - } -} - -// CustomPainter is what is passed to CustomPaint and actually draws the scene -// when its `paint` method is called. -class BoardPainter extends CustomPainter { - const BoardPainter({ - this.board, - }); - - final Board board; - - @override - void paint(Canvas canvas, Size size) { - void drawBoardPoint(BoardPoint boardPoint) { - final Color color = boardPoint.color.withOpacity( - board.selected == boardPoint ? 0.2 : 1.0, - ); - final Vertices vertices = board.getVerticesForBoardPoint(boardPoint, color); - canvas.drawVertices(vertices, BlendMode.color, Paint()); - } - - board.forEach(drawBoardPoint); - } - - // We should repaint whenever the board changes, such as board.selected. - @override - bool shouldRepaint(BoardPainter oldDelegate) { - return oldDelegate.board != board; - } -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo_board.dart b/web/gallery/lib/demo/transformations/transformations_demo_board.dart deleted file mode 100644 index 8d830e527..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo_board.dart +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2014 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:collection' show IterableMixin; -import 'dart:math'; -import 'dart:ui' show Vertices; -import 'package:flutter/material.dart' hide Gradient; -import 'package:vector_math/vector_math_64.dart' show Vector3; - -// The entire state of the hex board and abstraction to get information about -// it. Iterable so that all BoardPoints on the board can be iterated over. -@immutable -class Board extends Object with IterableMixin { - Board({ - @required this.boardRadius, - @required this.hexagonRadius, - @required this.hexagonMargin, - this.selected, - List boardPoints, - }) : assert(boardRadius > 0), - assert(hexagonRadius > 0), - assert(hexagonMargin >= 0) { - // Set up the positions for the center hexagon where the entire board is - // centered on the origin. - // Start point of hexagon (top vertex). - final Point hexStart = Point(0, -hexagonRadius); - final double hexagonRadiusPadded = hexagonRadius - hexagonMargin; - final double centerToFlat = sqrt(3) / 2 * hexagonRadiusPadded; - positionsForHexagonAtOrigin.addAll([ - Offset(hexStart.x, hexStart.y), - Offset(hexStart.x + centerToFlat, hexStart.y + 0.5 * hexagonRadiusPadded), - Offset(hexStart.x + centerToFlat, hexStart.y + 1.5 * hexagonRadiusPadded), - Offset(hexStart.x + centerToFlat, hexStart.y + 1.5 * hexagonRadiusPadded), - Offset(hexStart.x, hexStart.y + 2 * hexagonRadiusPadded), - Offset(hexStart.x, hexStart.y + 2 * hexagonRadiusPadded), - Offset(hexStart.x - centerToFlat, hexStart.y + 1.5 * hexagonRadiusPadded), - Offset(hexStart.x - centerToFlat, hexStart.y + 1.5 * hexagonRadiusPadded), - Offset(hexStart.x - centerToFlat, hexStart.y + 0.5 * hexagonRadiusPadded), - ]); - - if (boardPoints != null) { - _boardPoints.addAll(boardPoints); - } else { - // Generate boardPoints for a fresh board. - BoardPoint boardPoint = _getNextBoardPoint(null); - while (boardPoint != null) { - _boardPoints.add(boardPoint); - boardPoint = _getNextBoardPoint(boardPoint); - } - } - } - - final int boardRadius; // Number of hexagons from center to edge. - final double hexagonRadius; // Pixel radius of a hexagon (center to vertex). - final double hexagonMargin; // Margin between hexagons. - final List positionsForHexagonAtOrigin = []; - final BoardPoint selected; - final List _boardPoints = []; - - @override - Iterator get iterator => _BoardIterator(_boardPoints); - - // For a given q axial coordinate, get the range of possible r values - // See the definition of BoardPoint for more information about hex grids and - // axial coordinates. - _Range _getRRangeForQ(int q) { - int rStart; - int rEnd; - if (q <= 0) { - rStart = -boardRadius - q; - rEnd = boardRadius; - } else { - rEnd = boardRadius - q; - rStart = -boardRadius; - } - - return _Range(rStart, rEnd); - } - - // Get the BoardPoint that comes after the given BoardPoint. If given null, - // returns the origin BoardPoint. If given BoardPoint is the last, returns - // null. - BoardPoint _getNextBoardPoint (BoardPoint boardPoint) { - // If before the first element. - if (boardPoint == null) { - return BoardPoint(-boardRadius, 0); - } - - final _Range rRange = _getRRangeForQ(boardPoint.q); - - // If at or after the last element. - if (boardPoint.q >= boardRadius && boardPoint.r >= rRange.max) { - return null; - } - - // If wrapping from one q to the next. - if (boardPoint.r >= rRange.max) { - return BoardPoint(boardPoint.q + 1, _getRRangeForQ(boardPoint.q + 1).min); - } - - // Otherwise we're just incrementing r. - return BoardPoint(boardPoint.q, boardPoint.r + 1); - } - - // Check if the board point is actually on the board. - bool _validateBoardPoint(BoardPoint boardPoint) { - const BoardPoint center = BoardPoint(0, 0); - final int distanceFromCenter = getDistance(center, boardPoint); - return distanceFromCenter <= boardRadius; - } - - // Get the distance between two BoardPoins. - static int getDistance(BoardPoint a, BoardPoint b) { - final Vector3 a3 = a.cubeCoordinates; - final Vector3 b3 = b.cubeCoordinates; - return - ((a3.x - b3.x).abs() + (a3.y - b3.y).abs() + (a3.z - b3.z).abs()) ~/ 2; - } - - // Return the q,r BoardPoint for a point in the scene, where the origin is in - // the center of the board in both coordinate systems. If no BoardPoint at the - // location, return null. - BoardPoint pointToBoardPoint(Offset point) { - final BoardPoint boardPoint = BoardPoint( - ((sqrt(3) / 3 * point.dx - 1 / 3 * point.dy) / hexagonRadius).round(), - ((2 / 3 * point.dy) / hexagonRadius).round(), - ); - - if (!_validateBoardPoint(boardPoint)) { - return null; - } - - return _boardPoints.firstWhere((BoardPoint boardPointI) { - return boardPointI.q == boardPoint.q && boardPointI.r == boardPoint.r; - }); - } - - // Return a scene point for the center of a hexagon given its q,r point. - Point boardPointToPoint(BoardPoint boardPoint) { - return Point( - sqrt(3) * hexagonRadius * boardPoint.q + sqrt(3) / 2 * hexagonRadius * boardPoint.r, - 1.5 * hexagonRadius * boardPoint.r, - ); - } - - // Get Vertices that can be drawn to a Canvas for the given BoardPoint. - Vertices getVerticesForBoardPoint(BoardPoint boardPoint, Color color) { - final Point centerOfHexZeroCenter = boardPointToPoint(boardPoint); - - final List positions = positionsForHexagonAtOrigin.map((Offset offset) { - return offset.translate(centerOfHexZeroCenter.x, centerOfHexZeroCenter.y); - }).toList(); - - return Vertices( - VertexMode.triangleFan, - positions, - colors: List.filled(positions.length, color), - ); - } - - // Return a new board with the given BoardPoint selected. - Board copyWithSelected(BoardPoint boardPoint) { - if (selected == boardPoint) { - return this; - } - final Board nextBoard = Board( - boardRadius: boardRadius, - hexagonRadius: hexagonRadius, - hexagonMargin: hexagonMargin, - selected: boardPoint, - boardPoints: _boardPoints, - ); - return nextBoard; - } - - // Return a new board where boardPoint has the given color. - Board copyWithBoardPointColor(BoardPoint boardPoint, Color color) { - final BoardPoint nextBoardPoint = boardPoint.copyWithColor(color); - final int boardPointIndex = _boardPoints.indexWhere((BoardPoint boardPointI) => - boardPointI.q == boardPoint.q && boardPointI.r == boardPoint.r - ); - - if (elementAt(boardPointIndex) == boardPoint && boardPoint.color == color) { - return this; - } - - final List nextBoardPoints = List.from(_boardPoints); - nextBoardPoints[boardPointIndex] = nextBoardPoint; - final BoardPoint selectedBoardPoint = boardPoint == selected - ? nextBoardPoint - : selected; - return Board( - boardRadius: boardRadius, - hexagonRadius: hexagonRadius, - hexagonMargin: hexagonMargin, - selected: selectedBoardPoint, - boardPoints: nextBoardPoints, - ); - } -} - -class _BoardIterator extends Iterator { - _BoardIterator(this.boardPoints); - - final List boardPoints; - int currentIndex; - - @override - BoardPoint current; - - @override - bool moveNext() { - if (currentIndex == null) { - currentIndex = 0; - } else { - currentIndex++; - } - - if (currentIndex >= boardPoints.length) { - current = null; - return false; - } - - current = boardPoints[currentIndex]; - return true; - } -} - -// A range of q/r board coordinate values. -@immutable -class _Range { - const _Range(this.min, this.max) - : assert(min != null), - assert(max != null), - assert(min <= max); - - final int min; - final int max; -} - -final Set boardPointColors = { - Colors.grey, - Colors.black, - Colors.red, - Colors.blue, -}; - -// A location on the board in axial coordinates. -// Axial coordinates use two integers, q and r, to locate a hexagon on a grid. -// https://www.redblobgames.com/grids/hexagons/#coordinates-axial -@immutable -class BoardPoint { - const BoardPoint(this.q, this.r, { - this.color = Colors.grey, - }); - - final int q; - final int r; - final Color color; - - @override - String toString() { - return 'BoardPoint($q, $r, $color)'; - } - - // Only compares by location. - @override - bool operator ==(dynamic other) { - if (other.runtimeType != runtimeType) { - return false; - } - final BoardPoint boardPoint = other; - return boardPoint.q == q && boardPoint.r == r; - } - - @override - int get hashCode => hashValues(q, r); - - BoardPoint copyWithColor(Color nextColor) => BoardPoint(q, r, color: nextColor); - - // Convert from q,r axial coords to x,y,z cube coords. - Vector3 get cubeCoordinates { - return Vector3( - q.toDouble(), - r.toDouble(), - (-q - r).toDouble(), - ); - } -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo_color_picker.dart b/web/gallery/lib/demo/transformations/transformations_demo_color_picker.dart deleted file mode 100644 index 80e612d87..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo_color_picker.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2014 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'; - -// A generic widget for a list of selectable colors. -@immutable -class ColorPicker extends StatelessWidget { - const ColorPicker({ - @required this.colors, - @required this.selectedColor, - this.onColorSelection, - }) : assert(colors != null), - assert(selectedColor != null); - - final Set colors; - final Color selectedColor; - final ValueChanged onColorSelection; - - @override - Widget build (BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: colors.map((Color color) { - return _ColorPickerSwatch( - color: color, - selected: color == selectedColor, - onTap: () { - if (onColorSelection != null) { - onColorSelection(color); - } - }, - ); - }).toList(), - ); - } -} - -// A single selectable color widget in the ColorPicker. -@immutable -class _ColorPickerSwatch extends StatelessWidget { - const _ColorPickerSwatch({ - @required this.color, - @required this.selected, - this.onTap, - }) : assert(color != null), - assert(selected != null); - - final Color color; - final bool selected; - final Function onTap; - - @override - Widget build (BuildContext context) { - return Container( - width: 60.0, - height: 60.0, - padding: const EdgeInsets.fromLTRB(2.0, 0.0, 2.0, 0.0), - child: RawMaterialButton( - fillColor: color, - onPressed: () { - if (onTap != null) { - onTap(); - } - }, - child: !selected ? null : const Icon( - Icons.check, - color: Colors.white, - ), - ), - ); - } -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo_edit_board_point.dart b/web/gallery/lib/demo/transformations/transformations_demo_edit_board_point.dart deleted file mode 100644 index b9803d865..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo_edit_board_point.dart +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 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 'transformations_demo_board.dart'; -import 'transformations_demo_color_picker.dart'; - -// The panel for editing a board point. -@immutable -class EditBoardPoint extends StatelessWidget { - const EditBoardPoint({ - Key key, - @required this.boardPoint, - this.onColorSelection, - }) : assert(boardPoint != null), - super(key: key); - - final BoardPoint boardPoint; - final ValueChanged onColorSelection; - - @override - Widget build (BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - '${boardPoint.q}, ${boardPoint.r}', - textAlign: TextAlign.right, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ColorPicker( - colors: boardPointColors, - selectedColor: boardPoint.color, - onColorSelection: onColorSelection, - ), - ], - ); - } -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo_gesture_transformable.dart b/web/gallery/lib/demo/transformations/transformations_demo_gesture_transformable.dart deleted file mode 100644 index 54f55e137..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo_gesture_transformable.dart +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2014 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:vector_math/vector_math_64.dart' show Vector3; -import 'transformations_demo_inertial_motion.dart'; - -// This widget allows 2D transform interactions on its child in relation to its -// parent. The user can transform the child by dragging to pan or pinching to -// zoom and rotate. All event callbacks for GestureDetector are supported, and -// the coordinates that are given are untransformed and in relation to the -// original position of the child. -@immutable -class GestureTransformable extends StatefulWidget { - const GestureTransformable({ - Key key, - // The child to perform the transformations on. - @required this.child, - // The desired visible size of the widget and the area that is receptive to - // gestures. If a widget that's as big as possible is desired, then wrap - // this in a LayoutBuilder and pass - // `Size(constraints.maxWidth, constraints.maxHeight)`. - @required this.size, - // The scale will be clamped to between these values. A maxScale of null has - // no bounds. minScale must be greater than zero. - this.maxScale = 2.5, - this.minScale = 0.8, - // Transforms will be limited so that the viewport can not view beyond this - // Rect. The Rect does not rotate with the rest of the scene, so it is - // always aligned with the viewport. A null boundaryRect results in no - // limits to the distance that the viewport can be transformed to see. - this.boundaryRect, - // Initial values for the transform can be provided. - this.initialTranslation, - this.initialScale, - this.initialRotation, - // Any and all of the possible transformations can be disabled. - this.disableTranslation = false, - this.disableScale = false, - this.disableRotation = false, - // If set to true, this widget will animate back to its initial transform - // and call onResetEnd when done. When utilizing reset, onResetEnd should - // also be implemented, and it should set reset to false when called. - this.reset = false, - // Access to event callbacks from GestureDetector. Called with untransformed - // coordinates in an Offset. - this.onTapDown, - this.onTapUp, - this.onTap, - this.onTapCancel, - this.onDoubleTap, - this.onLongPress, - this.onLongPressUp, - this.onVerticalDragDown, - this.onVerticalDragStart, - this.onVerticalDragUpdate, - this.onVerticalDragEnd, - this.onVerticalDragCancel, - this.onHorizontalDragDown, - this.onHorizontalDragStart, - this.onHorizontalDragUpdate, - this.onHorizontalDragEnd, - this.onHorizontalDragCancel, - this.onPanDown, - this.onPanStart, - this.onPanUpdate, - this.onPanEnd, - this.onPanCancel, - this.onResetEnd, - this.onScaleStart, - this.onScaleUpdate, - this.onScaleEnd, - }) : assert(child != null), - assert(size != null), - assert(minScale != null), - assert(minScale > 0), - assert(disableTranslation != null), - assert(disableScale != null), - assert(disableRotation != null), - assert(reset != null), - assert( - !reset || onResetEnd != null, - 'Must implement onResetEnd to use reset.', - ), - super(key: key); - - final Widget child; - final Size size; - final bool reset; - final GestureTapDownCallback onTapDown; - final GestureTapUpCallback onTapUp; - final GestureTapCallback onTap; - final GestureTapCancelCallback onTapCancel; - final GestureTapCallback onDoubleTap; - final GestureLongPressCallback onLongPress; - final GestureLongPressUpCallback onLongPressUp; - final GestureDragDownCallback onVerticalDragDown; - final GestureDragStartCallback onVerticalDragStart; - final GestureDragUpdateCallback onVerticalDragUpdate; - final GestureDragEndCallback onVerticalDragEnd; - final GestureDragCancelCallback onVerticalDragCancel; - final GestureDragDownCallback onHorizontalDragDown; - final GestureDragStartCallback onHorizontalDragStart; - final GestureDragUpdateCallback onHorizontalDragUpdate; - final GestureDragEndCallback onHorizontalDragEnd; - final GestureDragCancelCallback onHorizontalDragCancel; - final GestureDragDownCallback onPanDown; - final GestureDragStartCallback onPanStart; - final GestureDragUpdateCallback onPanUpdate; - final GestureDragEndCallback onPanEnd; - final GestureDragCancelCallback onPanCancel; - final VoidCallback onResetEnd; - final GestureScaleStartCallback onScaleStart; - final GestureScaleUpdateCallback onScaleUpdate; - final GestureScaleEndCallback onScaleEnd; - final double maxScale; - final double minScale; - final Rect boundaryRect; - final bool disableTranslation; - final bool disableScale; - final bool disableRotation; - final Offset initialTranslation; - final double initialScale; - final double initialRotation; - - @override _GestureTransformableState createState() => _GestureTransformableState(); -} - -// A single user event can only represent one of these gestures. The user can't -// do multiple at the same time, which results in more precise transformations. -enum _GestureType { - translate, - scale, - rotate, -} - -// This is public only for access from a unit test. -class _GestureTransformableState extends State with TickerProviderStateMixin { - Animation _animation; - AnimationController _controller; - Animation _animationReset; - AnimationController _controllerReset; - // The translation that will be applied to the scene (not viewport). - // A positive x offset moves the scene right, viewport left. - // A positive y offset moves the scene down, viewport up. - Offset _translateFromScene; // Point where a single translation began. - double _scaleStart; // Scale value at start of scaling gesture. - double _rotationStart = 0.0; // Rotation at start of rotation gesture. - Rect _boundaryRect; - Matrix4 _transform = Matrix4.identity(); - double _currentRotation = 0.0; - _GestureType gestureType; - - // The transformation matrix that gives the initial home position. - Matrix4 get _initialTransform { - Matrix4 matrix = Matrix4.identity(); - if (widget.initialTranslation != null) { - matrix = matrixTranslate(matrix, widget.initialTranslation); - } - if (widget.initialScale != null) { - matrix = matrixScale(matrix, widget.initialScale); - } - if (widget.initialRotation != null) { - matrix = matrixRotate(matrix, widget.initialRotation, Offset.zero); - } - return matrix; - } - - // Return the scene point at the given viewport point. - static Offset fromViewport(Offset viewportPoint, Matrix4 transform) { - // On viewportPoint, perform the inverse transformation of the scene to get - // where the point would be in the scene before the transformation. - final Matrix4 inverseMatrix = Matrix4.inverted(transform); - final Vector3 untransformed = inverseMatrix.transform3(Vector3( - viewportPoint.dx, - viewportPoint.dy, - 0, - )); - return Offset(untransformed.x, untransformed.y); - } - - // Get the offset of the current widget from the global screen coordinates. - // TODO(justinmc): Protect against calling this during first build. - static Offset getOffset(BuildContext context) { - final RenderBox renderObject = context.findRenderObject(); - return renderObject.localToGlobal(Offset.zero); - } - - @override - void initState() { - super.initState(); - _boundaryRect = widget.boundaryRect ?? Offset.zero & widget.size; - _transform = _initialTransform; - _controller = AnimationController( - vsync: this, - ); - _controllerReset = AnimationController( - vsync: this, - ); - if (widget.reset) { - _animateResetInitialize(); - } - } - - @override - void didUpdateWidget(GestureTransformable oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.reset && !oldWidget.reset && _animationReset == null) { - _animateResetInitialize(); - } else if (!widget.reset && oldWidget.reset && _animationReset != null) { - _animateResetStop(); - } - } - - @override - Widget build(BuildContext context) { - // A GestureDetector allows the detection of panning and zooming gestures on - // its child, which is the CustomPaint. - return GestureDetector( - behavior: HitTestBehavior.opaque, // Necessary when translating off screen - onTapDown: widget.onTapDown == null ? null : (TapDownDetails details) { - widget.onTapDown(TapDownDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onTapUp: widget.onTapUp == null ? null : (TapUpDetails details) { - widget.onTapUp(TapUpDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onTap: widget.onTap, - onTapCancel: widget.onTapCancel, - onDoubleTap: widget.onDoubleTap, - onLongPress: widget.onLongPress, - onLongPressUp: widget.onLongPressUp, - onVerticalDragDown: widget.onVerticalDragDown == null ? null : (DragDownDetails details) { - widget.onVerticalDragDown(DragDownDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onVerticalDragStart: widget.onVerticalDragStart == null ? null : (DragStartDetails details) { - widget.onVerticalDragStart(DragStartDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onVerticalDragUpdate: widget.onVerticalDragUpdate == null ? null : (DragUpdateDetails details) { - widget.onVerticalDragUpdate(DragUpdateDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onVerticalDragEnd: widget.onVerticalDragEnd, - onVerticalDragCancel: widget.onVerticalDragCancel, - onHorizontalDragDown: widget.onHorizontalDragDown == null ? null : (DragDownDetails details) { - widget.onHorizontalDragDown(DragDownDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onHorizontalDragStart: widget.onHorizontalDragStart == null ? null : (DragStartDetails details) { - widget.onHorizontalDragStart(DragStartDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onHorizontalDragUpdate: widget.onHorizontalDragUpdate == null ? null : (DragUpdateDetails details) { - widget.onHorizontalDragUpdate(DragUpdateDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onHorizontalDragEnd: widget.onHorizontalDragEnd, - onHorizontalDragCancel: widget.onHorizontalDragCancel, - onPanDown: widget.onPanDown == null ? null : (DragDownDetails details) { - widget.onPanDown(DragDownDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onPanStart: widget.onPanStart == null ? null : (DragStartDetails details) { - widget.onPanStart(DragStartDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onPanUpdate: widget.onPanUpdate == null ? null : (DragUpdateDetails details) { - widget.onPanUpdate(DragUpdateDetails( - globalPosition: fromViewport(details.globalPosition - getOffset(context), _transform), - )); - }, - onPanEnd: widget.onPanEnd, - onPanCancel: widget.onPanCancel, - onScaleEnd: _onScaleEnd, - onScaleStart: _onScaleStart, - onScaleUpdate: _onScaleUpdate, - child: ClipRect( - // The scene is panned/zoomed/rotated using this Transform widget. - child: Transform( - transform: _transform, - child: Container( - child: widget.child, - height: widget.size.height, - width: widget.size.width, - ), - ), - ), - ); - } - - // Return a new matrix representing the given matrix after applying the given - // translation. - Matrix4 matrixTranslate(Matrix4 matrix, Offset translation) { - if (widget.disableTranslation || translation == Offset.zero) { - return matrix; - } - - // Clamp translation so the viewport remains inside _boundaryRect. - final double scale = _transform.getMaxScaleOnAxis(); - final Size scaledSize = widget.size / scale; - final Rect viewportBoundaries = Rect.fromLTRB( - _boundaryRect.left, - _boundaryRect.top, - _boundaryRect.right - scaledSize.width, - _boundaryRect.bottom - scaledSize.height, - ); - // Translation is reversed (a positive translation moves the scene to the - // right, viewport to the left). - final Rect translationBoundaries = Rect.fromLTRB( - -scale * viewportBoundaries.right, - -scale * viewportBoundaries.bottom, - -scale * viewportBoundaries.left, - -scale * viewportBoundaries.top, - ); - final Matrix4 nextMatrix = matrix.clone()..translate( - translation.dx, - translation.dy, - ); - final Vector3 nextTranslationVector = nextMatrix.getTranslation(); - final Offset nextTranslation = Offset( - nextTranslationVector.x, - nextTranslationVector.y, - ); - final bool inBoundaries = translationBoundaries.contains( - Offset(nextTranslation.dx, nextTranslation.dy), - ); - if (!inBoundaries) { - // TODO(justinmc): Instead of canceling translation when it goes out of - // bounds, stop translation at boundary. - return matrix; - } - - return nextMatrix; - } - - // Return a new matrix representing the given matrix after applying the given - // scale transform. - Matrix4 matrixScale(Matrix4 matrix, double scale) { - if (widget.disableScale || scale == 1) { - return matrix; - } - assert(scale != 0); - - // Don't allow a scale that moves the viewport outside of _boundaryRect. - final Offset tl = fromViewport(const Offset(0, 0), _transform); - final Offset tr = fromViewport(Offset(widget.size.width, 0), _transform); - final Offset bl = fromViewport(Offset(0, widget.size.height), _transform); - final Offset br = fromViewport( - Offset(widget.size.width, widget.size.height), - _transform, - ); - if (!_boundaryRect.contains(tl) - || !_boundaryRect.contains(tr) - || !_boundaryRect.contains(bl) - || !_boundaryRect.contains(br)) { - return matrix; - } - - // Don't allow a scale that results in an overall scale beyond min/max - // scale. - final double currentScale = _transform.getMaxScaleOnAxis(); - final double totalScale = currentScale * scale; - final double clampedTotalScale = totalScale.clamp( - widget.minScale, - widget.maxScale, - ); - final double clampedScale = clampedTotalScale / currentScale; - return matrix..scale(clampedScale); - } - - // Return a new matrix representing the given matrix after applying the given - // rotation transform. - // Rotating the scene cannot cause the viewport to view beyond _boundaryRect. - Matrix4 matrixRotate(Matrix4 matrix, double rotation, Offset focalPoint) { - if (widget.disableRotation || rotation == 0) { - return matrix; - } - final Offset focalPointScene = fromViewport(focalPoint, matrix); - return matrix - ..translate(focalPointScene.dx, focalPointScene.dy) - ..rotateZ(-rotation) - ..translate(-focalPointScene.dx, -focalPointScene.dy); - } - - // Handle the start of a gesture of _GestureType. - void _onScaleStart(ScaleStartDetails details) { - if (widget.onScaleStart != null) { - widget.onScaleStart(details); - } - - if (_controller.isAnimating) { - _controller.stop(); - _controller.reset(); - _animation?.removeListener(_onAnimate); - _animation = null; - } - if (_controllerReset.isAnimating) { - _animateResetStop(); - } - - gestureType = null; - setState(() { - _scaleStart = _transform.getMaxScaleOnAxis(); - _translateFromScene = fromViewport(details.focalPoint, _transform); - _rotationStart = _currentRotation; - }); - } - - // Handle an update to an ongoing gesture of _GestureType. - void _onScaleUpdate(ScaleUpdateDetails details) { - double scale = _transform.getMaxScaleOnAxis(); - if (widget.onScaleUpdate != null) { - widget.onScaleUpdate(ScaleUpdateDetails( - focalPoint: fromViewport(details.focalPoint, _transform), - scale: details.scale, - rotation: details.rotation, - )); - } - final Offset focalPointScene = fromViewport( - details.focalPoint, - _transform, - ); - if (gestureType == null) { - // Decide which type of gesture this is by comparing the amount of scale - // and rotation in the gesture, if any. Scale starts at 1 and rotation - // starts at 0. Translate will have 0 scale and 0 rotation because it uses - // only one finger. - if ((details.scale - 1).abs() > details.rotation.abs()) { - gestureType = _GestureType.scale; - } else if (details.rotation != 0) { - gestureType = _GestureType.rotate; - } else { - gestureType = _GestureType.translate; - } - } - setState(() { - if (gestureType == _GestureType.scale && _scaleStart != null) { - // details.scale gives us the amount to change the scale as of the - // start of this gesture, so calculate the amount to scale as of the - // previous call to _onScaleUpdate. - final double desiredScale = _scaleStart * details.scale; - final double scaleChange = desiredScale / scale; - _transform = matrixScale(_transform, scaleChange); - scale = _transform.getMaxScaleOnAxis(); - - // While scaling, translate such that the user's two fingers stay on the - // same places in the scene. That means that the focal point of the - // scale should be on the same place in the scene before and after the - // scale. - final Offset focalPointSceneNext = fromViewport( - details.focalPoint, - _transform, - ); - _transform = matrixTranslate(_transform, focalPointSceneNext - focalPointScene); - } else if (gestureType == _GestureType.rotate && details.rotation != 0.0) { - final double desiredRotation = _rotationStart + details.rotation; - _transform = matrixRotate(_transform, _currentRotation - desiredRotation, details.focalPoint); - _currentRotation = desiredRotation; - } else if (_translateFromScene != null && details.scale == 1.0) { - // Translate so that the same point in the scene is underneath the - // focal point before and after the movement. - final Offset translationChange = focalPointScene - _translateFromScene; - _transform = matrixTranslate(_transform, translationChange); - _translateFromScene = fromViewport(details.focalPoint, _transform); - } - }); - } - - // Handle the end of a gesture of _GestureType. - void _onScaleEnd(ScaleEndDetails details) { - if (widget.onScaleEnd != null) { - widget.onScaleEnd(details); - } - setState(() { - _scaleStart = null; - _rotationStart = null; - _translateFromScene = null; - }); - - _animation?.removeListener(_onAnimate); - _controller.reset(); - - // If the scale ended with velocity, animate inertial movement - final double velocityTotal = details.velocity.pixelsPerSecond.dx.abs() - + details.velocity.pixelsPerSecond.dy.abs(); - if (velocityTotal == 0) { - return; - } - - final Vector3 translationVector = _transform.getTranslation(); - final Offset translation = Offset(translationVector.x, translationVector.y); - final InertialMotion inertialMotion = InertialMotion(details.velocity, translation); - _animation = Tween( - begin: translation, - end: inertialMotion.finalPosition, - ).animate(_controller); - _controller.duration = Duration(milliseconds: inertialMotion.duration.toInt()); - _animation.addListener(_onAnimate); - _controller.fling(); - } - - // Handle inertia drag animation. - void _onAnimate() { - setState(() { - // Translate _transform such that the resulting translation is - // _animation.value. - final Vector3 translationVector = _transform.getTranslation(); - final Offset translation = Offset(translationVector.x, translationVector.y); - final Offset translationScene = fromViewport(translation, _transform); - final Offset animationScene = fromViewport(_animation.value, _transform); - final Offset translationChangeScene = animationScene - translationScene; - _transform = matrixTranslate(_transform, translationChangeScene); - }); - if (!_controller.isAnimating) { - _animation?.removeListener(_onAnimate); - _animation = null; - _controller.reset(); - } - } - - // Handle reset to home transform animation. - void _onAnimateReset() { - setState(() { - _transform = _animationReset.value; - }); - if (!_controllerReset.isAnimating) { - _animationReset?.removeListener(_onAnimateReset); - _animationReset = null; - _controllerReset.reset(); - widget.onResetEnd(); - } - } - - // Initialize the reset to home transform animation. - void _animateResetInitialize() { - _controllerReset.reset(); - _animationReset = Matrix4Tween( - begin: _transform, - end: _initialTransform, - ).animate(_controllerReset); - _controllerReset.duration = const Duration(milliseconds: 400); - _animationReset.addListener(_onAnimateReset); - _controllerReset.forward(); - } - - // Stop a running reset to home transform animation. - void _animateResetStop() { - _controllerReset.stop(); - _animationReset?.removeListener(_onAnimateReset); - _animationReset = null; - _controllerReset.reset(); - widget.onResetEnd(); - } - - @override - void dispose() { - _controller.dispose(); - _controllerReset.dispose(); - super.dispose(); - } -} diff --git a/web/gallery/lib/demo/transformations/transformations_demo_inertial_motion.dart b/web/gallery/lib/demo/transformations/transformations_demo_inertial_motion.dart deleted file mode 100644 index 389e46a4d..000000000 --- a/web/gallery/lib/demo/transformations/transformations_demo_inertial_motion.dart +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 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'; -import 'package:flutter/material.dart'; -import 'package:vector_math/vector_math.dart' show Vector2; - -// Provides calculations for an object moving with inertia and friction using -// the equation of motion from physics. -// https://en.wikipedia.org/wiki/Equations_of_motion#Constant_translational_acceleration_in_a_straight_line -// TODO(justinmc): Can this be replaced with friction_simulation.dart? -@immutable -class InertialMotion { - const InertialMotion(this._initialVelocity, this._initialPosition); - - static const double _kFrictionalAcceleration = 0.01; // How quickly to stop - final Velocity _initialVelocity; - final Offset _initialPosition; - - // The position when the motion stops. - Offset get finalPosition { - return _getPositionAt(Duration(milliseconds: duration.toInt())); - } - - // The total time that the animation takes start to stop in milliseconds. - double get duration { - return (_initialVelocity.pixelsPerSecond.dx / 1000 / _acceleration.x).abs(); - } - - // The acceleration opposing the initial velocity in x and y components. - Vector2 get _acceleration { - // TODO(justinmc): Find actual velocity instead of summing? - final double velocityTotal = _initialVelocity.pixelsPerSecond.dx.abs() - + _initialVelocity.pixelsPerSecond.dy.abs(); - final double vRatioX = _initialVelocity.pixelsPerSecond.dx / velocityTotal; - final double vRatioY = _initialVelocity.pixelsPerSecond.dy / velocityTotal; - return Vector2( - _kFrictionalAcceleration * vRatioX, - _kFrictionalAcceleration * vRatioY, - ); - } - - // The position at a given time. - Offset _getPositionAt(Duration time) { - final double xf = _getPosition( - r0: _initialPosition.dx, - v0: _initialVelocity.pixelsPerSecond.dx / 1000, - t: time.inMilliseconds, - a: _acceleration.x, - ); - final double yf = _getPosition( - r0: _initialPosition.dy, - v0: _initialVelocity.pixelsPerSecond.dy / 1000, - t: time.inMilliseconds, - a: _acceleration.y, - ); - return Offset(xf, yf); - } - - // Solve the equation of motion to find the position at a given point in time - // in one dimension. - double _getPosition({double r0, double v0, int t, double a}) { - // Stop movement when it would otherwise reverse direction. - final double stopTime = (v0 / a).abs(); - if (t > stopTime) { - t = stopTime.toInt(); - } - - return r0 + v0 * t + 0.5 * a * pow(t, 2); - } -} diff --git a/web/gallery/lib/demo/typography_demo.dart b/web/gallery/lib/demo/typography_demo.dart deleted file mode 100644 index b974be556..000000000 --- a/web/gallery/lib/demo/typography_demo.dart +++ /dev/null @@ -1,74 +0,0 @@ -// 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'; - -class TextStyleItem extends StatelessWidget { - const TextStyleItem({ - Key key, - @required this.name, - @required this.style, - @required this.text, - }) : assert(name != null), - assert(style != null), - assert(text != null), - super(key: key); - - final String name; - final TextStyle style; - final String text; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextStyle nameStyle = theme.textTheme.caption.copyWith(color: theme.textTheme.caption.color); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 72.0, - child: Text(name, style: nameStyle), - ), - Expanded( - child: Text(text, style: style.copyWith(height: 1.0)), - ), - ], - ), - ); - } -} - -class TypographyDemo extends StatelessWidget { - static const String routeName = '/typography'; - - @override - Widget build(BuildContext context) { - final TextTheme textTheme = Theme.of(context).textTheme; - final List styleItems = [ - if (MediaQuery.of(context).size.width > 500.0) - TextStyleItem(name: 'Display 4', style: textTheme.display4, text: 'Light 112sp'), - TextStyleItem(name: 'Display 3', style: textTheme.display3, text: 'Regular 56sp'), - TextStyleItem(name: 'Display 2', style: textTheme.display2, text: 'Regular 45sp'), - TextStyleItem(name: 'Display 1', style: textTheme.display1, text: 'Regular 34sp'), - TextStyleItem(name: 'Headline', style: textTheme.headline, text: 'Regular 24sp'), - TextStyleItem(name: 'Title', style: textTheme.title, text: 'Medium 20sp'), - TextStyleItem(name: 'Subheading', style: textTheme.subhead, text: 'Regular 16sp'), - TextStyleItem(name: 'Body 2', style: textTheme.body2, text: 'Medium 14sp'), - TextStyleItem(name: 'Body 1', style: textTheme.body1, text: 'Regular 14sp'), - TextStyleItem(name: 'Caption', style: textTheme.caption, text: 'Regular 12sp'), - TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp'), - ]; - - return Scaffold( - appBar: AppBar(title: const Text('Typography')), - body: SafeArea( - top: false, - bottom: false, - child: Scrollbar(child: ListView(children: styleItems)), - ), - ); - } -} diff --git a/web/gallery/lib/demo/video_demo.dart b/web/gallery/lib/demo/video_demo.dart deleted file mode 100644 index 81f7bfcec..000000000 --- a/web/gallery/lib/demo/video_demo.dart +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2017 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:async'; -import 'dart:io'; -import 'package:connectivity/connectivity.dart'; -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; -import 'package:device_info/device_info.dart'; - -class VideoCard extends StatelessWidget { - const VideoCard({ Key key, this.controller, this.title, this.subtitle }) : super(key: key); - - final VideoPlayerController controller; - final String title; - final String subtitle; - - Widget _buildInlineVideo() { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 30.0), - child: Center( - child: AspectRatio( - aspectRatio: 3 / 2, - child: Hero( - tag: controller, - child: VideoPlayerLoading(controller), - ), - ), - ), - ); - } - - Widget _buildFullScreenVideo() { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: AspectRatio( - aspectRatio: 3 / 2, - child: Hero( - tag: controller, - child: VideoPlayPause(controller), - ), - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - Widget fullScreenRoutePageBuilder( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - ) { - return _buildFullScreenVideo(); - } - - void pushFullScreenWidget() { - final TransitionRoute route = PageRouteBuilder( - settings: RouteSettings(name: title, isInitialRoute: false), - pageBuilder: fullScreenRoutePageBuilder, - ); - - route.completed.then((void value) { - controller.setVolume(0.0); - }); - - controller.setVolume(1.0); - Navigator.of(context).push(route); - } - - return SafeArea( - top: false, - bottom: false, - child: Card( - child: Column( - children: [ - ListTile(title: Text(title), subtitle: Text(subtitle)), - GestureDetector( - onTap: pushFullScreenWidget, - child: _buildInlineVideo(), - ), - ], - ), - ), - ); - } -} - -class VideoPlayerLoading extends StatefulWidget { - const VideoPlayerLoading(this.controller); - - final VideoPlayerController controller; - - @override - _VideoPlayerLoadingState createState() => _VideoPlayerLoadingState(); -} - -class _VideoPlayerLoadingState extends State { - bool _initialized; - - @override - void initState() { - super.initState(); - _initialized = widget.controller.value.initialized; - widget.controller.addListener(() { - if (!mounted) { - return; - } - final bool controllerInitialized = widget.controller.value.initialized; - if (_initialized != controllerInitialized) { - setState(() { - _initialized = controllerInitialized; - }); - } - }); - } - - @override - Widget build(BuildContext context) { - if (_initialized) { - return VideoPlayer(widget.controller); - } - return Stack( - children: [ - VideoPlayer(widget.controller), - const Center(child: CircularProgressIndicator()), - ], - fit: StackFit.expand, - ); - } -} - -class VideoPlayPause extends StatefulWidget { - const VideoPlayPause(this.controller); - - final VideoPlayerController controller; - - @override - State createState() => _VideoPlayPauseState(); -} - -class _VideoPlayPauseState extends State { - _VideoPlayPauseState() { - listener = () { - if (mounted) - setState(() { }); - }; - } - - FadeAnimation imageFadeAnimation; - VoidCallback listener; - - VideoPlayerController get controller => widget.controller; - - @override - void initState() { - super.initState(); - controller.addListener(listener); - } - - @override - void deactivate() { - controller.removeListener(listener); - super.deactivate(); - } - - @override - Widget build(BuildContext context) { - return Stack( - alignment: Alignment.bottomCenter, - fit: StackFit.expand, - children: [ - GestureDetector( - child: VideoPlayerLoading(controller), - onTap: () { - if (!controller.value.initialized) { - return; - } - if (controller.value.isPlaying) { - imageFadeAnimation = const FadeAnimation( - child: Icon(Icons.pause, size: 100.0), - ); - controller.pause(); - } else { - imageFadeAnimation = const FadeAnimation( - child: Icon(Icons.play_arrow, size: 100.0), - ); - controller.play(); - } - }, - ), - Center(child: imageFadeAnimation), - ], - ); - } -} - -class FadeAnimation extends StatefulWidget { - const FadeAnimation({ - this.child, - this.duration = const Duration(milliseconds: 500), - }); - - final Widget child; - final Duration duration; - - @override - _FadeAnimationState createState() => _FadeAnimationState(); -} - -class _FadeAnimationState extends State with SingleTickerProviderStateMixin { - AnimationController animationController; - - @override - void initState() { - super.initState(); - animationController = AnimationController( - duration: widget.duration, - vsync: this, - ); - animationController.addListener(() { - if (mounted) { - setState(() { }); - } - }); - animationController.forward(from: 0.0); - } - - @override - void deactivate() { - animationController.stop(); - super.deactivate(); - } - - @override - void didUpdateWidget(FadeAnimation oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.child != widget.child) { - animationController.forward(from: 0.0); - } - } - - @override - void dispose() { - animationController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return animationController.isAnimating - ? Opacity( - opacity: 1.0 - animationController.value, - child: widget.child, - ) - : Container(); - } -} - -class ConnectivityOverlay extends StatefulWidget { - const ConnectivityOverlay({ - this.child, - this.connectedCompleter, - this.scaffoldKey, - }); - - final Widget child; - final Completer connectedCompleter; - final GlobalKey scaffoldKey; - - @override - _ConnectivityOverlayState createState() => _ConnectivityOverlayState(); -} - -class _ConnectivityOverlayState extends State { - StreamSubscription connectivitySubscription; - bool connected = true; - - static const Widget errorSnackBar = SnackBar( - backgroundColor: Colors.red, - content: ListTile( - title: Text('No network'), - subtitle: Text( - 'To load the videos you must have an active network connection', - ), - ), - ); - - Stream connectivityStream() async* { - final Connectivity connectivity = Connectivity(); - ConnectivityResult previousResult = await connectivity.checkConnectivity(); - yield previousResult; - await for (ConnectivityResult result - in connectivity.onConnectivityChanged) { - if (result != previousResult) { - yield result; - previousResult = result; - } - } - } - - @override - void initState() { - super.initState(); - connectivitySubscription = connectivityStream().listen( - (ConnectivityResult connectivityResult) { - if (!mounted) { - return; - } - if (connectivityResult == ConnectivityResult.none) { - widget.scaffoldKey.currentState.showSnackBar(errorSnackBar); - } else { - if (!widget.connectedCompleter.isCompleted) { - widget.connectedCompleter.complete(null); - } - } - }, - ); - } - - @override - void dispose() { - connectivitySubscription.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => widget.child; -} - -class VideoDemo extends StatefulWidget { - const VideoDemo({ Key key }) : super(key: key); - - static const String routeName = '/video'; - - @override - _VideoDemoState createState() => _VideoDemoState(); -} - -final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); - -Future isIOSSimulator() async { - return Platform.isIOS && !(await deviceInfoPlugin.iosInfo).isPhysicalDevice; -} - -class _VideoDemoState extends State with SingleTickerProviderStateMixin { - final VideoPlayerController butterflyController = VideoPlayerController.asset( - 'videos/butterfly.mp4', - package: 'flutter_gallery_assets', - ); - - // TODO(sigurdm): This should not be stored here. - static const String beeUri = 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'; - final VideoPlayerController beeController = VideoPlayerController.network(beeUri); - - final GlobalKey scaffoldKey = GlobalKey(); - final Completer connectedCompleter = Completer(); - bool isSupported = true; - bool isDisposed = false; - - @override - void initState() { - super.initState(); - - Future initController(VideoPlayerController controller, String name) async { - print('> VideoDemo initController "$name" ${isDisposed ? "DISPOSED" : ""}'); - controller.setLooping(true); - controller.setVolume(0.0); - controller.play(); - await connectedCompleter.future; - await controller.initialize(); - if (mounted) { - print('< VideoDemo initController "$name" done ${isDisposed ? "DISPOSED" : ""}'); - setState(() { }); - } - } - - initController(butterflyController, 'butterfly'); - initController(beeController, 'bee'); - isIOSSimulator().then((bool result) { - isSupported = !result; - }); - } - - @override - void dispose() { - print('> VideoDemo dispose'); - isDisposed = true; - butterflyController.dispose(); - beeController.dispose(); - print('< VideoDemo dispose'); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: const Text('Videos'), - ), - body: isSupported - ? ConnectivityOverlay( - child: Scrollbar( - child: ListView( - children: [ - VideoCard( - title: 'Butterfly', - subtitle: '… flutters by', - controller: butterflyController, - ), - VideoCard( - title: 'Bee', - subtitle: '… gently buzzing', - controller: beeController, - ), - ], - ), - ), - connectedCompleter: connectedCompleter, - scaffoldKey: scaffoldKey, - ) - : const Center( - child: Text( - 'Video playback not supported on the iOS Simulator.', - ), - ), - ); - } -} diff --git a/web/gallery/lib/gallery/about.dart b/web/gallery/lib/gallery/about.dart deleted file mode 100644 index 0658fdaa4..000000000 --- a/web/gallery/lib/gallery/about.dart +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 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/gestures.dart'; -import 'package:flutter/foundation.dart' show defaultTargetPlatform; -import 'package:flutter/material.dart'; - -import 'package:url_launcher/url_launcher.dart'; - -class _LinkTextSpan extends TextSpan { - - // Beware! - // - // This class is only safe because the TapGestureRecognizer is not - // given a deadline and therefore never allocates any resources. - // - // In any other situation -- setting a deadline, using any of the less trivial - // recognizers, etc -- you would have to manage the gesture recognizer's - // lifetime and call dispose() when the TextSpan was no longer being rendered. - // - // Since TextSpan itself is @immutable, this means that you would have to - // manage the recognizer from outside the TextSpan, e.g. in the State of a - // stateful widget that then hands the recognizer to the TextSpan. - - _LinkTextSpan({ TextStyle style, String url, String text }) : super( - style: style, - text: text ?? url, - recognizer: TapGestureRecognizer()..onTap = () { - launch(url, forceSafariVC: false); - } - ); -} - -void showGalleryAboutDialog(BuildContext context) { - final ThemeData themeData = Theme.of(context); - final TextStyle aboutTextStyle = themeData.textTheme.body2; - final TextStyle linkStyle = themeData.textTheme.body2.copyWith(color: themeData.accentColor); - - showAboutDialog( - context: context, - applicationVersion: 'January 2019', - applicationIcon: const FlutterLogo(), - applicationLegalese: '© 2019 The Chromium Authors', - children: [ - Padding( - padding: const EdgeInsets.only(top: 24.0), - child: RichText( - text: TextSpan( - children: [ - TextSpan( - style: aboutTextStyle, - text: 'Flutter is an open-source project to help developers ' - 'build high-performance, high-fidelity, mobile apps for ' - '${defaultTargetPlatform == TargetPlatform.iOS ? 'multiple platforms' : 'iOS and Android'} ' - 'from a single codebase. This design lab is a playground ' - "and showcase of Flutter's many widgets, behaviors, " - 'animations, layouts, and more. Learn more about Flutter at ', - ), - _LinkTextSpan( - style: linkStyle, - url: 'https://flutter.dev', - ), - TextSpan( - style: aboutTextStyle, - text: '.\n\nTo see the source code for this app, please visit the ', - ), - _LinkTextSpan( - style: linkStyle, - url: 'https://goo.gl/iv1p4G', - text: 'flutter github repo', - ), - TextSpan( - style: aboutTextStyle, - text: '.', - ), - ], - ), - ), - ), - ], - ); -} diff --git a/web/gallery/lib/gallery/app.dart b/web/gallery/lib/gallery/app.dart deleted file mode 100644 index b21f77fa8..000000000 --- a/web/gallery/lib/gallery/app.dart +++ /dev/null @@ -1,168 +0,0 @@ -// 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:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart' show defaultTargetPlatform; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart' show timeDilation; -import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; -import 'package:scoped_model/scoped_model.dart'; - -import 'package:url_launcher/url_launcher.dart'; - -import 'demos.dart'; -import 'home.dart'; -import 'options.dart'; -import 'scales.dart'; -import 'themes.dart'; -import 'updater.dart'; - -class GalleryApp extends StatefulWidget { - const GalleryApp({ - Key key, - this.updateUrlFetcher, - this.enablePerformanceOverlay = true, - this.enableRasterCacheImagesCheckerboard = true, - this.enableOffscreenLayersCheckerboard = true, - this.onSendFeedback, - this.testMode = false, - }) : super(key: key); - - final UpdateUrlFetcher updateUrlFetcher; - final bool enablePerformanceOverlay; - final bool enableRasterCacheImagesCheckerboard; - final bool enableOffscreenLayersCheckerboard; - final VoidCallback onSendFeedback; - final bool testMode; - - @override - _GalleryAppState createState() => _GalleryAppState(); -} - -class _GalleryAppState extends State { - GalleryOptions _options; - Timer _timeDilationTimer; - AppStateModel model; - - Map _buildRoutes() { - // For a different example of how to set up an application routing table - // using named routes, consider the example in the Navigator class documentation: - // https://docs.flutter.io/flutter/widgets/Navigator-class.html - return Map.fromIterable( - kAllGalleryDemos, - key: (dynamic demo) => '${demo.routeName}', - value: (dynamic demo) => demo.buildRoute, - ); - } - - @override - void initState() { - super.initState(); - _options = GalleryOptions( - themeMode: ThemeMode.system, - textScaleFactor: kAllGalleryTextScaleValues[0], - timeDilation: timeDilation, - platform: defaultTargetPlatform, - ); - model = AppStateModel()..loadProducts(); - } - - @override - void dispose() { - _timeDilationTimer?.cancel(); - _timeDilationTimer = null; - super.dispose(); - } - - void _handleOptionsChanged(GalleryOptions newOptions) { - setState(() { - if (_options.timeDilation != newOptions.timeDilation) { - _timeDilationTimer?.cancel(); - _timeDilationTimer = null; - if (newOptions.timeDilation > 1.0) { - // We delay the time dilation change long enough that the user can see - // that UI has started reacting and then we slam on the brakes so that - // they see that the time is in fact now dilated. - _timeDilationTimer = Timer(const Duration(milliseconds: 150), () { - timeDilation = newOptions.timeDilation; - }); - } else { - timeDilation = newOptions.timeDilation; - } - } - - _options = newOptions; - }); - } - - Widget _applyTextScaleFactor(Widget child) { - return Builder( - builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: _options.textScaleFactor.scale, - ), - child: child, - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - Widget home = GalleryHome( - testMode: widget.testMode, - optionsPage: GalleryOptionsPage( - options: _options, - onOptionsChanged: _handleOptionsChanged, - onSendFeedback: widget.onSendFeedback ?? () { - launch('https://github.com/flutter/flutter/issues/new/choose', forceSafariVC: false); - }, - ), - ); - - if (widget.updateUrlFetcher != null) { - home = Updater( - updateUrlFetcher: widget.updateUrlFetcher, - child: home, - ); - } - - return ScopedModel( - model: model, - child: MaterialApp( - theme: kLightGalleryTheme.copyWith(platform: _options.platform), - darkTheme: kDarkGalleryTheme.copyWith(platform: _options.platform), - themeMode: _options.themeMode, - title: 'Flutter Gallery', - color: Colors.grey, - showPerformanceOverlay: _options.showPerformanceOverlay, - checkerboardOffscreenLayers: _options.showOffscreenLayersCheckerboard, - checkerboardRasterCacheImages: _options.showRasterCacheImagesCheckerboard, - routes: _buildRoutes(), - builder: (BuildContext context, Widget child) { - return Directionality( - textDirection: _options.textDirection, - child: _applyTextScaleFactor( - // Specifically use a blank Cupertino theme here and do not transfer - // over the Material primary color etc except the brightness to - // showcase standard iOS looks. - Builder(builder: (BuildContext context) { - return CupertinoTheme( - data: CupertinoThemeData( - brightness: Theme.of(context).brightness, - ), - child: child, - ); - }), - ), - ); - }, - home: home, - ), - ); - } -} diff --git a/web/gallery/lib/gallery/backdrop.dart b/web/gallery/lib/gallery/backdrop.dart deleted file mode 100644 index 609f3a405..000000000 --- a/web/gallery/lib/gallery/backdrop.dart +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2018 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 'package:flutter/rendering.dart'; -import 'package:flutter/material.dart'; - -const double _kFrontHeadingHeight = 32.0; // front layer beveled rectangle -const double _kFrontClosedHeight = 92.0; // front layer height when closed -const double _kBackAppBarHeight = 56.0; // back layer (options) appbar height - -// The size of the front layer heading's left and right beveled corners. -final Animatable _kFrontHeadingBevelRadius = BorderRadiusTween( - begin: const BorderRadius.only( - topLeft: Radius.circular(12.0), - topRight: Radius.circular(12.0), - ), - end: const BorderRadius.only( - topLeft: Radius.circular(_kFrontHeadingHeight), - topRight: Radius.circular(_kFrontHeadingHeight), - ), -); - -class _TappableWhileStatusIs extends StatefulWidget { - const _TappableWhileStatusIs( - this.status, { - Key key, - this.controller, - this.child, - }) : super(key: key); - - final AnimationController controller; - final AnimationStatus status; - final Widget child; - - @override - _TappableWhileStatusIsState createState() => _TappableWhileStatusIsState(); -} - -class _TappableWhileStatusIsState extends State<_TappableWhileStatusIs> { - bool _active; - - @override - void initState() { - super.initState(); - widget.controller.addStatusListener(_handleStatusChange); - _active = widget.controller.status == widget.status; - } - - @override - void dispose() { - widget.controller.removeStatusListener(_handleStatusChange); - super.dispose(); - } - - void _handleStatusChange(AnimationStatus status) { - final bool value = widget.controller.status == widget.status; - if (_active != value) { - setState(() { - _active = value; - }); - } - } - - @override - Widget build(BuildContext context) { - Widget child = AbsorbPointer( - absorbing: !_active, - child: widget.child, - ); - - if (!_active) { - child = FocusScope( - canRequestFocus: false, - debugLabel: '$_TappableWhileStatusIs', - child: child, - ); - } - return child; - } -} - -class _CrossFadeTransition extends AnimatedWidget { - const _CrossFadeTransition({ - Key key, - this.alignment = Alignment.center, - Animation progress, - this.child0, - this.child1, - }) : super(key: key, listenable: progress); - - final AlignmentGeometry alignment; - final Widget child0; - final Widget child1; - - @override - Widget build(BuildContext context) { - final Animation progress = listenable; - - final double opacity1 = CurvedAnimation( - parent: ReverseAnimation(progress), - curve: const Interval(0.5, 1.0), - ).value; - - final double opacity2 = CurvedAnimation( - parent: progress, - curve: const Interval(0.5, 1.0), - ).value; - - return Stack( - alignment: alignment, - children: [ - Opacity( - opacity: opacity1, - child: Semantics( - scopesRoute: true, - explicitChildNodes: true, - child: child1, - ), - ), - Opacity( - opacity: opacity2, - child: Semantics( - scopesRoute: true, - explicitChildNodes: true, - child: child0, - ), - ), - ], - ); - } -} - -class _BackAppBar extends StatelessWidget { - const _BackAppBar({ - Key key, - this.leading = const SizedBox(width: 56.0), - @required this.title, - this.trailing, - }) : assert(leading != null), assert(title != null), super(key: key); - - final Widget leading; - final Widget title; - final Widget trailing; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return IconTheme.merge( - data: theme.primaryIconTheme, - child: DefaultTextStyle( - style: theme.primaryTextTheme.title, - child: SizedBox( - height: _kBackAppBarHeight, - child: Row( - children: [ - Container( - alignment: Alignment.center, - width: 56.0, - child: leading, - ), - Expanded( - child: title, - ), - if (trailing != null) - Container( - alignment: Alignment.center, - width: 56.0, - child: trailing, - ), - ], - ), - ), - ), - ); - } -} - -class Backdrop extends StatefulWidget { - const Backdrop({ - this.frontAction, - this.frontTitle, - this.frontHeading, - this.frontLayer, - this.backTitle, - this.backLayer, - }); - - final Widget frontAction; - final Widget frontTitle; - final Widget frontLayer; - final Widget frontHeading; - final Widget backTitle; - final Widget backLayer; - - @override - _BackdropState createState() => _BackdropState(); -} - -class _BackdropState extends State with SingleTickerProviderStateMixin { - final GlobalKey _backdropKey = GlobalKey(debugLabel: 'Backdrop'); - AnimationController _controller; - Animation _frontOpacity; - - static final Animatable _frontOpacityTween = Tween(begin: 0.2, end: 1.0) - .chain(CurveTween(curve: const Interval(0.0, 0.4, curve: Curves.easeInOut))); - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 300), - value: 1.0, - vsync: this, - ); - _frontOpacity = _controller.drive(_frontOpacityTween); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - double get _backdropHeight { - // Warning: this can be safely called from the event handlers but it may - // not be called at build time. - final RenderBox renderBox = _backdropKey.currentContext.findRenderObject(); - return math.max(0.0, renderBox.size.height - _kBackAppBarHeight - _kFrontClosedHeight); - } - - void _handleDragUpdate(DragUpdateDetails details) { - _controller.value -= details.primaryDelta / (_backdropHeight ?? details.primaryDelta); - } - - void _handleDragEnd(DragEndDetails details) { - if (_controller.isAnimating || _controller.status == AnimationStatus.completed) - return; - - final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight; - if (flingVelocity < 0.0) - _controller.fling(velocity: math.max(2.0, -flingVelocity)); - else if (flingVelocity > 0.0) - _controller.fling(velocity: math.min(-2.0, -flingVelocity)); - else - _controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0); - } - - void _toggleFrontLayer() { - final AnimationStatus status = _controller.status; - final bool isOpen = status == AnimationStatus.completed || status == AnimationStatus.forward; - _controller.fling(velocity: isOpen ? -2.0 : 2.0); - } - - Widget _buildStack(BuildContext context, BoxConstraints constraints) { - final Animation frontRelativeRect = _controller.drive(RelativeRectTween( - begin: RelativeRect.fromLTRB(0.0, constraints.biggest.height - _kFrontClosedHeight, 0.0, 0.0), - end: const RelativeRect.fromLTRB(0.0, _kBackAppBarHeight, 0.0, 0.0), - )); - return Stack( - key: _backdropKey, - children: [ - // Back layer - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _BackAppBar( - leading: widget.frontAction, - title: _CrossFadeTransition( - progress: _controller, - alignment: AlignmentDirectional.centerStart, - child0: Semantics(namesRoute: true, child: widget.frontTitle), - child1: Semantics(namesRoute: true, child: widget.backTitle), - ), - trailing: IconButton( - onPressed: _toggleFrontLayer, - tooltip: 'Toggle options page', - icon: AnimatedIcon( - icon: AnimatedIcons.close_menu, - progress: _controller, - ), - ), - ), - Expanded( - child: _TappableWhileStatusIs( - AnimationStatus.dismissed, - controller: _controller, - child: Visibility( - child: widget.backLayer, - visible: _controller.status != AnimationStatus.completed, - maintainState: true, - ), - ), - ), - ], - ), - // Front layer - PositionedTransition( - rect: frontRelativeRect, - child: AnimatedBuilder( - animation: _controller, - builder: (BuildContext context, Widget child) { - return PhysicalShape( - elevation: 12.0, - color: Theme.of(context).canvasColor, - clipper: ShapeBorderClipper( - shape: BeveledRectangleBorder( - borderRadius: _kFrontHeadingBevelRadius.transform(_controller.value), - ), - ), - clipBehavior: Clip.antiAlias, - child: child, - ); - }, - child: _TappableWhileStatusIs( - AnimationStatus.completed, - controller: _controller, - child: FadeTransition( - opacity: _frontOpacity, - child: widget.frontLayer, - ), - ), - ), - ), - // The front "heading" is a (typically transparent) widget that's stacked on - // top of, and at the top of, the front layer. It adds support for dragging - // the front layer up and down and for opening and closing the front layer - // with a tap. It may obscure part of the front layer's topmost child. - if (widget.frontHeading != null) - PositionedTransition( - rect: frontRelativeRect, - child: ExcludeSemantics( - child: Container( - alignment: Alignment.topLeft, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: _toggleFrontLayer, - onVerticalDragUpdate: _handleDragUpdate, - onVerticalDragEnd: _handleDragEnd, - child: widget.frontHeading, - ), - ), - ), - ), - ], - ); - } - - @override - Widget build(BuildContext context) { - return LayoutBuilder(builder: _buildStack); - } -} diff --git a/web/gallery/lib/gallery/demo.dart b/web/gallery/lib/gallery/demo.dart deleted file mode 100644 index 178d8dea7..000000000 --- a/web/gallery/lib/gallery/demo.dart +++ /dev/null @@ -1,261 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import 'demos.dart'; -import 'example_code_parser.dart'; -import 'syntax_highlighter.dart'; - -class ComponentDemoTabData { - ComponentDemoTabData({ - this.demoWidget, - this.exampleCodeTag, - this.description, - this.tabName, - this.documentationUrl, - }); - - final Widget demoWidget; - final String exampleCodeTag; - final String description; - final String tabName; - final String documentationUrl; - - @override - bool operator==(Object other) { - if (other.runtimeType != runtimeType) - return false; - final ComponentDemoTabData typedOther = other; - return typedOther.tabName == tabName - && typedOther.description == description - && typedOther.documentationUrl == documentationUrl; - } - - @override - int get hashCode => hashValues(tabName, description, documentationUrl); -} - -class TabbedComponentDemoScaffold extends StatelessWidget { - const TabbedComponentDemoScaffold({ - this.title, - this.demos, - this.actions, - this.isScrollable = true, - this.showExampleCodeAction = true, - }); - - final List demos; - final String title; - final List actions; - final bool isScrollable; - final bool showExampleCodeAction; - - void _showExampleCode(BuildContext context) { - final String tag = demos[DefaultTabController.of(context).index].exampleCodeTag; - if (tag != null) { - Navigator.push(context, MaterialPageRoute( - builder: (BuildContext context) => FullScreenCodeDialog(exampleCodeTag: tag) - )); - } - } - - Future _showApiDocumentation(BuildContext context) async { - final String url = demos[DefaultTabController.of(context).index].documentationUrl; - if (url == null) - return; - - if (await canLaunch(url)) { - await launch(url); - } else { - showDialog( - context: context, - builder: (BuildContext context) { - return SimpleDialog( - title: const Text('Couldn\'t display URL:'), - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text(url), - ), - ], - ); - }, - ); - } - } - - @override - Widget build(BuildContext context) { - return DefaultTabController( - length: demos.length, - child: Scaffold( - appBar: AppBar( - title: Text(title), - actions: [ - ...?actions, - Builder( - builder: (BuildContext context) { - return IconButton( - icon: const Icon(Icons.library_books, semanticLabel: 'Show documentation'), - onPressed: () => _showApiDocumentation(context), - ); - }, - ), - if (showExampleCodeAction) - Builder( - builder: (BuildContext context) { - return IconButton( - icon: const Icon(Icons.code), - tooltip: 'Show example code', - onPressed: () => _showExampleCode(context), - ); - }, - ), - ], - bottom: TabBar( - isScrollable: isScrollable, - tabs: demos.map((ComponentDemoTabData data) => Tab(text: data.tabName)).toList(), - ), - ), - body: TabBarView( - children: demos.map((ComponentDemoTabData demo) { - return SafeArea( - top: false, - bottom: false, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text(demo.description, - style: Theme.of(context).textTheme.subhead, - ), - ), - Expanded(child: demo.demoWidget), - ], - ), - ); - }).toList(), - ), - ), - ); - } -} - -class FullScreenCodeDialog extends StatefulWidget { - const FullScreenCodeDialog({ this.exampleCodeTag }); - - final String exampleCodeTag; - - @override - FullScreenCodeDialogState createState() => FullScreenCodeDialogState(); -} - -class FullScreenCodeDialogState extends State { - - String _exampleCode; - - @override - void didChangeDependencies() { - getExampleCode(widget.exampleCodeTag, DefaultAssetBundle.of(context)).then((String code) { - if (mounted) { - setState(() { - _exampleCode = code ?? 'Example code not found'; - }); - } - }); - super.didChangeDependencies(); - } - - @override - Widget build(BuildContext context) { - final SyntaxHighlighterStyle style = Theme.of(context).brightness == Brightness.dark - ? SyntaxHighlighterStyle.darkThemeStyle() - : SyntaxHighlighterStyle.lightThemeStyle(); - - Widget body; - if (_exampleCode == null) { - body = const Center( - child: CircularProgressIndicator(), - ); - } else { - body = SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: RichText( - text: TextSpan( - style: const TextStyle(fontFamily: 'monospace', fontSize: 10.0), - children: [ - DartSyntaxHighlighter(style).format(_exampleCode), - ], - ), - ), - ), - ); - } - - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon( - Icons.clear, - semanticLabel: 'Close', - ), - onPressed: () { Navigator.pop(context); }, - ), - title: const Text('Example code'), - ), - body: body, - ); - } -} - -class MaterialDemoDocumentationButton extends StatelessWidget { - MaterialDemoDocumentationButton(String routeName, { Key key }) - : documentationUrl = kDemoDocumentationUrl[routeName], - assert( - kDemoDocumentationUrl[routeName] != null, - 'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos', - ), - super(key: key); - - final String documentationUrl; - - @override - Widget build(BuildContext context) { - return IconButton( - icon: const Icon(Icons.library_books), - tooltip: 'API documentation', - onPressed: () => launch(documentationUrl, forceWebView: true), - ); - } -} - -class CupertinoDemoDocumentationButton extends StatelessWidget { - CupertinoDemoDocumentationButton(String routeName, { Key key }) - : documentationUrl = kDemoDocumentationUrl[routeName], - assert( - kDemoDocumentationUrl[routeName] != null, - 'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos', - ), - super(key: key); - - final String documentationUrl; - - @override - Widget build(BuildContext context) { - return CupertinoButton( - padding: EdgeInsets.zero, - child: Semantics( - label: 'API documentation', - child: const Icon(CupertinoIcons.book), - ), - onPressed: () => launch(documentationUrl, forceWebView: true), - ); - } -} diff --git a/web/gallery/lib/gallery/demos.dart b/web/gallery/lib/gallery/demos.dart deleted file mode 100644 index 2756ae963..000000000 --- a/web/gallery/lib/gallery/demos.dart +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright 2018 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 '../demo/all.dart'; -import 'icons.dart'; - -class GalleryDemoCategory { - const GalleryDemoCategory._({ - @required this.name, - @required this.icon, - }); - - final String name; - final IconData icon; - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) - return true; - if (runtimeType != other.runtimeType) - return false; - final GalleryDemoCategory typedOther = other; - return typedOther.name == name && typedOther.icon == icon; - } - - @override - int get hashCode => hashValues(name, icon); - - @override - String toString() { - return '$runtimeType($name)'; - } -} - -const GalleryDemoCategory _kDemos = GalleryDemoCategory._( - name: 'Studies', - icon: GalleryIcons.animation, -); - -const GalleryDemoCategory _kStyle = GalleryDemoCategory._( - name: 'Style', - icon: GalleryIcons.custom_typography, -); - -const GalleryDemoCategory _kMaterialComponents = GalleryDemoCategory._( - name: 'Material', - icon: GalleryIcons.category_mdc, -); - -const GalleryDemoCategory _kCupertinoComponents = GalleryDemoCategory._( - name: 'Cupertino', - icon: GalleryIcons.phone_iphone, -); - -const GalleryDemoCategory _kMedia = GalleryDemoCategory._( - name: 'Media', - icon: GalleryIcons.drive_video, -); - -class GalleryDemo { - const GalleryDemo({ - @required this.title, - @required this.icon, - this.subtitle, - @required this.category, - @required this.routeName, - this.documentationUrl, - @required this.buildRoute, - }) : assert(title != null), - assert(category != null), - assert(routeName != null), - assert(buildRoute != null); - - final String title; - final IconData icon; - final String subtitle; - final GalleryDemoCategory category; - final String routeName; - final WidgetBuilder buildRoute; - final String documentationUrl; - - @override - String toString() { - return '$runtimeType($title $routeName)'; - } -} - -List _buildGalleryDemos() { - final List galleryDemos = [ - // Demos - GalleryDemo( - title: 'Shrine', - subtitle: 'Basic shopping app', - icon: GalleryIcons.shrine, - category: _kDemos, - routeName: ShrineDemo.routeName, - buildRoute: (BuildContext context) => const ShrineDemo(), - ), - GalleryDemo( - title: 'Fortnightly', - subtitle: 'Newspaper typography app', - icon: GalleryIcons.custom_typography, - category: _kDemos, - routeName: FortnightlyDemo.routeName, - buildRoute: (BuildContext context) => FortnightlyDemo(), - ), - GalleryDemo( - title: 'Contact profile', - subtitle: 'Address book entry with a flexible appbar', - icon: GalleryIcons.account_box, - category: _kDemos, - routeName: ContactsDemo.routeName, - buildRoute: (BuildContext context) => ContactsDemo(), - ), - GalleryDemo( - title: 'Animation', - subtitle: 'Section organizer', - icon: GalleryIcons.animation, - category: _kDemos, - routeName: AnimationDemo.routeName, - buildRoute: (BuildContext context) => const AnimationDemo(), - ), - GalleryDemo( - title: '2D Transformations', - subtitle: 'Pan, Zoom, Rotate', - icon: GalleryIcons.grid_on, - category: _kDemos, - routeName: TransformationsDemo.routeName, - buildRoute: (BuildContext context) => const TransformationsDemo(), - ), - GalleryDemo( - title: 'Pesto', - subtitle: 'Simple recipe browser', - icon: Icons.adjust, - category: _kDemos, - routeName: PestoDemo.routeName, - buildRoute: (BuildContext context) => const PestoDemo(), - ), - - // Style - GalleryDemo( - title: 'Colors', - subtitle: 'All of the predefined colors', - icon: GalleryIcons.colors, - category: _kStyle, - routeName: ColorsDemo.routeName, - buildRoute: (BuildContext context) => ColorsDemo(), - ), - GalleryDemo( - title: 'Typography', - subtitle: 'All of the predefined text styles', - icon: GalleryIcons.custom_typography, - category: _kStyle, - routeName: TypographyDemo.routeName, - buildRoute: (BuildContext context) => TypographyDemo(), - ), - - // Material Components - GalleryDemo( - title: 'Backdrop', - subtitle: 'Select a front layer from back layer', - icon: GalleryIcons.backdrop, - category: _kMaterialComponents, - routeName: BackdropDemo.routeName, - buildRoute: (BuildContext context) => BackdropDemo(), - ), - GalleryDemo( - title: 'Banner', - subtitle: 'Displaying a banner within a list', - icon: GalleryIcons.lists_leave_behind, - category: _kMaterialComponents, - routeName: BannerDemo.routeName, - documentationUrl: 'https://api.flutter.dev/flutter/material/MaterialBanner-class.html', - buildRoute: (BuildContext context) => const BannerDemo(), - ), - GalleryDemo( - title: 'Bottom app bar', - subtitle: 'Optional floating action button notch', - icon: GalleryIcons.bottom_app_bar, - category: _kMaterialComponents, - routeName: BottomAppBarDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/BottomAppBar-class.html', - buildRoute: (BuildContext context) => BottomAppBarDemo(), - ), - GalleryDemo( - title: 'Bottom navigation', - subtitle: 'Bottom navigation with cross-fading views', - icon: GalleryIcons.bottom_navigation, - category: _kMaterialComponents, - routeName: BottomNavigationDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/BottomNavigationBar-class.html', - buildRoute: (BuildContext context) => BottomNavigationDemo(), - ), - GalleryDemo( - title: 'Bottom sheet: Modal', - subtitle: 'A dismissible bottom sheet', - icon: GalleryIcons.bottom_sheets, - category: _kMaterialComponents, - routeName: ModalBottomSheetDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/showModalBottomSheet.html', - buildRoute: (BuildContext context) => ModalBottomSheetDemo(), - ), - GalleryDemo( - title: 'Bottom sheet: Persistent', - subtitle: 'A bottom sheet that sticks around', - icon: GalleryIcons.bottom_sheet_persistent, - category: _kMaterialComponents, - routeName: PersistentBottomSheetDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ScaffoldState/showBottomSheet.html', - buildRoute: (BuildContext context) => PersistentBottomSheetDemo(), - ), - GalleryDemo( - title: 'Buttons', - subtitle: 'Flat, raised, dropdown, and more', - icon: GalleryIcons.generic_buttons, - category: _kMaterialComponents, - routeName: ButtonsDemo.routeName, - buildRoute: (BuildContext context) => ButtonsDemo(), - ), - GalleryDemo( - title: 'Buttons: Floating Action Button', - subtitle: 'FAB with transitions', - icon: GalleryIcons.buttons, - category: _kMaterialComponents, - routeName: TabsFabDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/FloatingActionButton-class.html', - buildRoute: (BuildContext context) => TabsFabDemo(), - ), - GalleryDemo( - title: 'Cards', - subtitle: 'Baseline cards with rounded corners', - icon: GalleryIcons.cards, - category: _kMaterialComponents, - routeName: CardsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Card-class.html', - buildRoute: (BuildContext context) => CardsDemo(), - ), - GalleryDemo( - title: 'Chips', - subtitle: 'Labeled with delete buttons and avatars', - icon: GalleryIcons.chips, - category: _kMaterialComponents, - routeName: ChipDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Chip-class.html', - buildRoute: (BuildContext context) => ChipDemo(), - ), - GalleryDemo( - title: 'Data tables', - subtitle: 'Rows and columns', - icon: GalleryIcons.data_table, - category: _kMaterialComponents, - routeName: DataTableDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/PaginatedDataTable-class.html', - buildRoute: (BuildContext context) => DataTableDemo(), - ), - GalleryDemo( - title: 'Dialogs', - subtitle: 'Simple, alert, and fullscreen', - icon: GalleryIcons.dialogs, - category: _kMaterialComponents, - routeName: DialogDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/showDialog.html', - buildRoute: (BuildContext context) => DialogDemo(), - ), - GalleryDemo( - title: 'Elevations', - subtitle: 'Shadow values on cards', - // TODO(larche): Change to custom icon for elevations when one exists. - icon: GalleryIcons.cupertino_progress, - category: _kMaterialComponents, - routeName: ElevationDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Material/elevation.html', - buildRoute: (BuildContext context) => ElevationDemo(), - ), - GalleryDemo( - title: 'Expand/collapse list control', - subtitle: 'A list with one sub-list level', - icon: GalleryIcons.expand_all, - category: _kMaterialComponents, - routeName: ExpansionTileListDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ExpansionTile-class.html', - buildRoute: (BuildContext context) => ExpansionTileListDemo(), - ), - GalleryDemo( - title: 'Expansion panels', - subtitle: 'List of expanding panels', - icon: GalleryIcons.expand_all, - category: _kMaterialComponents, - routeName: ExpansionPanelsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ExpansionPanel-class.html', - buildRoute: (BuildContext context) => ExpansionPanelsDemo(), - ), - GalleryDemo( - title: 'Grid', - subtitle: 'Row and column layout', - icon: GalleryIcons.grid_on, - category: _kMaterialComponents, - routeName: GridListDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/widgets/GridView-class.html', - buildRoute: (BuildContext context) => const GridListDemo(), - ), - GalleryDemo( - title: 'Icons', - subtitle: 'Enabled and disabled icons with opacity', - icon: GalleryIcons.sentiment_very_satisfied, - category: _kMaterialComponents, - routeName: IconsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/IconButton-class.html', - buildRoute: (BuildContext context) => IconsDemo(), - ), - GalleryDemo( - title: 'Lists', - subtitle: 'Scrolling list layouts', - icon: GalleryIcons.list_alt, - category: _kMaterialComponents, - routeName: ListDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ListTile-class.html', - buildRoute: (BuildContext context) => const ListDemo(), - ), - GalleryDemo( - title: 'Lists: leave-behind list items', - subtitle: 'List items with hidden actions', - icon: GalleryIcons.lists_leave_behind, - category: _kMaterialComponents, - routeName: LeaveBehindDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/widgets/Dismissible-class.html', - buildRoute: (BuildContext context) => const LeaveBehindDemo(), - ), - GalleryDemo( - title: 'Lists: reorderable', - subtitle: 'Reorderable lists', - icon: GalleryIcons.list_alt, - category: _kMaterialComponents, - routeName: ReorderableListDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ReorderableListView-class.html', - buildRoute: (BuildContext context) => const ReorderableListDemo(), - ), - GalleryDemo( - title: 'Menus', - subtitle: 'Menu buttons and simple menus', - icon: GalleryIcons.more_vert, - category: _kMaterialComponents, - routeName: MenuDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/PopupMenuButton-class.html', - buildRoute: (BuildContext context) => const MenuDemo(), - ), - GalleryDemo( - title: 'Navigation drawer', - subtitle: 'Navigation drawer with standard header', - icon: GalleryIcons.menu, - category: _kMaterialComponents, - routeName: DrawerDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Drawer-class.html', - buildRoute: (BuildContext context) => DrawerDemo(), - ), - GalleryDemo( - title: 'Pagination', - subtitle: 'PageView with indicator', - icon: GalleryIcons.page_control, - category: _kMaterialComponents, - routeName: PageSelectorDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/TabBarView-class.html', - buildRoute: (BuildContext context) => PageSelectorDemo(), - ), - GalleryDemo( - title: 'Pickers', - subtitle: 'Date and time selection widgets', - icon: GalleryIcons.event, - category: _kMaterialComponents, - routeName: DateAndTimePickerDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/showDatePicker.html', - buildRoute: (BuildContext context) => DateAndTimePickerDemo(), - ), - GalleryDemo( - title: 'Progress indicators', - subtitle: 'Linear, circular, indeterminate', - icon: GalleryIcons.progress_activity, - category: _kMaterialComponents, - routeName: ProgressIndicatorDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/LinearProgressIndicator-class.html', - buildRoute: (BuildContext context) => ProgressIndicatorDemo(), - ), - GalleryDemo( - title: 'Pull to refresh', - subtitle: 'Refresh indicators', - icon: GalleryIcons.refresh, - category: _kMaterialComponents, - routeName: OverscrollDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/RefreshIndicator-class.html', - buildRoute: (BuildContext context) => const OverscrollDemo(), - ), - GalleryDemo( - title: 'Search', - subtitle: 'Expandable search', - icon: Icons.search, - category: _kMaterialComponents, - routeName: SearchDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/showSearch.html', - buildRoute: (BuildContext context) => SearchDemo(), - ), - GalleryDemo( - title: 'Selection controls', - subtitle: 'Checkboxes, radio buttons, and switches', - icon: GalleryIcons.check_box, - category: _kMaterialComponents, - routeName: SelectionControlsDemo.routeName, - buildRoute: (BuildContext context) => SelectionControlsDemo(), - ), - GalleryDemo( - title: 'Sliders', - subtitle: 'Widgets for selecting a value by swiping', - icon: GalleryIcons.sliders, - category: _kMaterialComponents, - routeName: SliderDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Slider-class.html', - buildRoute: (BuildContext context) => SliderDemo(), - ), - GalleryDemo( - title: 'Snackbar', - subtitle: 'Temporary messaging', - icon: GalleryIcons.snackbar, - category: _kMaterialComponents, - routeName: SnackBarDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/ScaffoldState/showSnackBar.html', - buildRoute: (BuildContext context) => const SnackBarDemo(), - ), - GalleryDemo( - title: 'Tabs', - subtitle: 'Tabs with independently scrollable views', - icon: GalleryIcons.tabs, - category: _kMaterialComponents, - routeName: TabsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/TabBarView-class.html', - buildRoute: (BuildContext context) => TabsDemo(), - ), - GalleryDemo( - title: 'Tabs: Scrolling', - subtitle: 'Tab bar that scrolls', - category: _kMaterialComponents, - icon: GalleryIcons.tabs, - routeName: ScrollableTabsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/TabBar-class.html', - buildRoute: (BuildContext context) => ScrollableTabsDemo(), - ), - GalleryDemo( - title: 'Text fields', - subtitle: 'Single line of editable text and numbers', - icon: GalleryIcons.text_fields_alt, - category: _kMaterialComponents, - routeName: TextFormFieldDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/TextFormField-class.html', - buildRoute: (BuildContext context) => const TextFormFieldDemo(), - ), - GalleryDemo( - title: 'Tooltips', - subtitle: 'Short message displayed on long-press', - icon: GalleryIcons.tooltip, - category: _kMaterialComponents, - routeName: TooltipDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/material/Tooltip-class.html', - buildRoute: (BuildContext context) => TooltipDemo(), - ), - - // Cupertino Components - GalleryDemo( - title: 'Activity Indicator', - icon: GalleryIcons.cupertino_progress, - category: _kCupertinoComponents, - routeName: CupertinoProgressIndicatorDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoActivityIndicator-class.html', - buildRoute: (BuildContext context) => CupertinoProgressIndicatorDemo(), - ), - GalleryDemo( - title: 'Alerts', - icon: GalleryIcons.dialogs, - category: _kCupertinoComponents, - routeName: CupertinoAlertDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/showCupertinoDialog.html', - buildRoute: (BuildContext context) => CupertinoAlertDemo(), - ), - GalleryDemo( - title: 'Buttons', - icon: GalleryIcons.generic_buttons, - category: _kCupertinoComponents, - routeName: CupertinoButtonsDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoButton-class.html', - buildRoute: (BuildContext context) => CupertinoButtonsDemo(), - ), - GalleryDemo( - title: 'Navigation', - icon: GalleryIcons.bottom_navigation, - category: _kCupertinoComponents, - routeName: CupertinoNavigationDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoTabScaffold-class.html', - buildRoute: (BuildContext context) => CupertinoNavigationDemo(), - ), - GalleryDemo( - title: 'Pickers', - icon: GalleryIcons.event, - category: _kCupertinoComponents, - routeName: CupertinoPickerDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoPicker-class.html', - buildRoute: (BuildContext context) => CupertinoPickerDemo(), - ), - GalleryDemo( - title: 'Pull to refresh', - icon: GalleryIcons.cupertino_pull_to_refresh, - category: _kCupertinoComponents, - routeName: CupertinoRefreshControlDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSliverRefreshControl-class.html', - buildRoute: (BuildContext context) => CupertinoRefreshControlDemo(), - ), - GalleryDemo( - title: 'Segmented Control', - icon: GalleryIcons.tabs, - category: _kCupertinoComponents, - routeName: CupertinoSegmentedControlDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSegmentedControl-class.html', - buildRoute: (BuildContext context) => CupertinoSegmentedControlDemo(), - ), - GalleryDemo( - title: 'Sliders', - icon: GalleryIcons.sliders, - category: _kCupertinoComponents, - routeName: CupertinoSliderDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSlider-class.html', - buildRoute: (BuildContext context) => CupertinoSliderDemo(), - ), - GalleryDemo( - title: 'Switches', - icon: GalleryIcons.cupertino_switch, - category: _kCupertinoComponents, - routeName: CupertinoSwitchDemo.routeName, - documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSwitch-class.html', - buildRoute: (BuildContext context) => CupertinoSwitchDemo(), - ), - GalleryDemo( - title: 'Text Fields', - icon: GalleryIcons.text_fields_alt, - category: _kCupertinoComponents, - routeName: CupertinoTextFieldDemo.routeName, - buildRoute: (BuildContext context) => CupertinoTextFieldDemo(), - ), - - // Media - GalleryDemo( - title: 'Animated images', - subtitle: 'GIF and WebP animations', - icon: GalleryIcons.animation, - category: _kMedia, - routeName: ImagesDemo.routeName, - buildRoute: (BuildContext context) => ImagesDemo(), - ), - GalleryDemo( - title: 'Video', - subtitle: 'Video playback', - icon: GalleryIcons.drive_video, - category: _kMedia, - routeName: VideoDemo.routeName, - buildRoute: (BuildContext context) => const VideoDemo(), - ), - ]; - return galleryDemos; -} - -final List kAllGalleryDemos = _buildGalleryDemos(); - -final Set kAllGalleryDemoCategories = - kAllGalleryDemos.map((GalleryDemo demo) => demo.category).toSet(); - -final Map> kGalleryCategoryToDemos = - Map>.fromIterable( - kAllGalleryDemoCategories, - value: (dynamic category) { - return kAllGalleryDemos.where((GalleryDemo demo) => demo.category == category).toList(); - }, - ); - -final Map kDemoDocumentationUrl = - Map.fromIterable( - kAllGalleryDemos.where((GalleryDemo demo) => demo.documentationUrl != null), - key: (dynamic demo) => demo.routeName, - value: (dynamic demo) => demo.documentationUrl, - ); diff --git a/web/gallery/lib/gallery/example_code.dart b/web/gallery/lib/gallery/example_code.dart deleted file mode 100644 index c20be2e1a..000000000 --- a/web/gallery/lib/gallery/example_code.dart +++ /dev/null @@ -1,286 +0,0 @@ -// 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. - -// Note: This code is not runnable, it contains code snippets displayed in the -// gallery. - -import 'package:flutter/material.dart'; - -class ButtonsDemo { - void setState(VoidCallback callback) { } - BuildContext context; - - void buttons() { - -// START buttons_raised -// Create a raised button. -RaisedButton( - child: const Text('BUTTON TITLE'), - onPressed: () { - // Perform some action - }, -); - -// Create a disabled button. -// Buttons are disabled when onPressed isn't -// specified or is null. -const RaisedButton( - child: Text('BUTTON TITLE'), - onPressed: null, -); - -// Create a button with an icon and a -// title. -RaisedButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('BUTTON TITLE'), - onPressed: () { - // Perform some action - }, -); -// END - -// START buttons_outline -// Create an outline button. -OutlineButton( - child: const Text('BUTTON TITLE'), - onPressed: () { - // Perform some action - }, -); - -// Create a disabled button. -// Buttons are disabled when onPressed isn't -// specified or is null. -const OutlineButton( - child: Text('BUTTON TITLE'), - onPressed: null, -); - -// Create a button with an icon and a -// title. -OutlineButton.icon( - icon: const Icon(Icons.add, size: 18.0), - label: const Text('BUTTON TITLE'), - onPressed: () { - // Perform some action - }, -); -// END - -// START buttons_flat -// Create a flat button. -FlatButton( - child: const Text('BUTTON TITLE'), - onPressed: () { - // Perform some action - }, -); - -// Create a disabled button. -// Buttons are disabled when onPressed isn't -// specified or is null. -const FlatButton( - child: Text('BUTTON TITLE'), - onPressed: null, -); -// END - - -// START buttons_dropdown -// Member variable holding value. -String dropdownValue; - -// Dropdown button with string values. -DropdownButton( - value: dropdownValue, - onChanged: (String newValue) { - // null indicates the user didn't select a - // new value. - setState(() { - if (newValue != null) - dropdownValue = newValue; - }); - }, - items: ['One', 'Two', 'Free', 'Four'] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value)); - }) - .toList(), -); -// END - - -// START buttons_icon -// Member variable holding toggle value. -bool value; - -// Toggleable icon button. -IconButton( - icon: const Icon(Icons.thumb_up), - onPressed: () { - setState(() => value = !value); - }, - color: value ? Theme.of(context).primaryColor : null, -); -// END - - -// START buttons_action -// Floating action button in Scaffold. -Scaffold( - appBar: AppBar( - title: const Text('Demo'), - ), - floatingActionButton: const FloatingActionButton( - child: Icon(Icons.add), - onPressed: null, - ), -); -// END - } -} - - -class SelectionControls { - void setState(VoidCallback callback) { } - - void selectionControls() { - -// START selectioncontrols_checkbox -// Member variable holding the checkbox's value. -bool checkboxValue = false; - -// Create a checkbox. -Checkbox( - value: checkboxValue, - onChanged: (bool value) { - setState(() { - checkboxValue = value; - }); - }, -); - -// Create a tristate checkbox. -Checkbox( - tristate: true, - value: checkboxValue, - onChanged: (bool value) { - setState(() { - checkboxValue = value; - }); - }, -); - -// Create a disabled checkbox. -// Checkboxes are disabled when onChanged isn't -// specified or null. -const Checkbox(value: false, onChanged: null); -// END - - -// START selectioncontrols_radio -// Member variable holding value. -int radioValue = 0; - -// Method setting value. -void handleRadioValueChanged(int value) { - setState(() { - radioValue = value; - }); -} - -// Creates a set of radio buttons. -Row( - children: [ - Radio( - value: 0, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - Radio( - value: 1, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - Radio( - value: 2, - groupValue: radioValue, - onChanged: handleRadioValueChanged, - ), - ], -); - -// Creates a disabled radio button. -const Radio( - value: 0, - groupValue: 0, - onChanged: null, -); -// END - - -// START selectioncontrols_switch -// Member variable holding value. -bool switchValue = false; - -// Create a switch. -Switch( - value: switchValue, - onChanged: (bool value) { - setState(() { - switchValue = value; - } - ); -}); - -// Create a disabled switch. -// Switches are disabled when onChanged isn't -// specified or null. -const Switch(value: false, onChanged: null); -// END - } -} - - -class GridLists { - void gridlists() { -// START gridlists -// Creates a scrollable grid list with images -// loaded from the web. -GridView.count( - crossAxisCount: 3, - childAspectRatio: 1.0, - padding: const EdgeInsets.all(4.0), - mainAxisSpacing: 4.0, - crossAxisSpacing: 4.0, - children: [ - 'https://example.com/image-0.jpg', - 'https://example.com/image-1.jpg', - 'https://example.com/image-2.jpg', - '...', - 'https://example.com/image-n.jpg', - ].map((String url) { - return GridTile( - footer: GridTileBar( - title: Text(url), - ), - child: Image.network(url, fit: BoxFit.cover), - ); - }).toList(), -); -// END - } -} - - -class AnimatedImage { - void animatedImage() { -// START animated_image -Image.network('https://example.com/animated-image.gif'); -// END - } -} diff --git a/web/gallery/lib/gallery/example_code_parser.dart b/web/gallery/lib/gallery/example_code_parser.dart deleted file mode 100644 index 7f5029249..000000000 --- a/web/gallery/lib/gallery/example_code_parser.dart +++ /dev/null @@ -1,55 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/services.dart'; - -const String _kStartTag = '// START '; -const String _kEndTag = '// END'; - -Map _exampleCode; - -Future getExampleCode(String tag, AssetBundle bundle) async { - if (_exampleCode == null) - await _parseExampleCode(bundle); - return _exampleCode[tag]; -} - -Future _parseExampleCode(AssetBundle bundle) async { - final String code = await bundle.loadString('lib/gallery/example_code.dart') ?? - '// lib/gallery/example_code.dart not found\n'; - _exampleCode = {}; - - final List lines = code.split('\n'); - - List codeBlock; - String codeTag; - - for (String line in lines) { - if (codeBlock == null) { - // Outside a block. - if (line.startsWith(_kStartTag)) { - // Starting a new code block. - codeBlock = []; - codeTag = line.substring(_kStartTag.length).trim(); - } else { - // Just skipping the line. - } - } else { - // Inside a block. - if (line.startsWith(_kEndTag)) { - // Add the block. - _exampleCode[codeTag] = codeBlock.join('\n'); - codeBlock = null; - codeTag = null; - } else { - // Add to the current block - // trimRight() to remove any \r on Windows - // without removing any useful indentation - codeBlock.add(line.trimRight()); - } - } - } -} diff --git a/web/gallery/lib/gallery/home.dart b/web/gallery/lib/gallery/home.dart deleted file mode 100644 index ec785383c..000000000 --- a/web/gallery/lib/gallery/home.dart +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2018 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:async'; -import 'dart:developer'; -import 'dart:math' as math; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/gestures.dart' show DragStartBehavior; - -import 'backdrop.dart'; -import 'demos.dart'; - -const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; -const Color _kFlutterBlue = Color(0xFF003D75); -const double _kDemoItemHeight = 64.0; -const Duration _kFrontLayerSwitchDuration = Duration(milliseconds: 300); - -class _FlutterLogo extends StatelessWidget { - const _FlutterLogo({ Key key }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: Container( - width: 34.0, - height: 34.0, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'logos/flutter_white/logo.png', - package: _kGalleryAssetsPackage, - ), - ), - ), - ), - ); - } -} - -class _CategoryItem extends StatelessWidget { - const _CategoryItem({ - Key key, - this.category, - this.onTap, - }) : super (key: key); - - final GalleryDemoCategory category; - final VoidCallback onTap; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final bool isDark = theme.brightness == Brightness.dark; - - // This repaint boundary prevents the entire _CategoriesPage from being - // repainted when the button's ink splash animates. - return RepaintBoundary( - child: RawMaterialButton( - padding: EdgeInsets.zero, - hoverColor: theme.primaryColor.withOpacity(0.05), - splashColor: theme.primaryColor.withOpacity(0.12), - highlightColor: Colors.transparent, - onPressed: onTap, - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(6.0), - child: Icon( - category.icon, - size: 60.0, - color: isDark ? Colors.white : _kFlutterBlue, - ), - ), - const SizedBox(height: 10.0), - Container( - height: 48.0, - alignment: Alignment.center, - child: Text( - category.name, - textAlign: TextAlign.center, - style: theme.textTheme.subhead.copyWith( - fontFamily: 'GoogleSans', - color: isDark ? Colors.white : _kFlutterBlue, - ), - ), - ), - ], - ), - ), - ); - } -} - -class _CategoriesPage extends StatelessWidget { - const _CategoriesPage({ - Key key, - this.categories, - this.onCategoryTap, - }) : super(key: key); - - final Iterable categories; - final ValueChanged onCategoryTap; - - @override - Widget build(BuildContext context) { - const double aspectRatio = 160.0 / 180.0; - final List categoriesList = categories.toList(); - final int columnCount = (MediaQuery.of(context).orientation == Orientation.portrait) ? 2 : 3; - - return Semantics( - scopesRoute: true, - namesRoute: true, - label: 'categories', - explicitChildNodes: true, - child: SingleChildScrollView( - key: const PageStorageKey('categories'), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - final double columnWidth = constraints.biggest.width / columnCount.toDouble(); - final double rowHeight = math.min(225.0, columnWidth * aspectRatio); - final int rowCount = (categories.length + columnCount - 1) ~/ columnCount; - - // This repaint boundary prevents the inner contents of the front layer - // from repainting when the backdrop toggle triggers a repaint on the - // LayoutBuilder. - return RepaintBoundary( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: List.generate(rowCount, (int rowIndex) { - final int columnCountForRow = rowIndex == rowCount - 1 - ? categories.length - columnCount * math.max(0, rowCount - 1) - : columnCount; - - return Row( - children: List.generate(columnCountForRow, (int columnIndex) { - final int index = rowIndex * columnCount + columnIndex; - final GalleryDemoCategory category = categoriesList[index]; - - return SizedBox( - width: columnWidth, - height: rowHeight, - child: _CategoryItem( - category: category, - onTap: () { - onCategoryTap(category); - }, - ), - ); - }), - ); - }), - ), - ); - }, - ), - ), - ); - } -} - -class _DemoItem extends StatelessWidget { - const _DemoItem({ Key key, this.demo }) : super(key: key); - - final GalleryDemo demo; - - void _launchDemo(BuildContext context) { - if (demo.routeName != null) { - Timeline.instantSync('Start Transition', arguments: { - 'from': '/', - 'to': demo.routeName, - }); - Navigator.pushNamed(context, demo.routeName); - } - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final bool isDark = theme.brightness == Brightness.dark; - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); - return RawMaterialButton( - padding: EdgeInsets.zero, - splashColor: theme.primaryColor.withOpacity(0.12), - highlightColor: Colors.transparent, - onPressed: () { - _launchDemo(context); - }, - child: Container( - constraints: BoxConstraints(minHeight: _kDemoItemHeight * textScaleFactor), - child: Row( - children: [ - Container( - width: 56.0, - height: 56.0, - alignment: Alignment.center, - child: Icon( - demo.icon, - size: 24.0, - color: isDark ? Colors.white : _kFlutterBlue, - ), - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - demo.title, - style: theme.textTheme.subhead.copyWith( - color: isDark ? Colors.white : const Color(0xFF202124), - ), - ), - if (demo.subtitle != null) - Text( - demo.subtitle, - style: theme.textTheme.body1.copyWith( - color: isDark ? Colors.white : const Color(0xFF60646B) - ), - ), - ], - ), - ), - const SizedBox(width: 44.0), - ], - ), - ), - ); - } -} - -class _DemosPage extends StatelessWidget { - const _DemosPage(this.category); - - final GalleryDemoCategory category; - - @override - Widget build(BuildContext context) { - // When overriding ListView.padding, it is necessary to manually handle - // safe areas. - final double windowBottomPadding = MediaQuery.of(context).padding.bottom; - return KeyedSubtree( - key: const ValueKey('GalleryDemoList'), // So the tests can find this ListView - child: Semantics( - scopesRoute: true, - namesRoute: true, - label: category.name, - explicitChildNodes: true, - child: ListView( - dragStartBehavior: DragStartBehavior.down, - key: PageStorageKey(category.name), - padding: EdgeInsets.only(top: 8.0, bottom: windowBottomPadding), - children: kGalleryCategoryToDemos[category].map((GalleryDemo demo) { - return _DemoItem(demo: demo); - }).toList(), - ), - ), - ); - } -} - -class GalleryHome extends StatefulWidget { - const GalleryHome({ - Key key, - this.testMode = false, - this.optionsPage, - }) : super(key: key); - - final Widget optionsPage; - final bool testMode; - - // In checked mode our MaterialApp will show the default "debug" banner. - // Otherwise show the "preview" banner. - static bool showPreviewBanner = true; - - @override - _GalleryHomeState createState() => _GalleryHomeState(); -} - -class _GalleryHomeState extends State with SingleTickerProviderStateMixin { - static final GlobalKey _scaffoldKey = GlobalKey(); - AnimationController _controller; - GalleryDemoCategory _category; - - static Widget _topHomeLayout(Widget currentChild, List previousChildren) { - return Stack( - children: [ - ...previousChildren, - if (currentChild != null) currentChild, - ], - alignment: Alignment.topCenter, - ); - } - - static const AnimatedSwitcherLayoutBuilder _centerHomeLayout = AnimatedSwitcher.defaultLayoutBuilder; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 600), - debugLabel: 'preview banner', - vsync: this, - )..forward(); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final bool isDark = theme.brightness == Brightness.dark; - final MediaQueryData media = MediaQuery.of(context); - final bool centerHome = media.orientation == Orientation.portrait && media.size.height < 800.0; - - const Curve switchOutCurve = Interval(0.4, 1.0, curve: Curves.fastOutSlowIn); - const Curve switchInCurve = Interval(0.4, 1.0, curve: Curves.fastOutSlowIn); - - Widget home = Scaffold( - key: _scaffoldKey, - backgroundColor: isDark ? _kFlutterBlue : theme.primaryColor, - body: SafeArea( - bottom: false, - child: WillPopScope( - onWillPop: () { - // Pop the category page if Android back button is pressed. - if (_category != null) { - setState(() => _category = null); - return Future.value(false); - } - return Future.value(true); - }, - child: Backdrop( - backTitle: const Text('Options'), - backLayer: widget.optionsPage, - frontAction: AnimatedSwitcher( - duration: _kFrontLayerSwitchDuration, - switchOutCurve: switchOutCurve, - switchInCurve: switchInCurve, - child: _category == null - ? const _FlutterLogo() - : IconButton( - icon: const BackButtonIcon(), - tooltip: 'Back', - onPressed: () => setState(() => _category = null), - ), - ), - frontTitle: AnimatedSwitcher( - duration: _kFrontLayerSwitchDuration, - child: _category == null - ? const Text('Flutter gallery') - : Text(_category.name), - ), - frontHeading: widget.testMode ? null : Container(height: 24.0), - frontLayer: AnimatedSwitcher( - duration: _kFrontLayerSwitchDuration, - switchOutCurve: switchOutCurve, - switchInCurve: switchInCurve, - layoutBuilder: centerHome ? _centerHomeLayout : _topHomeLayout, - child: _category != null - ? _DemosPage(_category) - : _CategoriesPage( - categories: kAllGalleryDemoCategories, - onCategoryTap: (GalleryDemoCategory category) { - setState(() => _category = category); - }, - ), - ), - ), - ), - ), - ); - - assert(() { - GalleryHome.showPreviewBanner = false; - return true; - }()); - - if (GalleryHome.showPreviewBanner) { - home = Stack( - fit: StackFit.expand, - children: [ - home, - FadeTransition( - opacity: CurvedAnimation(parent: _controller, curve: Curves.easeInOut), - child: const Banner( - message: 'PREVIEW', - location: BannerLocation.topEnd, - ), - ), - ], - ); - } - home = AnnotatedRegion( - child: home, - value: SystemUiOverlayStyle.light, - ); - - return home; - } -} diff --git a/web/gallery/lib/gallery/icons.dart b/web/gallery/lib/gallery/icons.dart deleted file mode 100644 index c82ba7377..000000000 --- a/web/gallery/lib/gallery/icons.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 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'; - -class GalleryIcons { - GalleryIcons._(); - - static const IconData tooltip = IconData(0xe900, fontFamily: 'GalleryIcons'); - static const IconData text_fields_alt = IconData(0xe901, fontFamily: 'GalleryIcons'); - static const IconData tabs = IconData(0xe902, fontFamily: 'GalleryIcons'); - static const IconData switches = IconData(0xe903, fontFamily: 'GalleryIcons'); - static const IconData sliders = IconData(0xe904, fontFamily: 'GalleryIcons'); - static const IconData shrine = IconData(0xe905, fontFamily: 'GalleryIcons'); - static const IconData sentiment_very_satisfied = IconData(0xe906, fontFamily: 'GalleryIcons'); - static const IconData refresh = IconData(0xe907, fontFamily: 'GalleryIcons'); - static const IconData progress_activity = IconData(0xe908, fontFamily: 'GalleryIcons'); - static const IconData phone_iphone = IconData(0xe909, fontFamily: 'GalleryIcons'); - static const IconData page_control = IconData(0xe90a, fontFamily: 'GalleryIcons'); - static const IconData more_vert = IconData(0xe90b, fontFamily: 'GalleryIcons'); - static const IconData menu = IconData(0xe90c, fontFamily: 'GalleryIcons'); - static const IconData list_alt = IconData(0xe90d, fontFamily: 'GalleryIcons'); - static const IconData grid_on = IconData(0xe90e, fontFamily: 'GalleryIcons'); - static const IconData expand_all = IconData(0xe90f, fontFamily: 'GalleryIcons'); - static const IconData event = IconData(0xe910, fontFamily: 'GalleryIcons'); - static const IconData drive_video = IconData(0xe911, fontFamily: 'GalleryIcons'); - static const IconData dialogs = IconData(0xe912, fontFamily: 'GalleryIcons'); - static const IconData data_table = IconData(0xe913, fontFamily: 'GalleryIcons'); - static const IconData custom_typography = IconData(0xe914, fontFamily: 'GalleryIcons'); - static const IconData colors = IconData(0xe915, fontFamily: 'GalleryIcons'); - static const IconData chips = IconData(0xe916, fontFamily: 'GalleryIcons'); - static const IconData check_box = IconData(0xe917, fontFamily: 'GalleryIcons'); - static const IconData cards = IconData(0xe918, fontFamily: 'GalleryIcons'); - static const IconData buttons = IconData(0xe919, fontFamily: 'GalleryIcons'); - static const IconData bottom_sheets = IconData(0xe91a, fontFamily: 'GalleryIcons'); - static const IconData bottom_navigation = IconData(0xe91b, fontFamily: 'GalleryIcons'); - static const IconData animation = IconData(0xe91c, fontFamily: 'GalleryIcons'); - static const IconData account_box = IconData(0xe91d, fontFamily: 'GalleryIcons'); - static const IconData snackbar = IconData(0xe91e, fontFamily: 'GalleryIcons'); - static const IconData category_mdc = IconData(0xe91f, fontFamily: 'GalleryIcons'); - static const IconData cupertino_progress = IconData(0xe920, fontFamily: 'GalleryIcons'); - static const IconData cupertino_pull_to_refresh = IconData(0xe921, fontFamily: 'GalleryIcons'); - static const IconData cupertino_switch = IconData(0xe922, fontFamily: 'GalleryIcons'); - static const IconData generic_buttons = IconData(0xe923, fontFamily: 'GalleryIcons'); - static const IconData backdrop = IconData(0xe924, fontFamily: 'GalleryIcons'); - static const IconData bottom_app_bar = IconData(0xe925, fontFamily: 'GalleryIcons'); - static const IconData bottom_sheet_persistent = IconData(0xe926, fontFamily: 'GalleryIcons'); - static const IconData lists_leave_behind = IconData(0xe927, fontFamily: 'GalleryIcons'); -} diff --git a/web/gallery/lib/gallery/options.dart b/web/gallery/lib/gallery/options.dart deleted file mode 100644 index 1849c2a86..000000000 --- a/web/gallery/lib/gallery/options.dart +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright 2018 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 'about.dart'; -import 'scales.dart'; - -class GalleryOptions { - GalleryOptions({ - this.themeMode, - this.textScaleFactor, - this.textDirection = TextDirection.ltr, - this.timeDilation = 1.0, - this.platform, - this.showOffscreenLayersCheckerboard = false, - this.showRasterCacheImagesCheckerboard = false, - this.showPerformanceOverlay = false, - }); - - final ThemeMode themeMode; - final GalleryTextScaleValue textScaleFactor; - final TextDirection textDirection; - final double timeDilation; - final TargetPlatform platform; - final bool showPerformanceOverlay; - final bool showRasterCacheImagesCheckerboard; - final bool showOffscreenLayersCheckerboard; - - GalleryOptions copyWith({ - ThemeMode themeMode, - GalleryTextScaleValue textScaleFactor, - TextDirection textDirection, - double timeDilation, - TargetPlatform platform, - bool showPerformanceOverlay, - bool showRasterCacheImagesCheckerboard, - bool showOffscreenLayersCheckerboard, - }) { - return GalleryOptions( - themeMode: themeMode ?? this.themeMode, - textScaleFactor: textScaleFactor ?? this.textScaleFactor, - textDirection: textDirection ?? this.textDirection, - timeDilation: timeDilation ?? this.timeDilation, - platform: platform ?? this.platform, - showPerformanceOverlay: showPerformanceOverlay ?? this.showPerformanceOverlay, - showOffscreenLayersCheckerboard: showOffscreenLayersCheckerboard ?? this.showOffscreenLayersCheckerboard, - showRasterCacheImagesCheckerboard: showRasterCacheImagesCheckerboard ?? this.showRasterCacheImagesCheckerboard, - ); - } - - @override - bool operator ==(dynamic other) { - if (runtimeType != other.runtimeType) - return false; - final GalleryOptions typedOther = other; - return themeMode == typedOther.themeMode - && textScaleFactor == typedOther.textScaleFactor - && textDirection == typedOther.textDirection - && platform == typedOther.platform - && showPerformanceOverlay == typedOther.showPerformanceOverlay - && showRasterCacheImagesCheckerboard == typedOther.showRasterCacheImagesCheckerboard - && showOffscreenLayersCheckerboard == typedOther.showRasterCacheImagesCheckerboard; - } - - @override - int get hashCode => hashValues( - themeMode, - textScaleFactor, - textDirection, - timeDilation, - platform, - showPerformanceOverlay, - showRasterCacheImagesCheckerboard, - showOffscreenLayersCheckerboard, - ); - - @override - String toString() { - return '$runtimeType($themeMode)'; - } -} - -const double _kItemHeight = 48.0; -const EdgeInsetsDirectional _kItemPadding = EdgeInsetsDirectional.only(start: 56.0); - -class _OptionsItem extends StatelessWidget { - const _OptionsItem({ Key key, this.child }) : super(key: key); - - final Widget child; - - @override - Widget build(BuildContext context) { - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); - - return MergeSemantics( - child: Container( - constraints: BoxConstraints(minHeight: _kItemHeight * textScaleFactor), - padding: _kItemPadding, - alignment: AlignmentDirectional.centerStart, - child: DefaultTextStyle( - style: DefaultTextStyle.of(context).style, - maxLines: 2, - overflow: TextOverflow.fade, - child: IconTheme( - data: Theme.of(context).primaryIconTheme, - child: child, - ), - ), - ), - ); - } -} - -class _BooleanItem extends StatelessWidget { - const _BooleanItem(this.title, this.value, this.onChanged, { this.switchKey }); - - final String title; - final bool value; - final ValueChanged onChanged; - // [switchKey] is used for accessing the switch from driver tests. - final Key switchKey; - - @override - Widget build(BuildContext context) { - final bool isDark = Theme.of(context).brightness == Brightness.dark; - return _OptionsItem( - child: Row( - children: [ - Expanded(child: Text(title)), - Switch( - key: switchKey, - value: value, - onChanged: onChanged, - activeColor: const Color(0xFF39CEFD), - activeTrackColor: isDark ? Colors.white30 : Colors.black26, - ), - ], - ), - ); - } -} - -class _ActionItem extends StatelessWidget { - const _ActionItem(this.text, this.onTap); - - final String text; - final VoidCallback onTap; - - @override - Widget build(BuildContext context) { - return _OptionsItem( - child: _FlatButton( - onPressed: onTap, - child: Text(text), - ), - ); - } -} - -class _FlatButton extends StatelessWidget { - const _FlatButton({ Key key, this.onPressed, this.child }) : super(key: key); - - final VoidCallback onPressed; - final Widget child; - - @override - Widget build(BuildContext context) { - return FlatButton( - padding: EdgeInsets.zero, - onPressed: onPressed, - child: DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.subhead, - child: child, - ), - ); - } -} - -class _Heading extends StatelessWidget { - const _Heading(this.text); - - final String text; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - return _OptionsItem( - child: DefaultTextStyle( - style: theme.textTheme.body1.copyWith( - fontFamily: 'GoogleSans', - color: theme.accentColor, - ), - child: Semantics( - child: Text(text), - header: true, - ), - ), - ); - } -} - -class _ThemeModeItem extends StatelessWidget { - const _ThemeModeItem(this.options, this.onOptionsChanged); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - - static final Map modeLabels = { - ThemeMode.system: 'System Default', - ThemeMode.light: 'Light', - ThemeMode.dark: 'Dark', - }; - - @override - Widget build(BuildContext context) { - return _OptionsItem( - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Theme'), - Text( - '${modeLabels[options.themeMode]}', - style: Theme.of(context).primaryTextTheme.body1, - ), - ], - ), - ), - PopupMenuButton( - padding: const EdgeInsetsDirectional.only(end: 16.0), - icon: const Icon(Icons.arrow_drop_down), - initialValue: options.themeMode, - itemBuilder: (BuildContext context) { - return ThemeMode.values.map>((ThemeMode mode) { - return PopupMenuItem( - value: mode, - child: Text(modeLabels[mode]), - ); - }).toList(); - }, - onSelected: (ThemeMode mode) { - onOptionsChanged( - options.copyWith(themeMode: mode), - ); - }, - ), - ], - ), - ); - } -} - -class _TextScaleFactorItem extends StatelessWidget { - const _TextScaleFactorItem(this.options, this.onOptionsChanged); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - - @override - Widget build(BuildContext context) { - return _OptionsItem( - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Text size'), - Text( - '${options.textScaleFactor.label}', - style: Theme.of(context).primaryTextTheme.body1, - ), - ], - ), - ), - PopupMenuButton( - padding: const EdgeInsetsDirectional.only(end: 16.0), - icon: const Icon(Icons.arrow_drop_down), - itemBuilder: (BuildContext context) { - return kAllGalleryTextScaleValues.map>((GalleryTextScaleValue scaleValue) { - return PopupMenuItem( - value: scaleValue, - child: Text(scaleValue.label), - ); - }).toList(); - }, - onSelected: (GalleryTextScaleValue scaleValue) { - onOptionsChanged( - options.copyWith(textScaleFactor: scaleValue), - ); - }, - ), - ], - ), - ); - } -} - -class _TextDirectionItem extends StatelessWidget { - const _TextDirectionItem(this.options, this.onOptionsChanged); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - - @override - Widget build(BuildContext context) { - return _BooleanItem( - 'Force RTL', - options.textDirection == TextDirection.rtl, - (bool value) { - onOptionsChanged( - options.copyWith( - textDirection: value ? TextDirection.rtl : TextDirection.ltr, - ), - ); - }, - switchKey: const Key('text_direction'), - ); - } -} - -class _TimeDilationItem extends StatelessWidget { - const _TimeDilationItem(this.options, this.onOptionsChanged); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - - @override - Widget build(BuildContext context) { - return _BooleanItem( - 'Slow motion', - options.timeDilation != 1.0, - (bool value) { - onOptionsChanged( - options.copyWith( - timeDilation: value ? 20.0 : 1.0, - ), - ); - }, - switchKey: const Key('slow_motion'), - ); - } -} - -class _PlatformItem extends StatelessWidget { - const _PlatformItem(this.options, this.onOptionsChanged); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - - String _platformLabel(TargetPlatform platform) { - switch(platform) { - case TargetPlatform.android: - return 'Mountain View'; - case TargetPlatform.fuchsia: - return 'Fuchsia'; - case TargetPlatform.iOS: - case TargetPlatform.macOS: - return 'Cupertino'; - } - assert(false); - return null; - } - - @override - Widget build(BuildContext context) { - return _OptionsItem( - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Platform mechanics'), - Text( - '${_platformLabel(options.platform)}', - style: Theme.of(context).primaryTextTheme.body1, - ), - ], - ), - ), - PopupMenuButton( - padding: const EdgeInsetsDirectional.only(end: 16.0), - icon: const Icon(Icons.arrow_drop_down), - itemBuilder: (BuildContext context) { - return TargetPlatform.values.map((TargetPlatform platform) { - return PopupMenuItem( - value: platform, - child: Text(_platformLabel(platform)), - ); - }).toList(); - }, - onSelected: (TargetPlatform platform) { - onOptionsChanged( - options.copyWith(platform: platform), - ); - }, - ), - ], - ), - ); - } -} - -class GalleryOptionsPage extends StatelessWidget { - const GalleryOptionsPage({ - Key key, - this.options, - this.onOptionsChanged, - this.onSendFeedback, - }) : super(key: key); - - final GalleryOptions options; - final ValueChanged onOptionsChanged; - final VoidCallback onSendFeedback; - - List _enabledDiagnosticItems() { - // Boolean showFoo options with a value of null: don't display - // the showFoo option at all. - if (options.showOffscreenLayersCheckerboard == null && - options.showRasterCacheImagesCheckerboard == null && - options.showPerformanceOverlay == null) - return const []; - - return [ - const Divider(), - const _Heading('Diagnostics'), - if (options.showOffscreenLayersCheckerboard != null) - _BooleanItem( - 'Highlight offscreen layers', - options.showOffscreenLayersCheckerboard, - (bool value) { - onOptionsChanged(options.copyWith(showOffscreenLayersCheckerboard: value)); - }, - ), - if (options.showRasterCacheImagesCheckerboard != null) - _BooleanItem( - 'Highlight raster cache images', - options.showRasterCacheImagesCheckerboard, - (bool value) { - onOptionsChanged(options.copyWith(showRasterCacheImagesCheckerboard: value)); - }, - ), - if (options.showPerformanceOverlay != null) - _BooleanItem( - 'Show performance overlay', - options.showPerformanceOverlay, - (bool value) { - onOptionsChanged(options.copyWith(showPerformanceOverlay: value)); - }, - ), - ]; - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - - return DefaultTextStyle( - style: theme.primaryTextTheme.subhead, - child: ListView( - padding: const EdgeInsets.only(bottom: 124.0), - children: [ - const _Heading('Display'), - _ThemeModeItem(options, onOptionsChanged), - _TextScaleFactorItem(options, onOptionsChanged), - _TextDirectionItem(options, onOptionsChanged), - _TimeDilationItem(options, onOptionsChanged), - const Divider(), - const _Heading('Platform mechanics'), - _PlatformItem(options, onOptionsChanged), - ..._enabledDiagnosticItems(), - const Divider(), - const _Heading('Flutter gallery'), - _ActionItem('About Flutter Gallery', () { - showGalleryAboutDialog(context); - }), - _ActionItem('Send feedback', onSendFeedback), - ], - ), - ); - } -} diff --git a/web/gallery/lib/gallery/scales.dart b/web/gallery/lib/gallery/scales.dart deleted file mode 100644 index 3e96db11e..000000000 --- a/web/gallery/lib/gallery/scales.dart +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 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'; - -class GalleryTextScaleValue { - const GalleryTextScaleValue(this.scale, this.label); - - final double scale; - final String label; - - @override - bool operator ==(dynamic other) { - if (runtimeType != other.runtimeType) - return false; - final GalleryTextScaleValue typedOther = other; - return scale == typedOther.scale && label == typedOther.label; - } - - @override - int get hashCode => hashValues(scale, label); - - @override - String toString() { - return '$runtimeType($label)'; - } - -} - -const List kAllGalleryTextScaleValues = [ - GalleryTextScaleValue(null, 'System Default'), - GalleryTextScaleValue(0.8, 'Small'), - GalleryTextScaleValue(1.0, 'Normal'), - GalleryTextScaleValue(1.3, 'Large'), - GalleryTextScaleValue(2.0, 'Huge'), -]; diff --git a/web/gallery/lib/gallery/syntax_highlighter.dart b/web/gallery/lib/gallery/syntax_highlighter.dart deleted file mode 100644 index 7d4e7d6ef..000000000 --- a/web/gallery/lib/gallery/syntax_highlighter.dart +++ /dev/null @@ -1,356 +0,0 @@ -// 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:string_scanner/string_scanner.dart'; - -class SyntaxHighlighterStyle { - SyntaxHighlighterStyle({ - this.baseStyle, - this.numberStyle, - this.commentStyle, - this.keywordStyle, - this.stringStyle, - this.punctuationStyle, - this.classStyle, - this.constantStyle, - }); - - static SyntaxHighlighterStyle lightThemeStyle() { - return SyntaxHighlighterStyle( - baseStyle: const TextStyle(color: Color(0xFF000000)), - numberStyle: const TextStyle(color: Color(0xFF1565C0)), - commentStyle: const TextStyle(color: Color(0xFF9E9E9E)), - keywordStyle: const TextStyle(color: Color(0xFF9C27B0)), - stringStyle: const TextStyle(color: Color(0xFF43A047)), - punctuationStyle: const TextStyle(color: Color(0xFF000000)), - classStyle: const TextStyle(color: Color(0xFF512DA8)), - constantStyle: const TextStyle(color: Color(0xFF795548)), - ); - } - - static SyntaxHighlighterStyle darkThemeStyle() { - return SyntaxHighlighterStyle( - baseStyle: const TextStyle(color: Color(0xFFFFFFFF)), - numberStyle: const TextStyle(color: Color(0xFF1565C0)), - commentStyle: const TextStyle(color: Color(0xFF9E9E9E)), - keywordStyle: const TextStyle(color: Color(0xFF80CBC4)), - stringStyle: const TextStyle(color: Color(0xFF009688)), - punctuationStyle: const TextStyle(color: Color(0xFFFFFFFF)), - classStyle: const TextStyle(color: Color(0xFF009688)), - constantStyle: const TextStyle(color: Color(0xFF795548)), - ); - } - - final TextStyle baseStyle; - final TextStyle numberStyle; - final TextStyle commentStyle; - final TextStyle keywordStyle; - final TextStyle stringStyle; - final TextStyle punctuationStyle; - final TextStyle classStyle; - final TextStyle constantStyle; -} - -abstract class SyntaxHighlighter { - TextSpan format(String src); -} - -class DartSyntaxHighlighter extends SyntaxHighlighter { - DartSyntaxHighlighter([this._style]) { - _spans = <_HighlightSpan>[]; - _style ??= SyntaxHighlighterStyle.darkThemeStyle(); - } - - SyntaxHighlighterStyle _style; - - static const List _keywords = [ - 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', - 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', - 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', - 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', - 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', - 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', - 'void', 'while', 'with', 'yield', - ]; - - static const List _builtInTypes = [ - 'int', 'double', 'num', 'bool', - ]; - - String _src; - StringScanner _scanner; - - List<_HighlightSpan> _spans; - - @override - TextSpan format(String src) { - _src = src; - _scanner = StringScanner(_src); - - if (_generateSpans()) { - // Successfully parsed the code - final List formattedText = []; - int currentPosition = 0; - - for (_HighlightSpan span in _spans) { - if (currentPosition != span.start) - formattedText.add(TextSpan(text: _src.substring(currentPosition, span.start))); - - formattedText.add(TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src))); - - currentPosition = span.end; - } - - if (currentPosition != _src.length) - formattedText.add(TextSpan(text: _src.substring(currentPosition, _src.length))); - - return TextSpan(style: _style.baseStyle, children: formattedText); - } else { - // Parsing failed, return with only basic formatting - return TextSpan(style: _style.baseStyle, text: src); - } - } - - bool _generateSpans() { - int lastLoopPosition = _scanner.position; - - while (!_scanner.isDone) { - // Skip White space - _scanner.scan(RegExp(r'\s+')); - - // Block comments - if (_scanner.scan(RegExp(r'/\*(.|\n)*\*/'))) { - _spans.add(_HighlightSpan( - _HighlightType.comment, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Line comments - if (_scanner.scan('//')) { - final int startComment = _scanner.lastMatch.start; - - bool eof = false; - int endComment; - if (_scanner.scan(RegExp(r'.*\n'))) { - endComment = _scanner.lastMatch.end - 1; - } else { - eof = true; - endComment = _src.length; - } - - _spans.add(_HighlightSpan( - _HighlightType.comment, - startComment, - endComment, - )); - - if (eof) - break; - - continue; - } - - // Raw r"String" - if (_scanner.scan(RegExp(r'r".*"'))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Raw r'String' - if (_scanner.scan(RegExp(r"r'.*'"))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Multiline """String""" - if (_scanner.scan(RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Multiline '''String''' - if (_scanner.scan(RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // "String" - if (_scanner.scan(RegExp(r'"(?:[^"\\]|\\.)*"'))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // 'String' - if (_scanner.scan(RegExp(r"'(?:[^'\\]|\\.)*'"))) { - _spans.add(_HighlightSpan( - _HighlightType.string, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Double - if (_scanner.scan(RegExp(r'\d+\.\d+'))) { - _spans.add(_HighlightSpan( - _HighlightType.number, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Integer - if (_scanner.scan(RegExp(r'\d+'))) { - _spans.add(_HighlightSpan( - _HighlightType.number, - _scanner.lastMatch.start, - _scanner.lastMatch.end) - ); - continue; - } - - // Punctuation - if (_scanner.scan(RegExp(r'[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]'))) { - _spans.add(_HighlightSpan( - _HighlightType.punctuation, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Meta data - if (_scanner.scan(RegExp(r'@\w+'))) { - _spans.add(_HighlightSpan( - _HighlightType.keyword, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - continue; - } - - // Words - if (_scanner.scan(RegExp(r'\w+'))) { - _HighlightType type; - - String word = _scanner.lastMatch[0]; - if (word.startsWith('_')) - word = word.substring(1); - - if (_keywords.contains(word)) - type = _HighlightType.keyword; - else if (_builtInTypes.contains(word)) - type = _HighlightType.keyword; - else if (_firstLetterIsUpperCase(word)) - type = _HighlightType.klass; - else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1))) - type = _HighlightType.constant; - - if (type != null) { - _spans.add(_HighlightSpan( - type, - _scanner.lastMatch.start, - _scanner.lastMatch.end, - )); - } - } - - // Check if this loop did anything - if (lastLoopPosition == _scanner.position) { - // Failed to parse this file, abort gracefully - return false; - } - lastLoopPosition = _scanner.position; - } - - _simplify(); - return true; - } - - void _simplify() { - for (int i = _spans.length - 2; i >= 0; i -= 1) { - if (_spans[i].type == _spans[i + 1].type && _spans[i].end == _spans[i + 1].start) { - _spans[i] = _HighlightSpan( - _spans[i].type, - _spans[i].start, - _spans[i + 1].end, - ); - _spans.removeAt(i + 1); - } - } - } - - bool _firstLetterIsUpperCase(String str) { - if (str.isNotEmpty) { - final String first = str.substring(0, 1); - return first == first.toUpperCase(); - } - return false; - } -} - -enum _HighlightType { - number, - comment, - keyword, - string, - punctuation, - klass, - constant -} - -class _HighlightSpan { - _HighlightSpan(this.type, this.start, this.end); - final _HighlightType type; - final int start; - final int end; - - String textForSpan(String src) { - return src.substring(start, end); - } - - TextStyle textStyle(SyntaxHighlighterStyle style) { - if (type == _HighlightType.number) - return style.numberStyle; - else if (type == _HighlightType.comment) - return style.commentStyle; - else if (type == _HighlightType.keyword) - return style.keywordStyle; - else if (type == _HighlightType.string) - return style.stringStyle; - else if (type == _HighlightType.punctuation) - return style.punctuationStyle; - else if (type == _HighlightType.klass) - return style.classStyle; - else if (type == _HighlightType.constant) - return style.constantStyle; - else - return style.baseStyle; - } -} diff --git a/web/gallery/lib/gallery/themes.dart b/web/gallery/lib/gallery/themes.dart deleted file mode 100644 index 78430128b..000000000 --- a/web/gallery/lib/gallery/themes.dart +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 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'; - -final ThemeData kLightGalleryTheme = _buildLightTheme(); -final ThemeData kDarkGalleryTheme = _buildDarkTheme(); - -TextTheme _buildTextTheme(TextTheme base) { - return base.copyWith( - title: base.title.copyWith( - fontFamily: 'GoogleSans', - ), - ); -} - -ThemeData _buildDarkTheme() { - const Color primaryColor = Color(0xFF0175c2); - const Color secondaryColor = Color(0xFF13B9FD); - final ColorScheme colorScheme = const ColorScheme.dark().copyWith( - primary: primaryColor, - secondary: secondaryColor, - ); - final ThemeData base = ThemeData( - brightness: Brightness.dark, - accentColorBrightness: Brightness.dark, - primaryColor: primaryColor, - primaryColorDark: const Color(0xFF0050a0), - primaryColorLight: secondaryColor, - buttonColor: primaryColor, - indicatorColor: Colors.white, - toggleableActiveColor: const Color(0xFF6997DF), - accentColor: secondaryColor, - canvasColor: const Color(0xFF202124), - scaffoldBackgroundColor: const Color(0xFF202124), - backgroundColor: const Color(0xFF202124), - errorColor: const Color(0xFFB00020), - buttonTheme: ButtonThemeData( - colorScheme: colorScheme, - textTheme: ButtonTextTheme.primary, - ), - ); - return base.copyWith( - textTheme: _buildTextTheme(base.textTheme), - primaryTextTheme: _buildTextTheme(base.primaryTextTheme), - accentTextTheme: _buildTextTheme(base.accentTextTheme), - ); -} - -ThemeData _buildLightTheme() { - const Color primaryColor = Color(0xFF0175c2); - const Color secondaryColor = Color(0xFF13B9FD); - final ColorScheme colorScheme = const ColorScheme.light().copyWith( - primary: primaryColor, - secondary: secondaryColor, - ); - final ThemeData base = ThemeData( - brightness: Brightness.light, - accentColorBrightness: Brightness.dark, - colorScheme: colorScheme, - primaryColor: primaryColor, - buttonColor: primaryColor, - indicatorColor: Colors.white, - toggleableActiveColor: const Color(0xFF1E88E5), - splashColor: Colors.white24, - splashFactory: InkRipple.splashFactory, - accentColor: secondaryColor, - canvasColor: Colors.white, - scaffoldBackgroundColor: Colors.white, - backgroundColor: Colors.white, - errorColor: const Color(0xFFB00020), - buttonTheme: ButtonThemeData( - colorScheme: colorScheme, - textTheme: ButtonTextTheme.primary, - ), - ); - return base.copyWith( - textTheme: _buildTextTheme(base.textTheme), - primaryTextTheme: _buildTextTheme(base.primaryTextTheme), - accentTextTheme: _buildTextTheme(base.accentTextTheme), - ); -} diff --git a/web/gallery/lib/gallery/updater.dart b/web/gallery/lib/gallery/updater.dart deleted file mode 100644 index c27a109b5..000000000 --- a/web/gallery/lib/gallery/updater.dart +++ /dev/null @@ -1,75 +0,0 @@ -// 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 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'package:url_launcher/url_launcher.dart'; - -typedef UpdateUrlFetcher = Future Function(); - -class Updater extends StatefulWidget { - const Updater({ @required this.updateUrlFetcher, this.child, Key key }) - : assert(updateUrlFetcher != null), - super(key: key); - - final UpdateUrlFetcher updateUrlFetcher; - final Widget child; - - @override - State createState() => UpdaterState(); -} - -class UpdaterState extends State { - @override - void initState() { - super.initState(); - _checkForUpdates(); - } - - static DateTime _lastUpdateCheck; - Future _checkForUpdates() async { - // Only prompt once a day - if (_lastUpdateCheck != null && - DateTime.now().difference(_lastUpdateCheck) < const Duration(days: 1)) { - return; // We already checked for updates recently - } - _lastUpdateCheck = DateTime.now(); - - final String updateUrl = await widget.updateUrlFetcher(); - if (updateUrl != null) { - final bool wantsUpdate = await showDialog(context: context, builder: _buildDialog); - if (wantsUpdate != null && wantsUpdate) - launch(updateUrl); - } - } - - Widget _buildDialog(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = - theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); - return AlertDialog( - title: const Text('Update Flutter Gallery?'), - content: Text('A newer version is available.', style: dialogTextStyle), - actions: [ - FlatButton( - child: const Text('NO THANKS'), - onPressed: () { - Navigator.pop(context, false); - }, - ), - FlatButton( - child: const Text('UPDATE'), - onPressed: () { - Navigator.pop(context, true); - }, - ), - ], - ); - } - - @override - Widget build(BuildContext context) => widget.child; -} diff --git a/web/gallery/lib/main.dart b/web/gallery/lib/main.dart deleted file mode 100644 index 0f0093d76..000000000 --- a/web/gallery/lib/main.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -// Thanks for checking out Flutter! -// Like what you see? Tweet us @FlutterDev - -import 'package:flutter/material.dart'; - -import 'gallery/app.dart'; - -void main() { - runApp(const GalleryApp()); -} diff --git a/web/gallery/lib/main_publish.dart b/web/gallery/lib/main_publish.dart deleted file mode 100644 index 5b4c37f7c..000000000 --- a/web/gallery/lib/main_publish.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 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 'gallery/home.dart'; -import 'main.dart' as other_main; - -// This main chain-calls main.dart's main. This file is used for publishing -// the gallery and removes the 'PREVIEW' banner. -void main() { - GalleryHome.showPreviewBanner = false; - other_main.main(); -} diff --git a/web/gallery/pubspec.lock b/web/gallery/pubspec.lock deleted file mode 100644 index e6086bafd..000000000 --- a/web/gallery/pubspec.lock +++ /dev/null @@ -1,573 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - analyzer: - dependency: "direct dev" - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "0.38.5" - archive: - dependency: "direct dev" - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - args: - dependency: "direct dev" - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.2" - async: - dependency: "direct dev" - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.0" - boolean_selector: - dependency: "direct dev" - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" - charcode: - dependency: "direct main" - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.2" - collection: - dependency: "direct main" - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.14.11" - connectivity: - dependency: "direct main" - description: - name: connectivity - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.5+3" - convert: - dependency: "direct dev" - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - coverage: - dependency: "direct dev" - description: - name: coverage - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.3+1" - crypto: - dependency: "direct dev" - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - csslib: - dependency: "direct dev" - description: - name: csslib - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" - device_info: - dependency: "direct main" - description: - name: device_info - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.1+1" - file: - dependency: "direct dev" - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_gallery_assets: - dependency: "direct main" - description: - name: flutter_gallery_assets - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.9+2" - flutter_goldens: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_goldens_client: - dependency: transitive - description: - path: "../../../../../flutter/packages/flutter_goldens_client" - relative: true - source: path - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - front_end: - dependency: "direct dev" - description: - name: front_end - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.27" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: "direct dev" - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - html: - dependency: "direct dev" - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.0+3" - http: - dependency: "direct dev" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.0+2" - http_multi_server: - dependency: "direct dev" - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - http_parser: - dependency: "direct dev" - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.3" - image: - dependency: "direct dev" - description: - name: image - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" - intl: - dependency: "direct main" - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.0" - io: - dependency: "direct dev" - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.3" - js: - dependency: "direct dev" - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.1+1" - json_rpc_2: - dependency: "direct dev" - description: - name: json_rpc_2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - kernel: - dependency: "direct dev" - description: - name: kernel - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.27" - logging: - dependency: "direct dev" - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "0.11.3+2" - matcher: - dependency: "direct dev" - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.6" - meta: - dependency: "direct main" - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.8" - mime: - dependency: "direct dev" - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.6+3" - multi_server_socket: - dependency: "direct dev" - description: - name: multi_server_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - node_interop: - dependency: "direct dev" - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - node_io: - dependency: "direct dev" - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1+2" - node_preamble: - dependency: "direct dev" - description: - name: node_preamble - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.8" - package_config: - dependency: "direct dev" - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - package_resolver: - dependency: "direct dev" - description: - name: package_resolver - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.10" - path: - dependency: "direct main" - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.4" - pedantic: - dependency: "direct dev" - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0+1" - petitparser: - dependency: "direct dev" - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.0" - platform: - dependency: "direct dev" - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" - pool: - dependency: "direct dev" - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.0" - process: - dependency: "direct dev" - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.12" - pub_semver: - dependency: "direct dev" - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.2" - quiver: - dependency: "direct dev" - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - scoped_model: - dependency: "direct main" - description: - name: scoped_model - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - shelf: - dependency: "direct dev" - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.5" - shelf_packages_handler: - dependency: "direct dev" - description: - name: shelf_packages_handler - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - shelf_static: - dependency: "direct dev" - description: - name: shelf_static - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.8" - shelf_web_socket: - dependency: "direct dev" - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.3" - shrine_images: - dependency: "direct main" - description: - name: shrine_images - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_map_stack_trace: - dependency: "direct dev" - description: - name: source_map_stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.5" - source_maps: - dependency: "direct dev" - description: - name: source_maps - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.8" - source_span: - dependency: "direct main" - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.5" - stack_trace: - dependency: "direct dev" - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.3" - stream_channel: - dependency: "direct dev" - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: "direct main" - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" - term_glyph: - dependency: "direct main" - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - test: - dependency: "direct dev" - description: - name: test - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.4" - test_api: - dependency: "direct dev" - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.11" - test_core: - dependency: "direct dev" - description: - name: test_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.15" - typed_data: - dependency: "direct main" - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.6" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - url: "https://pub.dartlang.org" - source: hosted - version: "5.2.5" - url_launcher_platform_interface: - dependency: "direct main" - description: - name: url_launcher_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - vector_math: - dependency: "direct main" - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - video_player: - dependency: "direct main" - description: - name: video_player - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.4+1" - video_player_platform_interface: - dependency: transitive - description: - name: video_player_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - video_player_web: - dependency: "direct main" - description: - name: video_player_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.0" - vm_service: - dependency: "direct dev" - description: - name: vm_service - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - vm_service_client: - dependency: "direct dev" - description: - name: vm_service_client - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.6+2" - watcher: - dependency: "direct dev" - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7+12" - web_socket_channel: - dependency: "direct dev" - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - xml: - dependency: "direct dev" - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "3.5.0" - yaml: - dependency: "direct dev" - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" -sdks: - dart: ">=2.4.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" diff --git a/web/gallery/pubspec.yaml b/web/gallery/pubspec.yaml deleted file mode 100644 index 3884db6a6..000000000 --- a/web/gallery/pubspec.yaml +++ /dev/null @@ -1,338 +0,0 @@ -name: flutter_gallery - -environment: - # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite. - sdk: ">=2.2.2 <3.0.0" - -dependencies: - flutter: - sdk: flutter - collection: 1.14.11 - device_info: 0.4.1+1 - intl: 0.16.0 - connectivity: 0.4.5+3 - string_scanner: 1.0.5 - url_launcher: 5.2.5 - cupertino_icons: 0.1.2 - video_player: 0.10.4+1 - video_player_web: 0.1.0 - scoped_model: 1.0.1 - shrine_images: 1.1.2 - - # Also update dev/benchmarks/complex_layout/pubspec.yaml - flutter_gallery_assets: 0.1.9+2 - - charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - flutter_goldens: - sdk: flutter - test: 1.9.4 - - analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - html: 0.14.0+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 0.12.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - image: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 0.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_io: 1.0.1+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 1.4.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_resolver: 1.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pedantic: 1.8.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 3.0.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - quiver: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 0.7.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 0.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 0.9.7+12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -flutter: - uses-material-design: true - assets: - - preview.png - - lib/gallery/example_code.dart - - packages/flutter_gallery_assets/people/ali_landscape.png - - packages/flutter_gallery_assets/monochrome/red-square-1024x1024.png - - packages/flutter_gallery_assets/logos/flutter_white/logo.png - - packages/flutter_gallery_assets/logos/fortnightly/fortnightly_logo.png - - packages/flutter_gallery_assets/videos/bee.mp4 - - packages/flutter_gallery_assets/videos/butterfly.mp4 - - packages/flutter_gallery_assets/animated_images/animated_flutter_lgtm.gif - - packages/flutter_gallery_assets/animated_images/animated_flutter_stickers.webp - - packages/flutter_gallery_assets/food/butternut_squash_soup.png - - packages/flutter_gallery_assets/food/cherry_pie.png - - packages/flutter_gallery_assets/food/chopped_beet_leaves.png - - packages/flutter_gallery_assets/food/fruits.png - - packages/flutter_gallery_assets/food/pesto_pasta.png - - packages/flutter_gallery_assets/food/roasted_chicken.png - - packages/flutter_gallery_assets/food/spanakopita.png - - packages/flutter_gallery_assets/food/spinach_onion_salad.png - - packages/flutter_gallery_assets/food/icons/fish.png - - packages/flutter_gallery_assets/food/icons/healthy.png - - packages/flutter_gallery_assets/food/icons/main.png - - packages/flutter_gallery_assets/food/icons/meat.png - - packages/flutter_gallery_assets/food/icons/quick.png - - packages/flutter_gallery_assets/food/icons/spicy.png - - packages/flutter_gallery_assets/food/icons/veggie.png - - packages/flutter_gallery_assets/logos/pesto/logo_small.png - - packages/flutter_gallery_assets/places/india_chennai_flower_market.png - - packages/flutter_gallery_assets/places/india_thanjavur_market.png - - packages/flutter_gallery_assets/places/india_tanjore_bronze_works.png - - packages/flutter_gallery_assets/places/india_tanjore_market_merchant.png - - packages/flutter_gallery_assets/places/india_tanjore_thanjavur_temple.png - - packages/flutter_gallery_assets/places/india_pondicherry_salt_farm.png - - packages/flutter_gallery_assets/places/india_chennai_highway.png - - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png - - packages/flutter_gallery_assets/places/india_tanjore_thanjavur_temple_carvings.png - - packages/flutter_gallery_assets/places/india_chettinad_produce.png - - packages/flutter_gallery_assets/places/india_tanjore_market_technology.png - - packages/flutter_gallery_assets/places/india_pondicherry_beach.png - - packages/flutter_gallery_assets/places/india_pondicherry_fisherman.png - - packages/flutter_gallery_assets/products/backpack.png - - packages/flutter_gallery_assets/products/belt.png - - packages/flutter_gallery_assets/products/cup.png - - packages/flutter_gallery_assets/products/deskset.png - - packages/flutter_gallery_assets/products/dress.png - - packages/flutter_gallery_assets/products/earrings.png - - packages/flutter_gallery_assets/products/flatwear.png - - packages/flutter_gallery_assets/products/hat.png - - packages/flutter_gallery_assets/products/jacket.png - - packages/flutter_gallery_assets/products/jumper.png - - packages/flutter_gallery_assets/products/kitchen_quattro.png - - packages/flutter_gallery_assets/products/napkins.png - - packages/flutter_gallery_assets/products/planters.png - - packages/flutter_gallery_assets/products/platter.png - - packages/flutter_gallery_assets/products/scarf.png - - packages/flutter_gallery_assets/products/shirt.png - - packages/flutter_gallery_assets/products/sunnies.png - - packages/flutter_gallery_assets/products/sweater.png - - packages/flutter_gallery_assets/products/sweats.png - - packages/flutter_gallery_assets/products/table.png - - packages/flutter_gallery_assets/products/teaset.png - - packages/flutter_gallery_assets/products/top.png - - packages/flutter_gallery_assets/people/ali.png - - packages/flutter_gallery_assets/people/square/ali.png - - packages/flutter_gallery_assets/people/square/peter.png - - packages/flutter_gallery_assets/people/square/sandra.png - - packages/flutter_gallery_assets/people/square/stella.png - - packages/flutter_gallery_assets/people/square/trevor.png - - packages/shrine_images/diamond.png - - packages/shrine_images/slanted_menu.png - - packages/shrine_images/0-0.jpg - - packages/shrine_images/1-0.jpg - - packages/shrine_images/2-0.jpg - - packages/shrine_images/3-0.jpg - - packages/shrine_images/4-0.jpg - - packages/shrine_images/5-0.jpg - - packages/shrine_images/6-0.jpg - - packages/shrine_images/7-0.jpg - - packages/shrine_images/8-0.jpg - - packages/shrine_images/9-0.jpg - - packages/shrine_images/10-0.jpg - - packages/shrine_images/11-0.jpg - - packages/shrine_images/12-0.jpg - - packages/shrine_images/13-0.jpg - - packages/shrine_images/14-0.jpg - - packages/shrine_images/15-0.jpg - - packages/shrine_images/16-0.jpg - - packages/shrine_images/17-0.jpg - - packages/shrine_images/18-0.jpg - - packages/shrine_images/19-0.jpg - - packages/shrine_images/20-0.jpg - - packages/shrine_images/21-0.jpg - - packages/shrine_images/22-0.jpg - - packages/shrine_images/23-0.jpg - - packages/shrine_images/24-0.jpg - - packages/shrine_images/25-0.jpg - - packages/shrine_images/26-0.jpg - - packages/shrine_images/27-0.jpg - - packages/shrine_images/28-0.jpg - - packages/shrine_images/29-0.jpg - - packages/shrine_images/30-0.jpg - - packages/shrine_images/31-0.jpg - - packages/shrine_images/32-0.jpg - - packages/shrine_images/33-0.jpg - - packages/shrine_images/34-0.jpg - - packages/shrine_images/35-0.jpg - - packages/shrine_images/36-0.jpg - - packages/shrine_images/37-0.jpg - - fonts: - - family: Raleway - fonts: - - asset: packages/flutter_gallery_assets/fonts/raleway/Raleway-Regular.ttf - - asset: packages/flutter_gallery_assets/fonts/raleway/Raleway-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/raleway/Raleway-SemiBold.ttf - weight: 600 - - family: AbrilFatface - fonts: - - asset: packages/flutter_gallery_assets/fonts/abrilfatface/AbrilFatface-Regular.ttf - - family: GalleryIcons - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/gallery_icons/GalleryIcons.ttf - - family: GoogleSans - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-MediumItalic.ttf - weight: 500 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Regular.ttf - weight: 400 - - family: GoogleSansDisplay - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-MediumItalic.ttf - style: italic - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Regular.ttf - weight: 400 - - family: LibreFranklin - fonts: - - asset: packages/flutter_gallery_assets/fonts/librefranklin/LibreFranklin-Bold.ttf - - asset: packages/flutter_gallery_assets/fonts/librefranklin/LibreFranklin-Light.ttf - - asset: packages/flutter_gallery_assets/fonts/librefranklin/LibreFranklin-Medium.ttf - - asset: packages/flutter_gallery_assets/fonts/librefranklin/LibreFranklin-Regular.ttf - - family: Merriweather - fonts: - - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-BlackItalic.ttf - - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Italic.ttf - - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf - # Work around missing Cupertino fonts by using GoogleSans instead. - - family: .SF Pro Text - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-MediumItalic.ttf - weight: 500 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Regular.ttf - weight: 400 - - family: .SF Pro Display - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-MediumItalic.ttf - style: italic - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Regular.ttf - weight: 400 - - family: .SF UI Text - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-MediumItalic.ttf - weight: 500 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSans-Regular.ttf - weight: 400 - - family: .SF UI Display - fonts: - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-BoldItalic.ttf - weight: 700 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Bold.ttf - weight: 700 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Italic.ttf - weight: 400 - style: italic - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-MediumItalic.ttf - style: italic - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Medium.ttf - weight: 500 - - asset: packages/flutter_gallery_assets/fonts/private/googlesans/GoogleSansDisplay-Regular.ttf - weight: 400 - -# PUBSPEC CHECKSUM: 1e1b diff --git a/web/gallery/web/index.html b/web/gallery/web/index.html deleted file mode 100644 index ba232943d..000000000 --- a/web/gallery/web/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Flutter Gallery - - - - - \ No newline at end of file