Unverified Commit 2d4f5a65 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[devicelab] introduce new old gallery. (#143486)

Fixes https://github.com/flutter/flutter/issues/143482

This brings in the gallery more or less as is:

* Removed localizations
* Ensure tests still run (locally verified, will switch CI later).
* Removed deferred components
* Fixup pubspec
parent c530276f
# Flutter Gallery
**NOTE**: The Flutter Gallery is now deprecated, and no longer being active maintained.
Flutter Gallery was a resource to help developers evaluate and use Flutter.
It is now being used primarily for testing. For posterity, the web version
remains [hosted here](https://flutter-gallery-archive.web.app).
We recommend Flutter developers check out the following resources:
* **Wonderous**
([web demo](https://wonderous.app/web/),
[App Store](https://apps.apple.com/us/app/wonderous/id1612491897),
[Google Play](https://play.google.com/store/apps/details?id=com.gskinner.flutter.wonders),
[source code](https://github.com/gskinnerTeam/flutter-wonderous-app)):<br>
A Flutter app that showcases Flutter's support for elegant design and rich animations.
* **Material 3 Demo**
([web demo](https://flutter.github.io/samples/web/material_3_demo/),
[source code](https://github.com/flutter/samples/tree/main/material_3_demo)):<br>
A Flutter app that showcases Material 3 features in the Flutter Material library.
* **Flutter Samples**
([samples](https://flutter.github.io/samples), [source code](https://github.com/flutter/samples)):<br>
A collection of open source samples that illustrate best practices for Flutter.
* **Widget catalogs**
([Material](https://docs.flutter.dev/ui/widgets/material), [Cupertino](https://docs.flutter.dev/ui/widgets/cupertino)):<br>
Catalogs for Material, Cupertino, and other widgets available for use in UI.
// Copyright 2014 The Flutter 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';
typedef CodeDisplayer = TextSpan Function(BuildContext context);
// Copyright 2014 The Flutter 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 CodeStyle extends InheritedWidget {
const CodeStyle({
super.key,
this.baseStyle,
this.numberStyle,
this.commentStyle,
this.keywordStyle,
this.stringStyle,
this.punctuationStyle,
this.classStyle,
this.constantStyle,
required super.child,
});
final TextStyle? baseStyle;
final TextStyle? numberStyle;
final TextStyle? commentStyle;
final TextStyle? keywordStyle;
final TextStyle? stringStyle;
final TextStyle? punctuationStyle;
final TextStyle? classStyle;
final TextStyle? constantStyle;
static CodeStyle of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CodeStyle>()!;
}
@override
bool updateShouldNotify(CodeStyle oldWidget) =>
oldWidget.baseStyle != baseStyle ||
oldWidget.numberStyle != numberStyle ||
oldWidget.commentStyle != commentStyle ||
oldWidget.keywordStyle != keywordStyle ||
oldWidget.stringStyle != stringStyle ||
oldWidget.punctuationStyle != punctuationStyle ||
oldWidget.classStyle != classStyle ||
oldWidget.constantStyle != constantStyle;
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Only put constants shared between files here.
import 'dart:typed_data';
// Height of the 'Gallery' header
const double galleryHeaderHeight = 64;
// The font size delta for headline4 font.
const double desktopDisplay1FontDelta = 16;
// The width of the settingsDesktop.
const double desktopSettingsWidth = 520;
// Sentinel value for the system text scale factor option.
const double systemTextScaleFactorOption = -1;
// The splash page animation duration.
const Duration splashPageAnimationDuration = Duration(milliseconds: 300);
// Half the splash page animation duration.
const Duration halfSplashPageAnimationDuration = Duration(milliseconds: 150);
// Duration for settings panel to open on mobile.
const Duration settingsPanelMobileAnimationDuration =
Duration(milliseconds: 200);
// Duration for settings panel to open on desktop.
const Duration settingsPanelDesktopAnimationDuration =
Duration(milliseconds: 600);
// Duration for home page elements to fade in.
const Duration entranceAnimationDuration = Duration(milliseconds: 200);
// The desktop top padding for a page's first header (e.g. Gallery, Settings)
const double firstHeaderDesktopTopPadding = 5.0;
// A transparent image used to avoid loading images when they are not needed.
final Uint8List kTransparentImage = Uint8List.fromList(<int>[
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B,
0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, 0xBD, 0xA7, 0x93, 0x00,
0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00,
0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49,
0x4D, 0x45, 0x07, 0xE6, 0x03, 0x10, 0x17, 0x07, 0x1D, 0x2E, 0x5E, 0x30, 0x9B,
0x00, 0x00, 0x00, 0x0B, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0x60, 0x00,
0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0xE2, 0x26, 0x05, 0x9B, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
]);
This diff is collapsed.
// Copyright 2014 The Flutter 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/scheduler.dart' show timeDilation;
import 'package:flutter/services.dart' show SystemUiOverlayStyle;
import '../constants.dart';
enum CustomTextDirection {
localeBased,
ltr,
rtl,
}
// See http://en.wikipedia.org/wiki/Right-to-left
const List<String> rtlLanguages = <String>[
'ar', // Arabic
'fa', // Farsi
'he', // Hebrew
'ps', // Pashto
'ur', // Urdu
];
// Fake locale to represent the system Locale option.
const Locale systemLocaleOption = Locale('system');
Locale? _deviceLocale;
Locale? get deviceLocale => _deviceLocale;
set deviceLocale(Locale? locale) {
_deviceLocale ??= locale;
}
@immutable
class GalleryOptions {
const GalleryOptions({
required this.themeMode,
required double? textScaleFactor,
required this.customTextDirection,
required Locale? locale,
required this.timeDilation,
required this.platform,
required this.isTestMode,
}) : _textScaleFactor = textScaleFactor ?? 1.0,
_locale = locale;
final ThemeMode themeMode;
final double _textScaleFactor;
final CustomTextDirection customTextDirection;
final Locale? _locale;
final double timeDilation;
final TargetPlatform? platform;
final bool isTestMode; // True for integration tests.
// We use a sentinel value to indicate the system text scale option. By
// default, return the actual text scale factor, otherwise return the
// sentinel value.
double textScaleFactor(BuildContext context, {bool useSentinel = false}) {
if (_textScaleFactor == systemTextScaleFactorOption) {
return useSentinel
? systemTextScaleFactorOption
// ignore: deprecated_member_use
: MediaQuery.of(context).textScaleFactor;
} else {
return _textScaleFactor;
}
}
Locale? get locale => _locale ?? deviceLocale;
/// Returns a text direction based on the [CustomTextDirection] setting.
/// If it is based on locale and the locale cannot be determined, returns
/// null.
TextDirection? resolvedTextDirection() {
switch (customTextDirection) {
case CustomTextDirection.localeBased:
final String? language = locale?.languageCode.toLowerCase();
if (language == null) {
return null;
}
return rtlLanguages.contains(language)
? TextDirection.rtl
: TextDirection.ltr;
case CustomTextDirection.rtl:
return TextDirection.rtl;
case CustomTextDirection.ltr:
return TextDirection.ltr;
}
}
/// Returns a [SystemUiOverlayStyle] based on the [ThemeMode] setting.
/// In other words, if the theme is dark, returns light; if the theme is
/// light, returns dark.
SystemUiOverlayStyle resolvedSystemUiOverlayStyle() {
Brightness brightness;
switch (themeMode) {
case ThemeMode.light:
brightness = Brightness.light;
case ThemeMode.dark:
brightness = Brightness.dark;
case ThemeMode.system:
brightness =
WidgetsBinding.instance.platformDispatcher.platformBrightness;
}
final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark
? SystemUiOverlayStyle.light
: SystemUiOverlayStyle.dark;
return overlayStyle;
}
GalleryOptions copyWith({
ThemeMode? themeMode,
double? textScaleFactor,
CustomTextDirection? customTextDirection,
Locale? locale,
double? timeDilation,
TargetPlatform? platform,
bool? isTestMode,
}) {
return GalleryOptions(
themeMode: themeMode ?? this.themeMode,
textScaleFactor: textScaleFactor ?? _textScaleFactor,
customTextDirection: customTextDirection ?? this.customTextDirection,
locale: locale ?? this.locale,
timeDilation: timeDilation ?? this.timeDilation,
platform: platform ?? this.platform,
isTestMode: isTestMode ?? this.isTestMode,
);
}
@override
bool operator ==(Object other) =>
other is GalleryOptions &&
themeMode == other.themeMode &&
_textScaleFactor == other._textScaleFactor &&
customTextDirection == other.customTextDirection &&
locale == other.locale &&
timeDilation == other.timeDilation &&
platform == other.platform &&
isTestMode == other.isTestMode;
@override
int get hashCode => Object.hash(
themeMode,
_textScaleFactor,
customTextDirection,
locale,
timeDilation,
platform,
isTestMode,
);
static GalleryOptions of(BuildContext context) {
final _ModelBindingScope scope =
context.dependOnInheritedWidgetOfExactType<_ModelBindingScope>()!;
return scope.modelBindingState.currentModel;
}
static void update(BuildContext context, GalleryOptions newModel) {
final _ModelBindingScope scope =
context.dependOnInheritedWidgetOfExactType<_ModelBindingScope>()!;
scope.modelBindingState.updateModel(newModel);
}
}
// Applies text GalleryOptions to a widget
class ApplyTextOptions extends StatelessWidget {
const ApplyTextOptions({
super.key,
required this.child,
});
final Widget child;
@override
Widget build(BuildContext context) {
final GalleryOptions options = GalleryOptions.of(context);
final TextDirection? textDirection = options.resolvedTextDirection();
final double textScaleFactor = options.textScaleFactor(context);
final Widget widget = MediaQuery(
data: MediaQuery.of(context).copyWith(
// ignore: deprecated_member_use
textScaleFactor: textScaleFactor,
),
child: child,
);
return textDirection == null
? widget
: Directionality(
textDirection: textDirection,
child: widget,
);
}
}
// Everything below is boilerplate except code relating to time dilation.
// See https://medium.com/flutter/managing-flutter-application-state-with-inheritedwidgets-1140452befe1
class _ModelBindingScope extends InheritedWidget {
const _ModelBindingScope({
required this.modelBindingState,
required super.child,
});
final _ModelBindingState modelBindingState;
@override
bool updateShouldNotify(_ModelBindingScope oldWidget) => true;
}
class ModelBinding extends StatefulWidget {
const ModelBinding({
super.key,
required this.initialModel,
required this.child,
});
final GalleryOptions initialModel;
final Widget child;
@override
State<ModelBinding> createState() => _ModelBindingState();
}
class _ModelBindingState extends State<ModelBinding> {
late GalleryOptions currentModel;
Timer? _timeDilationTimer;
@override
void initState() {
super.initState();
currentModel = widget.initialModel;
}
@override
void dispose() {
_timeDilationTimer?.cancel();
_timeDilationTimer = null;
super.dispose();
}
void handleTimeDilation(GalleryOptions newModel) {
if (currentModel.timeDilation != newModel.timeDilation) {
_timeDilationTimer?.cancel();
_timeDilationTimer = null;
if (newModel.timeDilation > 1) {
// 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 = newModel.timeDilation;
});
} else {
timeDilation = newModel.timeDilation;
}
}
}
void updateModel(GalleryOptions newModel) {
if (newModel != currentModel) {
handleTimeDilation(newModel);
setState(() {
currentModel = newModel;
});
}
}
@override
Widget build(BuildContext context) {
return _ModelBindingScope(
modelBindingState: this,
child: widget.child,
);
}
}
// Copyright 2014 The Flutter 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 textFieldsAlt = 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 sentimentVerySatisfied = IconData(
0xe906,
fontFamily: 'GalleryIcons',
);
static const IconData refresh = IconData(
0xe907,
fontFamily: 'GalleryIcons',
);
static const IconData progressActivity = IconData(
0xe908,
fontFamily: 'GalleryIcons',
);
static const IconData phoneIphone = IconData(
0xe909,
fontFamily: 'GalleryIcons',
);
static const IconData pageControl = IconData(
0xe90a,
fontFamily: 'GalleryIcons',
);
static const IconData moreVert = IconData(
0xe90b,
fontFamily: 'GalleryIcons',
);
static const IconData menu = IconData(
0xe90c,
fontFamily: 'GalleryIcons',
);
static const IconData listAlt = IconData(
0xe90d,
fontFamily: 'GalleryIcons',
);
static const IconData gridOn = IconData(
0xe90e,
fontFamily: 'GalleryIcons',
);
static const IconData expandAll = IconData(
0xe90f,
fontFamily: 'GalleryIcons',
);
static const IconData event = IconData(
0xe910,
fontFamily: 'GalleryIcons',
);
static const IconData driveVideo = IconData(
0xe911,
fontFamily: 'GalleryIcons',
);
static const IconData dialogs = IconData(
0xe912,
fontFamily: 'GalleryIcons',
);
static const IconData dataTable = IconData(
0xe913,
fontFamily: 'GalleryIcons',
);
static const IconData customTypography = IconData(
0xe914,
fontFamily: 'GalleryIcons',
);
static const IconData colors = IconData(
0xe915,
fontFamily: 'GalleryIcons',
);
static const IconData chips = IconData(
0xe916,
fontFamily: 'GalleryIcons',
);
static const IconData checkBox = IconData(
0xe917,
fontFamily: 'GalleryIcons',
);
static const IconData cards = IconData(
0xe918,
fontFamily: 'GalleryIcons',
);
static const IconData buttons = IconData(
0xe919,
fontFamily: 'GalleryIcons',
);
static const IconData bottomSheets = IconData(
0xe91a,
fontFamily: 'GalleryIcons',
);
static const IconData bottomNavigation = IconData(
0xe91b,
fontFamily: 'GalleryIcons',
);
static const IconData animation = IconData(
0xe91c,
fontFamily: 'GalleryIcons',
);
static const IconData accountBox = IconData(
0xe91d,
fontFamily: 'GalleryIcons',
);
static const IconData snackbar = IconData(
0xe91e,
fontFamily: 'GalleryIcons',
);
static const IconData categoryMdc = IconData(
0xe91f,
fontFamily: 'GalleryIcons',
);
static const IconData cupertinoProgress = IconData(
0xe920,
fontFamily: 'GalleryIcons',
);
static const IconData cupertinoPullToRefresh = IconData(
0xe921,
fontFamily: 'GalleryIcons',
);
static const IconData cupertinoSwitch = IconData(
0xe922,
fontFamily: 'GalleryIcons',
);
static const IconData genericButtons = IconData(
0xe923,
fontFamily: 'GalleryIcons',
);
static const IconData backdrop = IconData(
0xe924,
fontFamily: 'GalleryIcons',
);
static const IconData bottomAppBar = IconData(
0xe925,
fontFamily: 'GalleryIcons',
);
static const IconData bottomSheetPersistent = IconData(
0xe926,
fontFamily: 'GalleryIcons',
);
static const IconData listsLeaveBehind = IconData(
0xe927,
fontFamily: 'GalleryIcons',
);
static const IconData navigationRail = Icons.vertical_split;
static const IconData appbar = Icons.web_asset;
static const IconData divider = Icons.credit_card;
static const IconData search = Icons.search;
}
// Copyright 2014 The Flutter 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';
typedef LibraryLoader = Future<void> Function();
typedef DeferredWidgetBuilder = Widget Function();
/// Wraps the child inside a deferred module loader.
///
/// The child is created and a single instance of the Widget is maintained in
/// state as long as closure to create widget stays the same.
///
class DeferredWidget extends StatefulWidget {
DeferredWidget(
this.libraryLoader,
this.createWidget, {
super.key,
Widget? placeholder,
}) : placeholder = placeholder ?? Container();
final LibraryLoader libraryLoader;
final DeferredWidgetBuilder createWidget;
final Widget placeholder;
static final Map<LibraryLoader, Future<void>> _moduleLoaders = <LibraryLoader, Future<void>>{};
static final Set<LibraryLoader> _loadedModules = <LibraryLoader>{};
static Future<void> preload(LibraryLoader loader) {
if (!_moduleLoaders.containsKey(loader)) {
_moduleLoaders[loader] = loader().then((dynamic _) {
_loadedModules.add(loader);
});
}
return _moduleLoaders[loader]!;
}
@override
State<DeferredWidget> createState() => _DeferredWidgetState();
}
class _DeferredWidgetState extends State<DeferredWidget> {
_DeferredWidgetState();
Widget? _loadedChild;
DeferredWidgetBuilder? _loadedCreator;
@override
void initState() {
/// If module was already loaded immediately create widget instead of
/// waiting for future or zone turn.
if (DeferredWidget._loadedModules.contains(widget.libraryLoader)) {
_onLibraryLoaded();
} else {
DeferredWidget.preload(widget.libraryLoader)
.then((dynamic _) => _onLibraryLoaded());
}
super.initState();
}
void _onLibraryLoaded() {
setState(() {
_loadedCreator = widget.createWidget;
_loadedChild = _loadedCreator!();
});
}
@override
Widget build(BuildContext context) {
/// If closure to create widget changed, create new instance, otherwise
/// treat as const Widget.
if (_loadedCreator != widget.createWidget && _loadedCreator != null) {
_loadedCreator = widget.createWidget;
_loadedChild = _loadedCreator!();
}
return _loadedChild ?? widget.placeholder;
}
}
/// Displays a progress indicator and text description explaining that
/// the widget is a deferred component and is currently being installed.
class DeferredLoadingPlaceholder extends StatelessWidget {
const DeferredLoadingPlaceholder({
super.key,
this.name = 'This widget',
});
final String name;
@override
Widget build(BuildContext context) {
return Center(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[700],
border: Border.all(
width: 20,
color: Colors.grey[700]!,
),
borderRadius: const BorderRadius.all(Radius.circular(10))),
width: 250,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('$name is installing.',
style: Theme.of(context).textTheme.headlineMedium),
Container(height: 10),
Text(
'$name is a deferred component which are downloaded and installed at runtime.',
style: Theme.of(context).textTheme.bodyLarge),
Container(height: 20),
const Center(child: CircularProgressIndicator()),
],
),
),
);
}
}
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoActivityIndicatorDemo
class CupertinoProgressIndicatorDemo extends StatelessWidget {
const CupertinoProgressIndicatorDemo({super.key});
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(
GalleryLocalizations.of(context)!.demoCupertinoActivityIndicatorTitle,
),
),
child: const Center(
child: CupertinoActivityIndicator(),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoButtonDemo
class CupertinoButtonDemo extends StatelessWidget {
const CupertinoButtonDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(localizations.demoCupertinoButtonsTitle),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton(
onPressed: () {},
child: Text(
localizations.cupertinoButton,
),
),
const SizedBox(height: 16),
CupertinoButton.filled(
onPressed: () {},
child: Text(
localizations.cupertinoButtonWithBackground,
),
),
const SizedBox(height: 30),
// Disabled buttons
CupertinoButton(
onPressed: null,
child: Text(
localizations.cupertinoButton,
),
),
const SizedBox(height: 16),
CupertinoButton.filled(
onPressed: null,
child: Text(
localizations.cupertinoButtonWithBackground,
),
),
],
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoContextMenuDemo
class CupertinoContextMenuDemo extends StatelessWidget {
const CupertinoContextMenuDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations galleryLocalizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(
galleryLocalizations.demoCupertinoContextMenuTitle,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: SizedBox(
width: 100,
height: 100,
child: CupertinoContextMenu(
actions: <Widget>[
CupertinoContextMenuAction(
onPressed: () {
Navigator.pop(context);
},
child: Text(
galleryLocalizations.demoCupertinoContextMenuActionOne,
),
),
CupertinoContextMenuAction(
onPressed: () {
Navigator.pop(context);
},
child: Text(
galleryLocalizations.demoCupertinoContextMenuActionTwo,
),
),
],
child: const FlutterLogo(size: 250),
),
),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.all(30),
child: Text(
galleryLocalizations.demoCupertinoContextMenuActionText,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.black,
),
),
),
],
),
);
}
}
// END
// Copyright 2014 The Flutter 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 'package:gallery/demos/cupertino/cupertino_activity_indicator_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_alert_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_button_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_context_menu_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_navigation_bar_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_picker_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_scrollbar_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_search_text_field_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_segmented_control_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_slider_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_switch_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_tab_bar_demo.dart';
export 'package:gallery/demos/cupertino/cupertino_text_field_demo.dart';
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoNavigationBarDemo
class CupertinoNavigationBarDemo extends StatelessWidget {
const CupertinoNavigationBarDemo({super.key});
static const String homeRoute = '/home';
static const String secondPageRoute = '/home/item';
@override
Widget build(BuildContext context) {
return Navigator(
restorationScopeId: 'navigator',
initialRoute: CupertinoNavigationBarDemo.homeRoute,
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case CupertinoNavigationBarDemo.homeRoute:
return _NoAnimationCupertinoPageRoute<void>(
title: GalleryLocalizations.of(context)!
.demoCupertinoNavigationBarTitle,
settings: settings,
builder: (BuildContext context) => _FirstPage(),
);
case CupertinoNavigationBarDemo.secondPageRoute:
final Map<dynamic, dynamic> arguments = settings.arguments! as Map<dynamic, dynamic>;
final String? title = arguments['pageTitle'] as String?;
return CupertinoPageRoute<void>(
title: title,
settings: settings,
builder: (BuildContext context) => _SecondPage(),
);
}
return null;
},
);
}
}
class _FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: CustomScrollView(
slivers: <Widget>[
const CupertinoSliverNavigationBar(
automaticallyImplyLeading: false,
),
SliverPadding(
padding:
MediaQuery.of(context).removePadding(removeTop: true).padding,
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final String title = GalleryLocalizations.of(context)!
.starterAppDrawerItem(index + 1);
return ListTile(
onTap: () {
Navigator.of(context).restorablePushNamed<void>(
CupertinoNavigationBarDemo.secondPageRoute,
arguments: <String, String>{'pageTitle': title},
);
},
title: Text(title),
);
},
childCount: 20,
),
),
),
],
),
);
}
}
class _SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(),
child: Container(),
);
}
}
/// A CupertinoPageRoute without any transition animations.
class _NoAnimationCupertinoPageRoute<T> extends CupertinoPageRoute<T> {
_NoAnimationCupertinoPageRoute({
required super.builder,
super.settings,
super.title,
});
@override
Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return child;
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoPickersDemo
class CupertinoPickerDemo extends StatefulWidget {
const CupertinoPickerDemo({super.key});
@override
State<CupertinoPickerDemo> createState() => _CupertinoPickerDemoState();
}
class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
Duration timer = Duration.zero;
// 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();
int _selectedWeekday = 0;
static List<String> getDaysOfWeek([String? locale]) {
final DateTime now = DateTime.now();
final DateTime firstDayOfWeek = now.subtract(Duration(days: now.weekday - 1));
return List<int>.generate(7, (int index) => index)
.map((int value) => DateFormat(DateFormat.WEEKDAY, locale)
.format(firstDayOfWeek.add(Duration(days: value))))
.toList();
}
void _showDemoPicker({
required BuildContext context,
required Widget child,
}) {
final CupertinoThemeData themeData = CupertinoTheme.of(context);
final CupertinoTheme dialogBody = CupertinoTheme(
data: themeData,
child: child,
);
showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => dialogBody,
);
}
Widget _buildDatePicker(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showDemoPicker(
context: context,
child: _BottomPicker(
child: CupertinoDatePicker(
backgroundColor:
CupertinoColors.systemBackground.resolveFrom(context),
mode: CupertinoDatePickerMode.date,
initialDateTime: date,
onDateTimeChanged: (DateTime newDateTime) {
setState(() => date = newDateTime);
},
),
),
);
},
child: _Menu(
children: <Widget>[
Text(GalleryLocalizations.of(context)!.demoCupertinoPickerDate),
Text(
DateFormat.yMMMMd().format(date),
style: const TextStyle(color: CupertinoColors.inactiveGray),
),
],
),
),
);
}
Widget _buildTimePicker(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showDemoPicker(
context: context,
child: _BottomPicker(
child: CupertinoDatePicker(
backgroundColor:
CupertinoColors.systemBackground.resolveFrom(context),
mode: CupertinoDatePickerMode.time,
initialDateTime: time,
onDateTimeChanged: (DateTime newDateTime) {
setState(() => time = newDateTime);
},
),
),
);
},
child: _Menu(
children: <Widget>[
Text(GalleryLocalizations.of(context)!.demoCupertinoPickerTime),
Text(
DateFormat.jm().format(time),
style: const TextStyle(color: CupertinoColors.inactiveGray),
),
],
),
),
);
}
Widget _buildDateAndTimePicker(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showDemoPicker(
context: context,
child: _BottomPicker(
child: CupertinoDatePicker(
backgroundColor:
CupertinoColors.systemBackground.resolveFrom(context),
initialDateTime: dateTime,
onDateTimeChanged: (DateTime newDateTime) {
setState(() => dateTime = newDateTime);
},
),
),
);
},
child: _Menu(
children: <Widget>[
Text(GalleryLocalizations.of(context)!.demoCupertinoPickerDateTime),
Flexible(
child: Text(
DateFormat.yMMMd().add_jm().format(dateTime),
style: const TextStyle(color: CupertinoColors.inactiveGray),
),
),
],
),
),
);
}
Widget _buildCountdownTimerPicker(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showDemoPicker(
context: context,
child: _BottomPicker(
child: CupertinoTimerPicker(
backgroundColor:
CupertinoColors.systemBackground.resolveFrom(context),
initialTimerDuration: timer,
onTimerDurationChanged: (Duration newTimer) {
setState(() => timer = newTimer);
},
),
),
);
},
child: _Menu(
children: <Widget>[
Text(GalleryLocalizations.of(context)!.demoCupertinoPickerTimer),
Text(
'${timer.inHours}:'
'${(timer.inMinutes % 60).toString().padLeft(2, '0')}:'
'${(timer.inSeconds % 60).toString().padLeft(2, '0')}',
style: const TextStyle(color: CupertinoColors.inactiveGray),
),
],
),
),
);
}
Widget _buildPicker(BuildContext context) {
final String? locale = GalleryLocalizations.of(context)?.localeName;
final List<String> daysOfWeek = getDaysOfWeek(locale);
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showDemoPicker(
context: context,
child: _BottomPicker(
child: CupertinoPicker(
backgroundColor:
CupertinoColors.systemBackground.resolveFrom(context),
itemExtent: 32.0,
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
// This is called when selected item is changed.
onSelectedItemChanged: (int selectedItem) {
setState(() {
_selectedWeekday = selectedItem;
});
},
children: List<Widget>.generate(daysOfWeek.length, (int index) {
return Center(
child: Text(
daysOfWeek[index],
),
);
}),
),
),
);
},
child: _Menu(
children: <Widget>[
Text(GalleryLocalizations.of(context)!.demoCupertinoPicker),
Text(
daysOfWeek[_selectedWeekday],
style: const TextStyle(color: CupertinoColors.inactiveGray),
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle:
Text(GalleryLocalizations.of(context)!.demoCupertinoPickerTitle),
),
child: DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: ListView(
children: <Widget>[
const SizedBox(height: 32),
_buildDatePicker(context),
_buildTimePicker(context),
_buildDateAndTimePicker(context),
_buildCountdownTimerPicker(context),
_buildPicker(context),
],
),
),
);
}
}
class _BottomPicker extends StatelessWidget {
const _BottomPicker({required this.child});
final Widget child;
@override
Widget build(BuildContext context) {
return Container(
height: 216,
padding: const EdgeInsets.only(top: 6),
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
color: CupertinoColors.systemBackground.resolveFrom(context),
child: DefaultTextStyle(
style: TextStyle(
color: CupertinoColors.label.resolveFrom(context),
fontSize: 22,
),
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({required this.children});
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(color: CupertinoColors.inactiveGray, width: 0),
bottom: BorderSide(color: CupertinoColors.inactiveGray, width: 0),
),
),
height: 44,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: children,
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoScrollbarDemo
class CupertinoScrollbarDemo extends StatelessWidget {
const CupertinoScrollbarDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(localizations.demoCupertinoScrollbarTitle),
),
child: CupertinoScrollbar(
thickness: 6.0,
thicknessWhileDragging: 10.0,
radius: const Radius.circular(34.0),
radiusWhileDragging: Radius.zero,
child: ListView.builder(
itemCount: 120,
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text('item $index',
style: CupertinoTheme.of(context).textTheme.textStyle),
);
},
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoSearchTextFieldDemo
class CupertinoSearchTextFieldDemo extends StatefulWidget {
const CupertinoSearchTextFieldDemo({super.key});
@override
State<CupertinoSearchTextFieldDemo> createState() =>
_CupertinoSearchTextFieldDemoState();
}
class _CupertinoSearchTextFieldDemoState
extends State<CupertinoSearchTextFieldDemo> {
final List<String> platforms = <String>[
'Android',
'iOS',
'Windows',
'Linux',
'MacOS',
'Web'
];
final TextEditingController _queryTextController = TextEditingController();
String _searchPlatform = '';
List<String> filteredPlatforms = <String>[];
@override
void initState() {
super.initState();
filteredPlatforms = platforms;
_queryTextController.addListener(() {
if (_queryTextController.text.isEmpty) {
setState(() {
_searchPlatform = '';
filteredPlatforms = platforms;
});
} else {
setState(() {
_searchPlatform = _queryTextController.text;
});
}
});
}
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(localizations.demoCupertinoSearchTextFieldTitle),
),
child: SafeArea(
child: Column(
children: <Widget>[
CupertinoSearchTextField(
controller: _queryTextController,
restorationId: 'search_text_field',
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 12),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0,
color: CupertinoColors.inactiveGray,
),
),
),
placeholder:
localizations.demoCupertinoSearchTextFieldPlaceholder,
),
_buildPlatformList(),
],
),
),
);
}
Widget _buildPlatformList() {
if (_searchPlatform.isNotEmpty) {
final List<String> tempList = <String>[];
for (int i = 0; i < filteredPlatforms.length; i++) {
if (filteredPlatforms[i]
.toLowerCase()
.contains(_searchPlatform.toLowerCase())) {
tempList.add(filteredPlatforms[i]);
}
}
filteredPlatforms = tempList;
}
return ListView.builder(
itemCount: filteredPlatforms.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text(filteredPlatforms[index]));
},
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoSegmentedControlDemo
class CupertinoSegmentedControlDemo extends StatefulWidget {
const CupertinoSegmentedControlDemo({super.key});
@override
State<CupertinoSegmentedControlDemo> createState() =>
_CupertinoSegmentedControlDemoState();
}
class _CupertinoSegmentedControlDemoState
extends State<CupertinoSegmentedControlDemo> with RestorationMixin {
RestorableInt currentSegment = RestorableInt(0);
@override
String get restorationId => 'cupertino_segmented_control';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(currentSegment, 'current_segment');
}
void onValueChanged(int? newValue) {
setState(() {
currentSegment.value = newValue!;
});
}
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
const double segmentedControlMaxWidth = 500.0;
final Map<int, Widget> children = <int, Widget>{
0: Text(localizations.colorsIndigo),
1: Text(localizations.colorsTeal),
2: Text(localizations.colorsCyan),
};
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(
localizations.demoCupertinoSegmentedControlTitle,
),
),
child: DefaultTextStyle(
style: CupertinoTheme.of(context)
.textTheme
.textStyle
.copyWith(fontSize: 13),
child: SafeArea(
child: ListView(
children: <Widget>[
const SizedBox(height: 16),
SizedBox(
width: segmentedControlMaxWidth,
child: CupertinoSegmentedControl<int>(
children: children,
onValueChanged: onValueChanged,
groupValue: currentSegment.value,
),
),
SizedBox(
width: segmentedControlMaxWidth,
child: Padding(
padding: const EdgeInsets.all(16),
child: CupertinoSlidingSegmentedControl<int>(
children: children,
onValueChanged: onValueChanged,
groupValue: currentSegment.value,
),
),
),
Container(
padding: const EdgeInsets.all(16),
height: 300,
alignment: Alignment.center,
child: children[currentSegment.value],
),
],
),
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoSliderDemo
class CupertinoSliderDemo extends StatefulWidget {
const CupertinoSliderDemo({super.key});
@override
State<CupertinoSliderDemo> createState() => _CupertinoSliderDemoState();
}
class _CupertinoSliderDemoState extends State<CupertinoSliderDemo>
with RestorationMixin {
final RestorableDouble _value = RestorableDouble(25.0);
final RestorableDouble _discreteValue = RestorableDouble(20.0);
@override
String get restorationId => 'cupertino_slider_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_value, 'value');
registerForRestoration(_discreteValue, 'discrete_value');
}
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(localizations.demoCupertinoSliderTitle),
),
child: DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: Center(
child: Wrap(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const SizedBox(height: 32),
CupertinoSlider(
value: _value.value,
max: 100.0,
onChanged: (double value) {
setState(() {
_value.value = value;
});
},
),
CupertinoSlider(
value: _value.value,
max: 100.0,
onChanged: null,
),
MergeSemantics(
child: Text(
localizations.demoCupertinoSliderContinuous(
_value.value.toStringAsFixed(1),
),
),
),
],
),
// Disabled sliders
// TODO(guidezpl): See https://github.com/flutter/flutter/issues/106691
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const SizedBox(height: 32),
CupertinoSlider(
value: _discreteValue.value,
max: 100.0,
divisions: 5,
onChanged: (double value) {
setState(() {
_discreteValue.value = value;
});
},
),
CupertinoSlider(
value: _discreteValue.value,
max: 100.0,
divisions: 5,
onChanged: null,
),
MergeSemantics(
child: Text(
localizations.demoCupertinoSliderDiscrete(
_discreteValue.value.toStringAsFixed(1),
),
),
),
],
),
],
),
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoSwitchDemo
class CupertinoSwitchDemo extends StatefulWidget {
const CupertinoSwitchDemo({super.key});
@override
State<CupertinoSwitchDemo> createState() => _CupertinoSwitchDemoState();
}
class _CupertinoSwitchDemoState extends State<CupertinoSwitchDemo>
with RestorationMixin {
final RestorableBool _switchValueA = RestorableBool(false);
final RestorableBool _switchValueB = RestorableBool(true);
@override
String get restorationId => 'cupertino_switch_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_switchValueA, 'switch_valueA');
registerForRestoration(_switchValueB, 'switch_valueB');
}
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(
localizations.demoSelectionControlsSwitchTitle,
),
),
child: Center(
child: Semantics(
container: true,
label: localizations.demoSelectionControlsSwitchTitle,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoSwitch(
value: _switchValueA.value,
onChanged: (bool value) {
setState(() {
_switchValueA.value = value;
});
},
),
CupertinoSwitch(
value: _switchValueB.value,
onChanged: (bool value) {
setState(() {
_switchValueB.value = value;
});
},
),
],
),
// Disabled switches
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoSwitch(
value: _switchValueA.value,
onChanged: null,
),
CupertinoSwitch(
value: _switchValueB.value,
onChanged: null,
),
],
),
],
),
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoNavigationDemo
class _TabInfo {
const _TabInfo(this.title, this.icon);
final String title;
final IconData icon;
}
class CupertinoTabBarDemo extends StatelessWidget {
const CupertinoTabBarDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
final List<_TabInfo> tabInfo = <_TabInfo>[
_TabInfo(
localizations.cupertinoTabBarHomeTab,
CupertinoIcons.home,
),
_TabInfo(
localizations.cupertinoTabBarChatTab,
CupertinoIcons.conversation_bubble,
),
_TabInfo(
localizations.cupertinoTabBarProfileTab,
CupertinoIcons.profile_circled,
),
];
return DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: CupertinoTabScaffold(
restorationId: 'cupertino_tab_scaffold',
tabBar: CupertinoTabBar(
items: <BottomNavigationBarItem>[
for (final _TabInfo tabInfo in tabInfo)
BottomNavigationBarItem(
label: tabInfo.title,
icon: Icon(tabInfo.icon),
),
],
),
tabBuilder: (BuildContext context, int index) {
return CupertinoTabView(
restorationScopeId: 'cupertino_tab_view_$index',
builder: (BuildContext context) => _CupertinoDemoTab(
title: tabInfo[index].title,
icon: tabInfo[index].icon,
),
defaultTitle: tabInfo[index].title,
);
},
),
);
}
}
class _CupertinoDemoTab extends StatelessWidget {
const _CupertinoDemoTab({
required this.title,
required this.icon,
});
final String title;
final IconData icon;
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(),
backgroundColor: CupertinoColors.systemBackground,
child: Center(
child: Icon(
icon,
semanticLabel: title,
size: 100,
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN cupertinoTextFieldDemo
class CupertinoTextFieldDemo extends StatelessWidget {
const CupertinoTextFieldDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
automaticallyImplyLeading: false,
middle: Text(localizations.demoCupertinoTextFieldTitle),
),
child: SafeArea(
child: ListView(
restorationId: 'text_field_demo_list_view',
padding: const EdgeInsets.all(16),
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoTextField(
textInputAction: TextInputAction.next,
restorationId: 'email_address_text_field',
placeholder: localizations.demoTextFieldEmail,
keyboardType: TextInputType.emailAddress,
clearButtonMode: OverlayVisibilityMode.editing,
autocorrect: false,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoTextField(
textInputAction: TextInputAction.next,
restorationId: 'login_password_text_field',
placeholder: localizations.rallyLoginPassword,
clearButtonMode: OverlayVisibilityMode.editing,
obscureText: true,
autocorrect: false,
),
),
// Disabled text field
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoTextField(
enabled: false,
textInputAction: TextInputAction.next,
restorationId: 'login_password_text_field_disabled',
placeholder: localizations.rallyLoginPassword,
clearButtonMode: OverlayVisibilityMode.editing,
obscureText: true,
autocorrect: false,
),
),
CupertinoTextField(
textInputAction: TextInputAction.done,
restorationId: 'pin_number_text_field',
prefix: const Icon(
CupertinoIcons.padlock_solid,
size: 28,
),
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 12),
clearButtonMode: OverlayVisibilityMode.editing,
keyboardType: TextInputType.number,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0,
color: CupertinoColors.inactiveGray,
),
),
),
placeholder: localizations.demoCupertinoTextFieldPIN,
),
],
),
),
);
}
}
// END
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
enum AlertDemoType {
alert,
alertTitle,
alertButtons,
alertButtonsOnly,
actionSheet,
}
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN appbarDemo
class AppBarDemo extends StatelessWidget {
const AppBarDemo({super.key});
@override
Widget build(BuildContext context) {
final GalleryLocalizations localization = GalleryLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
leading: IconButton(
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: Text(
localization.demoAppBarTitle,
),
actions: <Widget>[
IconButton(
tooltip: localization.starterAppTooltipFavorite,
icon: const Icon(
Icons.favorite,
),
onPressed: () {},
),
IconButton(
tooltip: localization.starterAppTooltipSearch,
icon: const Icon(
Icons.search,
),
onPressed: () {},
),
PopupMenuButton<Text>(
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<Text>>[
PopupMenuItem<Text>(
child: Text(
localization.demoNavigationRailFirst,
),
),
PopupMenuItem<Text>(
child: Text(
localization.demoNavigationRailSecond,
),
),
PopupMenuItem<Text>(
child: Text(
localization.demoNavigationRailThird,
),
),
];
},
)
],
),
body: Center(
child: Text(
localization.cupertinoTabBarHomeTab,
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN bannerDemo
enum BannerDemoAction {
reset,
showMultipleActions,
showLeading,
}
class BannerDemo extends StatefulWidget {
const BannerDemo({super.key});
@override
State<BannerDemo> createState() => _BannerDemoState();
}
class _BannerDemoState extends State<BannerDemo> with RestorationMixin {
static const int _itemCount = 20;
@override
String get restorationId => 'banner_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_displayBanner, 'display_banner');
registerForRestoration(_showMultipleActions, 'show_multiple_actions');
registerForRestoration(_showLeading, 'show_leading');
}
final RestorableBool _displayBanner = RestorableBool(true);
final RestorableBool _showMultipleActions = RestorableBool(true);
final RestorableBool _showLeading = RestorableBool(true);
@override
void dispose() {
_displayBanner.dispose();
_showMultipleActions.dispose();
_showLeading.dispose();
super.dispose();
}
void handleDemoAction(BannerDemoAction action) {
setState(() {
switch (action) {
case BannerDemoAction.reset:
_displayBanner.value = true;
_showMultipleActions.value = true;
_showLeading.value = true;
case BannerDemoAction.showMultipleActions:
_showMultipleActions.value = !_showMultipleActions.value;
case BannerDemoAction.showLeading:
_showLeading.value = !_showLeading.value;
}
});
}
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
final MaterialBanner banner = MaterialBanner(
content: Text(localizations.bannerDemoText),
leading: _showLeading.value
? CircleAvatar(
backgroundColor: colorScheme.primary,
child: Icon(Icons.access_alarm, color: colorScheme.onPrimary),
)
: null,
actions: <Widget>[
TextButton(
onPressed: () {
setState(() {
_displayBanner.value = false;
});
},
child: Text(localizations.signIn),
),
if (_showMultipleActions.value)
TextButton(
onPressed: () {
setState(() {
_displayBanner.value = false;
});
},
child: Text(localizations.dismiss),
),
],
backgroundColor: colorScheme.background,
);
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(localizations.demoBannerTitle),
actions: <Widget>[
PopupMenuButton<BannerDemoAction>(
onSelected: handleDemoAction,
itemBuilder: (BuildContext context) => <PopupMenuEntry<BannerDemoAction>>[
PopupMenuItem<BannerDemoAction>(
value: BannerDemoAction.reset,
child: Text(localizations.bannerDemoResetText),
),
const PopupMenuDivider(),
CheckedPopupMenuItem<BannerDemoAction>(
value: BannerDemoAction.showMultipleActions,
checked: _showMultipleActions.value,
child: Text(localizations.bannerDemoMultipleText),
),
CheckedPopupMenuItem<BannerDemoAction>(
value: BannerDemoAction.showLeading,
checked: _showLeading.value,
child: Text(localizations.bannerDemoLeadingText),
),
],
),
],
),
body: ListView.builder(
restorationId: 'banner_demo_list_view',
itemCount: _displayBanner.value ? _itemCount + 1 : _itemCount,
itemBuilder: (BuildContext context, int index) {
if (index == 0 && _displayBanner.value) {
return banner;
}
return ListTile(
title: Text(
localizations.starterAppDrawerItem(
_displayBanner.value ? index : index + 1),
),
);
},
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
// BEGIN bottomAppBarDemo
class BottomAppBarDemo extends StatefulWidget {
const BottomAppBarDemo({super.key});
@override
State createState() => _BottomAppBarDemoState();
}
class _BottomAppBarDemoState extends State<BottomAppBarDemo>
with RestorationMixin {
final RestorableBool _showFab = RestorableBool(true);
final RestorableBool _showNotch = RestorableBool(true);
final RestorableInt _currentFabLocation = RestorableInt(0);
@override
String get restorationId => 'bottom_app_bar_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_showFab, 'show_fab');
registerForRestoration(_showNotch, 'show_notch');
registerForRestoration(_currentFabLocation, 'fab_location');
}
@override
void dispose() {
_showFab.dispose();
_showNotch.dispose();
_currentFabLocation.dispose();
super.dispose();
}
// Since FloatingActionButtonLocation is not an enum, the index of the
// selected FloatingActionButtonLocation is used for state restoration.
static const List<FloatingActionButtonLocation> _fabLocations = <FloatingActionButtonLocation>[
FloatingActionButtonLocation.endDocked,
FloatingActionButtonLocation.centerDocked,
FloatingActionButtonLocation.endFloat,
FloatingActionButtonLocation.centerFloat,
];
void _onShowNotchChanged(bool value) {
setState(() {
_showNotch.value = value;
});
}
void _onShowFabChanged(bool value) {
setState(() {
_showFab.value = value;
});
}
void _onFabLocationChanged(int? value) {
setState(() {
_currentFabLocation.value = value!;
});
}
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(localizations.demoBottomAppBarTitle),
),
body: ListView(
padding: const EdgeInsets.only(bottom: 88),
children: <Widget>[
SwitchListTile(
title: Text(
localizations.demoFloatingButtonTitle,
),
value: _showFab.value,
onChanged: _onShowFabChanged,
),
SwitchListTile(
title: Text(localizations.bottomAppBarNotch),
value: _showNotch.value,
onChanged: _onShowNotchChanged,
),
Padding(
padding: const EdgeInsets.all(16),
child: Text(localizations.bottomAppBarPosition),
),
RadioListTile<int>(
title: Text(
localizations.bottomAppBarPositionDockedEnd,
),
value: 0,
groupValue: _currentFabLocation.value,
onChanged: _onFabLocationChanged,
),
RadioListTile<int>(
title: Text(
localizations.bottomAppBarPositionDockedCenter,
),
value: 1,
groupValue: _currentFabLocation.value,
onChanged: _onFabLocationChanged,
),
RadioListTile<int>(
title: Text(
localizations.bottomAppBarPositionFloatingEnd,
),
value: 2,
groupValue: _currentFabLocation.value,
onChanged: _onFabLocationChanged,
),
RadioListTile<int>(
title: Text(
localizations.bottomAppBarPositionFloatingCenter,
),
value: 3,
groupValue: _currentFabLocation.value,
onChanged: _onFabLocationChanged,
),
],
),
floatingActionButton: _showFab.value
? Semantics(
container: true,
sortKey: const OrdinalSortKey(0),
child: FloatingActionButton(
onPressed: () {},
tooltip: localizations.buttonTextCreate,
child: const Icon(Icons.add),
),
)
: null,
floatingActionButtonLocation: _fabLocations[_currentFabLocation.value],
bottomNavigationBar: _DemoBottomAppBar(
fabLocation: _fabLocations[_currentFabLocation.value],
shape: _showNotch.value ? const CircularNotchedRectangle() : null,
),
);
}
}
class _DemoBottomAppBar extends StatelessWidget {
const _DemoBottomAppBar({
required this.fabLocation,
this.shape,
});
final FloatingActionButtonLocation fabLocation;
final NotchedShape? shape;
static final List<FloatingActionButtonLocation> centerLocations = <FloatingActionButtonLocation>[
FloatingActionButtonLocation.centerDocked,
FloatingActionButtonLocation.centerFloat,
];
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Semantics(
sortKey: const OrdinalSortKey(1),
container: true,
label: localizations.bottomAppBar,
child: BottomAppBar(
shape: shape,
child: IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary),
child: Row(
children: <Widget>[
IconButton(
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
icon: const Icon(Icons.menu),
onPressed: () {},
),
if (centerLocations.contains(fabLocation)) const Spacer(),
IconButton(
tooltip: localizations.starterAppTooltipSearch,
icon: const Icon(Icons.search),
onPressed: () {},
),
IconButton(
tooltip: localizations.starterAppTooltipFavorite,
icon: const Icon(Icons.favorite),
onPressed: () {},
)
],
),
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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:animations/animations.dart';
import 'package:flutter/material.dart';
import '../../gallery_localizations.dart';
import 'material_demo_types.dart';
// BEGIN bottomNavigationDemo
class BottomNavigationDemo extends StatefulWidget {
const BottomNavigationDemo({
super.key,
required this.restorationId,
required this.type,
});
final String restorationId;
final BottomNavigationDemoType type;
@override
State<BottomNavigationDemo> createState() => _BottomNavigationDemoState();
}
class _BottomNavigationDemoState extends State<BottomNavigationDemo>
with RestorationMixin {
final RestorableInt _currentIndex = RestorableInt(0);
@override
String get restorationId => widget.restorationId;
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_currentIndex, 'bottom_navigation_tab_index');
}
@override
void dispose() {
_currentIndex.dispose();
super.dispose();
}
String _title(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
switch (widget.type) {
case BottomNavigationDemoType.withLabels:
return localizations.demoBottomNavigationPersistentLabels;
case BottomNavigationDemoType.withoutLabels:
return localizations.demoBottomNavigationSelectedLabel;
}
}
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
final TextTheme textTheme = Theme.of(context).textTheme;
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
List<BottomNavigationBarItem> bottomNavigationBarItems = <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: const Icon(Icons.add_comment),
label: localizations.bottomNavigationCommentsTab,
),
BottomNavigationBarItem(
icon: const Icon(Icons.calendar_today),
label: localizations.bottomNavigationCalendarTab,
),
BottomNavigationBarItem(
icon: const Icon(Icons.account_circle),
label: localizations.bottomNavigationAccountTab,
),
BottomNavigationBarItem(
icon: const Icon(Icons.alarm_on),
label: localizations.bottomNavigationAlarmTab,
),
BottomNavigationBarItem(
icon: const Icon(Icons.camera_enhance),
label: localizations.bottomNavigationCameraTab,
),
];
if (widget.type == BottomNavigationDemoType.withLabels) {
bottomNavigationBarItems = bottomNavigationBarItems.sublist(
0, bottomNavigationBarItems.length - 2);
_currentIndex.value = _currentIndex.value
.clamp(0, bottomNavigationBarItems.length - 1)
;
}
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(_title(context)),
),
body: Center(
child: PageTransitionSwitcher(
transitionBuilder: (Widget child, Animation<double> animation, Animation<double> secondaryAnimation) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: _NavigationDestinationView(
// Adding [UniqueKey] to make sure the widget rebuilds when transitioning.
key: UniqueKey(),
item: bottomNavigationBarItems[_currentIndex.value],
),
),
),
bottomNavigationBar: BottomNavigationBar(
showUnselectedLabels:
widget.type == BottomNavigationDemoType.withLabels,
items: bottomNavigationBarItems,
currentIndex: _currentIndex.value,
type: BottomNavigationBarType.fixed,
selectedFontSize: textTheme.bodySmall!.fontSize!,
unselectedFontSize: textTheme.bodySmall!.fontSize!,
onTap: (int index) {
setState(() {
_currentIndex.value = index;
});
},
selectedItemColor: colorScheme.onPrimary,
unselectedItemColor: colorScheme.onPrimary.withOpacity(0.38),
backgroundColor: colorScheme.primary,
),
);
}
}
class _NavigationDestinationView extends StatelessWidget {
const _NavigationDestinationView({
super.key,
required this.item,
});
final BottomNavigationBarItem item;
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ExcludeSemantics(
child: Center(
child: Padding(
padding: const EdgeInsets.all(16),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.asset(
'assets/demos/bottom_navigation_background.png',
package: 'flutter_gallery_assets',
),
),
),
),
),
Center(
child: IconTheme(
data: const IconThemeData(
color: Colors.white,
size: 80,
),
child: Semantics(
label: GalleryLocalizations.of(context)!
.bottomNavigationContentPlaceholder(
item.label!,
),
child: item.icon,
),
),
),
],
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
import 'material_demo_types.dart';
class BottomSheetDemo extends StatelessWidget {
const BottomSheetDemo({
super.key,
required this.type,
});
final BottomSheetDemoType type;
String _title(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
switch (type) {
case BottomSheetDemoType.persistent:
return localizations.demoBottomSheetPersistentTitle;
case BottomSheetDemoType.modal:
return localizations.demoBottomSheetModalTitle;
}
}
Widget _bottomSheetDemo(BuildContext context) {
switch (type) {
case BottomSheetDemoType.persistent:
return _PersistentBottomSheetDemo();
case BottomSheetDemoType.modal:
return _ModalBottomSheetDemo();
}
}
@override
Widget build(BuildContext context) {
// We wrap the demo in a [Navigator] to make sure that the modal bottom
// sheets gets dismissed when changing demo.
return Navigator(
// Adding [ValueKey] to make sure that the widget gets rebuilt when
// changing type.
key: ValueKey<BottomSheetDemoType>(type),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
builder: (BuildContext context) => Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(_title(context)),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Theme.of(context).colorScheme.secondary,
child: Icon(
Icons.add,
semanticLabel:
GalleryLocalizations.of(context)!.demoBottomSheetAddLabel,
),
),
body: _bottomSheetDemo(context),
),
);
},
);
}
}
// BEGIN bottomSheetDemoModal#1 bottomSheetDemoPersistent#1
class _BottomSheetContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return SizedBox(
height: 300,
child: Column(
children: <Widget>[
SizedBox(
height: 70,
child: Center(
child: Text(
localizations.demoBottomSheetHeader,
textAlign: TextAlign.center,
),
),
),
const Divider(thickness: 1),
Expanded(
child: ListView.builder(
itemCount: 21,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(localizations.demoBottomSheetItem(index)),
);
},
),
),
],
),
);
}
}
// END bottomSheetDemoModal#1 bottomSheetDemoPersistent#1
// BEGIN bottomSheetDemoModal#2
class _ModalBottomSheetDemo extends StatelessWidget {
void _showModalBottomSheet(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return _BottomSheetContent();
},
);
}
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
_showModalBottomSheet(context);
},
child:
Text(GalleryLocalizations.of(context)!.demoBottomSheetButtonText),
),
);
}
}
// END
// BEGIN bottomSheetDemoPersistent#2
class _PersistentBottomSheetDemo extends StatefulWidget {
@override
_PersistentBottomSheetDemoState createState() =>
_PersistentBottomSheetDemoState();
}
class _PersistentBottomSheetDemoState
extends State<_PersistentBottomSheetDemo> {
VoidCallback? _showBottomSheetCallback;
@override
void initState() {
super.initState();
_showBottomSheetCallback = _showPersistentBottomSheet;
}
void _showPersistentBottomSheet() {
setState(() {
// Disable the show bottom sheet button.
_showBottomSheetCallback = null;
});
Scaffold.of(context)
.showBottomSheet(
(BuildContext context) {
return _BottomSheetContent();
},
elevation: 25,
)
.closed
.whenComplete(() {
if (mounted) {
setState(() {
// Re-enable the bottom sheet button.
_showBottomSheetCallback = _showPersistentBottomSheet;
});
}
});
}
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: _showBottomSheetCallback,
child:
Text(GalleryLocalizations.of(context)!.demoBottomSheetButtonText),
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
import 'material_demo_types.dart';
class ButtonDemo extends StatelessWidget {
const ButtonDemo({super.key, required this.type});
final ButtonDemoType type;
String _title(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
switch (type) {
case ButtonDemoType.text:
return localizations.demoTextButtonTitle;
case ButtonDemoType.elevated:
return localizations.demoElevatedButtonTitle;
case ButtonDemoType.outlined:
return localizations.demoOutlinedButtonTitle;
case ButtonDemoType.toggle:
return localizations.demoToggleButtonTitle;
case ButtonDemoType.floating:
return localizations.demoFloatingButtonTitle;
}
}
@override
Widget build(BuildContext context) {
Widget? buttons;
switch (type) {
case ButtonDemoType.text:
buttons = _TextButtonDemo();
case ButtonDemoType.elevated:
buttons = _ElevatedButtonDemo();
case ButtonDemoType.outlined:
buttons = _OutlinedButtonDemo();
case ButtonDemoType.toggle:
buttons = _ToggleButtonsDemo();
case ButtonDemoType.floating:
buttons = _FloatingActionButtonDemo();
}
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(_title(context)),
),
body: buttons,
);
}
}
// BEGIN buttonDemoText
class _TextButtonDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () {},
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
TextButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: () {},
),
],
),
const SizedBox(height: 12),
// Disabled buttons
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: null,
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
TextButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: null,
),
],
),
],
);
}
}
// END
// BEGIN buttonDemoElevated
class _ElevatedButtonDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {},
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
ElevatedButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: () {},
),
],
),
const SizedBox(height: 12),
// Disabled buttons
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: null,
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
ElevatedButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: null,
),
],
),
],
);
}
}
// END
// BEGIN buttonDemoOutlined
class _OutlinedButtonDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlinedButton(
onPressed: () {},
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
OutlinedButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: () {},
),
],
),
const SizedBox(height: 12),
// Disabled buttons
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlinedButton(
onPressed: null,
child: Text(localizations.buttonText),
),
const SizedBox(width: 12),
OutlinedButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text(localizations.buttonText),
onPressed: null,
),
],
),
],
);
}
}
// END
// BEGIN buttonDemoToggle
class _ToggleButtonsDemo extends StatefulWidget {
@override
_ToggleButtonsDemoState createState() => _ToggleButtonsDemoState();
}
class _ToggleButtonsDemoState extends State<_ToggleButtonsDemo>
with RestorationMixin {
final List<RestorableBool> isSelected = <RestorableBool>[
RestorableBool(false),
RestorableBool(true),
RestorableBool(false),
];
@override
String get restorationId => 'toggle_button_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(isSelected[0], 'first_item');
registerForRestoration(isSelected[1], 'second_item');
registerForRestoration(isSelected[2], 'third_item');
}
@override
void dispose() {
for (final RestorableBool restorableBool in isSelected) {
restorableBool.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ToggleButtons(
onPressed: (int index) {
setState(() {
isSelected[index].value = !isSelected[index].value;
});
},
isSelected: isSelected.map((RestorableBool element) => element.value).toList(),
children: const <Widget>[
Icon(Icons.format_bold),
Icon(Icons.format_italic),
Icon(Icons.format_underline),
],
),
const SizedBox(height: 12),
// Disabled toggle buttons
ToggleButtons(
isSelected: isSelected.map((RestorableBool element) => element.value).toList(),
children: const <Widget>[
Icon(Icons.format_bold),
Icon(Icons.format_italic),
Icon(Icons.format_underline),
],
),
],
),
);
}
}
// END
// BEGIN buttonDemoFloating
class _FloatingActionButtonDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
onPressed: () {},
tooltip: localizations.buttonTextCreate,
child: const Icon(Icons.add),
),
const SizedBox(width: 12),
FloatingActionButton.extended(
icon: const Icon(Icons.add),
label: Text(localizations.buttonTextCreate),
onPressed: () {},
),
],
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
import 'material_demo_types.dart';
class DividerDemo extends StatelessWidget {
const DividerDemo({super.key, required this.type});
final DividerDemoType type;
String _title(BuildContext context) {
switch (type) {
case DividerDemoType.horizontal:
return GalleryLocalizations.of(context)!.demoDividerTitle;
case DividerDemoType.vertical:
return GalleryLocalizations.of(context)!.demoVerticalDividerTitle;
}
}
@override
Widget build(BuildContext context) {
late Widget dividers;
switch (type) {
case DividerDemoType.horizontal:
dividers = _HorizontalDividerDemo();
case DividerDemoType.vertical:
dividers = _VerticalDividerDemo();
}
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
_title(context),
),
),
body: dividers,
);
}
}
// BEGIN dividerDemo
class _HorizontalDividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10),
child: Column(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.deepPurpleAccent,
),
),
),
const Divider(
color: Colors.grey,
height: 20,
thickness: 1,
indent: 20,
endIndent: 0,
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.deepOrangeAccent,
),
),
),
],
),
);
}
}
// END
// BEGIN verticalDividerDemo
class _VerticalDividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10),
child: Row(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.deepPurpleAccent,
),
),
),
const VerticalDivider(
color: Colors.grey,
thickness: 1,
indent: 20,
endIndent: 0,
width: 20,
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.deepOrangeAccent,
),
),
),
],
),
);
}
}
// END
// Copyright 2014 The Flutter 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_localizations.dart';
import 'material_demo_types.dart';
// BEGIN listDemo
class ListDemo extends StatelessWidget {
const ListDemo({super.key, required this.type});
final ListDemoType type;
@override
Widget build(BuildContext context) {
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(localizations.demoListsTitle),
),
body: Scrollbar(
child: ListView(
restorationId: 'list_demo_list_view',
padding: const EdgeInsets.symmetric(vertical: 8),
children: <Widget>[
for (int index = 1; index < 21; index++)
ListTile(
leading: ExcludeSemantics(
child: CircleAvatar(child: Text('$index')),
),
title: Text(
localizations.demoBottomSheetItem(index),
),
subtitle: type == ListDemoType.twoLine
? Text(localizations.demoListsSecondary)
: null,
),
],
),
),
);
}
}
// END
// Copyright 2014 The Flutter 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 'package:gallery/demos/material/app_bar_demo.dart';
export 'package:gallery/demos/material/banner_demo.dart';
export 'package:gallery/demos/material/bottom_app_bar_demo.dart';
export 'package:gallery/demos/material/bottom_navigation_demo.dart';
export 'package:gallery/demos/material/bottom_sheet_demo.dart';
export 'package:gallery/demos/material/button_demo.dart';
export 'package:gallery/demos/material/cards_demo.dart';
export 'package:gallery/demos/material/chip_demo.dart';
export 'package:gallery/demos/material/data_table_demo.dart';
export 'package:gallery/demos/material/dialog_demo.dart';
export 'package:gallery/demos/material/divider_demo.dart';
export 'package:gallery/demos/material/grid_list_demo.dart';
export 'package:gallery/demos/material/list_demo.dart';
export 'package:gallery/demos/material/menu_demo.dart';
export 'package:gallery/demos/material/navigation_drawer.dart';
export 'package:gallery/demos/material/navigation_rail_demo.dart';
export 'package:gallery/demos/material/picker_demo.dart';
export 'package:gallery/demos/material/progress_indicator_demo.dart';
export 'package:gallery/demos/material/selection_controls_demo.dart';
export 'package:gallery/demos/material/sliders_demo.dart';
export 'package:gallery/demos/material/snackbar_demo.dart';
export 'package:gallery/demos/material/tabs_demo.dart';
export 'package:gallery/demos/material/text_field_demo.dart';
export 'package:gallery/demos/material/tooltip_demo.dart';
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const String defaultRoute = '/crane';
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment