diff --git a/experimental/material_3_demo/ios/Flutter/Debug.xcconfig b/experimental/material_3_demo/ios/Flutter/Debug.xcconfig index 592ceee85..ec97fc6f3 100644 --- a/experimental/material_3_demo/ios/Flutter/Debug.xcconfig +++ b/experimental/material_3_demo/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/experimental/material_3_demo/ios/Flutter/Release.xcconfig b/experimental/material_3_demo/ios/Flutter/Release.xcconfig index 592ceee85..c4855bfe2 100644 --- a/experimental/material_3_demo/ios/Flutter/Release.xcconfig +++ b/experimental/material_3_demo/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/experimental/material_3_demo/ios/Podfile b/experimental/material_3_demo/ios/Podfile new file mode 100644 index 000000000..88359b225 --- /dev/null +++ b/experimental/material_3_demo/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/experimental/material_3_demo/lib/color_palettes_screen.dart b/experimental/material_3_demo/lib/color_palettes_screen.dart index 5380390e3..db399f817 100644 --- a/experimental/material_3_demo/lib/color_palettes_screen.dart +++ b/experimental/material_3_demo/lib/color_palettes_screen.dart @@ -2,7 +2,9 @@ // 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/material.dart'; +import 'package:url_launcher/url_launcher.dart'; const Widget divider = SizedBox(height: 10); @@ -45,18 +47,46 @@ class ColorPalettesScreen extends StatelessWidget { ); } + Widget dynamicColorNotice() => RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: Theme.of(context).textTheme.bodySmall, + children: [ + const TextSpan( + text: 'To create color schemes based on a ' + 'platform\'s implementation of dynamic color, ' + 'use the '), + TextSpan( + text: 'dynamic_color', + style: const TextStyle(decoration: TextDecoration.underline), + recognizer: TapGestureRecognizer() + ..onTap = () async { + final url = Uri.parse( + 'https://pub.dev/packages/dynamic_color', + ); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + }, + ), + const TextSpan(text: ' package.'), + ], + ), + ); + return Expanded( child: LayoutBuilder(builder: (context, constraints) { if (constraints.maxWidth < narrowScreenWidthThreshold) { return SingleChildScrollView( child: Column( children: [ + dynamicColorNotice(), divider, - schemeLabel('Light Theme'), + schemeLabel('Light ColorScheme'), schemeView(lightTheme), divider, divider, - schemeLabel('Dark Theme'), + schemeLabel('Dark ColorScheme'), schemeView(darkTheme), ], ), @@ -65,23 +95,28 @@ class ColorPalettesScreen extends StatelessWidget { return SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(top: 5), - child: Row( + child: Column( children: [ - Expanded( - child: Column( - children: [ - schemeLabel('Light Theme'), - schemeView(lightTheme), - ], - ), - ), - Expanded( - child: Column( - children: [ - schemeLabel('Dark Theme'), - schemeView(darkTheme), - ], - ), + dynamicColorNotice(), + Row( + children: [ + Expanded( + child: Column( + children: [ + schemeLabel('Light ColorScheme'), + schemeView(lightTheme), + ], + ), + ), + Expanded( + child: Column( + children: [ + schemeLabel('Dark ColorScheme'), + schemeView(darkTheme), + ], + ), + ), + ], ), ], ), diff --git a/experimental/material_3_demo/lib/component_screen.dart b/experimental/material_3_demo/lib/component_screen.dart index 1e3e9859f..ff3c8bd01 100644 --- a/experimental/material_3_demo/lib/component_screen.dart +++ b/experimental/material_3_demo/lib/component_screen.dart @@ -112,6 +112,9 @@ class Containment extends StatelessWidget { BottomSheetSection(), Cards(), Dialogs(), + Dividers(), + // TODO: Add Lists, https://github.com/flutter/flutter/issues/114006 + // TODO: Add Side sheets, https://github.com/flutter/flutter/issues/119328 ]); } } @@ -130,7 +133,10 @@ class Navigation extends StatelessWidget { isExampleBar: true, ), NavigationDrawers(scaffoldKey: scaffoldKey), + const NavigationRails(), + // TODO: Add Search https://github.com/flutter/flutter/issues/117483 const Tabs(), + const TopAppBars(), ]); } } @@ -141,12 +147,14 @@ class Selection extends StatelessWidget { @override Widget build(BuildContext context) { return const ComponentGroupDecoration(label: 'Selection', children: [ - Chips(), - DropdownMenus(), - Radios(), Checkboxes(), + Chips(), + // TODO: Add Date pickers https://github.com/flutter/flutter/issues/101481 + Menus(), + Radios(), Sliders(), Switches(), + // TODO: Add Time pickers https://github.com/flutter/flutter/issues/101480 ]); } } @@ -606,21 +614,74 @@ class _DialogsState extends State { ); } + void openFullscreenDialog(BuildContext context) { + showDialog( + context: context, + builder: (context) => Dialog.fullscreen( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Scaffold( + appBar: AppBar( + title: const Text('Full-screen dialog'), + centerTitle: false, + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ), + ), + ); + } + @override Widget build(BuildContext context) { - return Center( - child: ComponentDecoration( - label: 'Dialog', - tooltipMessage: 'Use AlertDialog or SimpleDialog', - child: UnconstrainedBox( - child: TextButton( + return ComponentDecoration( + label: 'Dialog', + tooltipMessage: + 'Use showDialog with Dialog.fullscreen, AlertDialog, or SimpleDialog', + child: Wrap( + alignment: WrapAlignment.spaceBetween, + children: [ + TextButton( child: const Text( 'Show dialog', style: TextStyle(fontWeight: FontWeight.bold), ), onPressed: () => openDialog(context), ), - ), + TextButton( + child: const Text( + 'Show full-screen dialog', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () => openFullscreenDialog(context), + ), + ], + ), + ); + } +} + +class Dividers extends StatelessWidget { + const Dividers({super.key}); + + @override + Widget build(BuildContext context) { + return ComponentDecoration( + label: 'Dividers', + tooltipMessage: 'Use Divider or VerticalDivider', + child: Column( + children: const [ + Divider(key: Key('divider')), + ], ), ); } @@ -1308,7 +1369,7 @@ class SegmentedButtons extends StatelessWidget { Widget build(BuildContext context) { return ComponentDecoration( label: 'Segmented buttons', - tooltipMessage: 'Use SegmentedButton', + tooltipMessage: 'Use SegmentedButton', child: Column( children: const [ SingleChoice(), @@ -1409,7 +1470,8 @@ class SnackBarSection extends StatelessWidget { Widget build(BuildContext context) { return ComponentDecoration( label: 'Snackbar', - tooltipMessage: 'Use SnackBar', + tooltipMessage: + 'Use ScaffoldMessenger.of(context).showSnackBar with SnackBar', child: TextButton( onPressed: () { final snackBar = SnackBar( @@ -1434,9 +1496,17 @@ class SnackBarSection extends StatelessWidget { } } -class BottomSheetSection extends StatelessWidget { +class BottomSheetSection extends StatefulWidget { const BottomSheetSection({super.key}); + @override + State createState() => _BottomSheetSectionState(); +} + +class _BottomSheetSectionState extends State { + bool isNonModalBottomSheetOpen = false; + PersistentBottomSheetController? _nonModalBottomSheetController; + @override Widget build(BuildContext context) { List buttonList = [ @@ -1472,31 +1542,77 @@ class BottomSheetSection extends StatelessWidget { return ComponentDecoration( label: 'Bottom sheet', tooltipMessage: 'Use showModalBottomSheet or showBottomSheet', - child: TextButton( - child: const Text( - 'Show bottom sheet', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onPressed: () { - showModalBottomSheet( - context: context, - // TODO: Remove when this is in the framework https://github.com/flutter/flutter/issues/118619 - constraints: const BoxConstraints(maxWidth: 640), - builder: (context) { - return SizedBox( - height: 150, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 32.0), - child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: buttonList, - ), - ), + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text( + 'Show modal bottom sheet', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + showModalBottomSheet( + context: context, + // TODO: Remove when this is in the framework https://github.com/flutter/flutter/issues/118619 + constraints: const BoxConstraints(maxWidth: 640), + builder: (context) { + return SizedBox( + height: 150, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32.0), + child: ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: buttonList, + ), + ), + ); + }, ); }, - ); - }, + ), + TextButton( + child: Text( + isNonModalBottomSheetOpen + ? 'Hide bottom sheet' + : 'Show bottom sheet', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + if (isNonModalBottomSheetOpen) { + _nonModalBottomSheetController?.close(); + setState(() { + isNonModalBottomSheetOpen = false; + }); + return; + } else { + setState(() { + isNonModalBottomSheetOpen = true; + }); + } + + _nonModalBottomSheetController = showBottomSheet( + elevation: 8.0, + context: context, + // TODO: Remove when this is in the framework https://github.com/flutter/flutter/issues/118619 + constraints: const BoxConstraints(maxWidth: 640), + builder: (context) { + return SizedBox( + height: 150, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32.0), + child: ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: buttonList, + ), + ), + ); + }, + ); + }, + ), + ], ), ); } @@ -1643,15 +1759,21 @@ class NavigationDrawers extends StatelessWidget { Widget build(BuildContext context) { return ComponentDecoration( label: 'Navigation drawer', - tooltipMessage: 'Use NavigationDrawer', - child: UnconstrainedBox( - child: TextButton( - child: const Text('Show navigation drawer', - style: TextStyle(fontWeight: FontWeight.bold)), - onPressed: () { - scaffoldKey.currentState!.openEndDrawer(); - }, - ), + tooltipMessage: + 'Use NavigationDrawer. For modal navigation drawers, see Scaffold.endDrawer', + child: Column( + children: [ + const SizedBox(height: 520, child: NavigationDrawerSection()), + colDivider, + colDivider, + TextButton( + child: const Text('Show modal navigation drawer', + style: TextStyle(fontWeight: FontWeight.bold)), + onPressed: () { + scaffoldKey.currentState!.openEndDrawer(); + }, + ), + ], ), ); } @@ -1692,10 +1814,7 @@ class _NavigationDrawerSectionState extends State { selectedIcon: destination.selectedIcon, ); }), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 28), - child: Divider(), - ), + const Divider(indent: 28, endIndent: 28), Padding( padding: const EdgeInsets.fromLTRB(28, 16, 16, 10), child: Text( @@ -1739,6 +1858,57 @@ const List labelDestinations = [ ExampleDestination('Work', Icon(Icons.bookmark_border), Icon(Icons.bookmark)), ]; +class NavigationRails extends StatelessWidget { + const NavigationRails({super.key}); + + @override + Widget build(BuildContext context) { + return const ComponentDecoration( + label: 'Navigation rail', + tooltipMessage: 'Use NavigationRail', + child: IntrinsicWidth( + child: SizedBox(height: 420, child: NavigationRailSection())), + ); + } +} + +class NavigationRailSection extends StatefulWidget { + const NavigationRailSection({super.key}); + + @override + State createState() => _NavigationRailSectionState(); +} + +class _NavigationRailSectionState extends State { + int navRailIndex = 0; + + @override + Widget build(BuildContext context) { + return NavigationRail( + onDestinationSelected: (selectedIndex) { + setState(() { + navRailIndex = selectedIndex; + }); + }, + elevation: 4, + leading: FloatingActionButton( + child: const Icon(Icons.create), onPressed: () {}), + groupAlignment: 0.0, + selectedIndex: navRailIndex, + labelType: NavigationRailLabelType.selected, + destinations: [ + ...destinations.map((destination) { + return NavigationRailDestination( + label: Text(destination.label), + icon: destination.icon, + selectedIcon: destination.selectedIcon, + ); + }), + ], + ); + } +} + class Tabs extends StatefulWidget { const Tabs({super.key}); @@ -1784,6 +1954,7 @@ class _TabsState extends State with TickerProviderStateMixin { ), ], ), + // TODO: Showcase secondary tab bar https://github.com/flutter/flutter/issues/111962 ), ), ), @@ -1791,14 +1962,84 @@ class _TabsState extends State with TickerProviderStateMixin { } } -class DropdownMenus extends StatefulWidget { - const DropdownMenus({super.key}); +class TopAppBars extends StatelessWidget { + const TopAppBars({super.key}); + + static final actions = [ + IconButton(icon: const Icon(Icons.attach_file), onPressed: () {}), + IconButton(icon: const Icon(Icons.event), onPressed: () {}), + IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}), + ]; @override - State createState() => _DropdownMenusState(); + Widget build(BuildContext context) { + return ComponentDecoration( + label: 'Top app bars', + tooltipMessage: + 'Use AppBar, SliverAppBar, SliverAppBar.medium, or SliverAppBar.large', + child: Column( + children: [ + AppBar( + title: const Text('Center-aligned'), + leading: const BackButton(), + actions: [ + IconButton( + iconSize: 32, + icon: const Icon(Icons.account_circle_outlined), + onPressed: () {}, + ), + ], + centerTitle: true, + ), + colDivider, + AppBar( + title: const Text('Small'), + leading: const BackButton(), + actions: actions, + centerTitle: false, + ), + colDivider, + SizedBox( + height: 100, + child: CustomScrollView( + slivers: [ + SliverAppBar.medium( + title: const Text('Medium'), + leading: const BackButton(), + actions: actions, + ), + const SliverFillRemaining(), + ], + ), + ), + colDivider, + SizedBox( + height: 130, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + title: const Text('Large'), + leading: const BackButton(), + actions: actions, + ), + const SliverFillRemaining(), + ], + ), + ), + ], + ), + ); + } } -class _DropdownMenusState extends State { +class Menus extends StatefulWidget { + const Menus({super.key}); + + @override + State createState() => _MenusState(); +} + +class _MenusState extends State { final TextEditingController colorController = TextEditingController(); final TextEditingController iconController = TextEditingController(); IconLabel? selectedIcon = IconLabel.smile; @@ -1822,14 +2063,11 @@ class _DropdownMenusState extends State { return ComponentDecoration( label: 'Menus', - tooltipMessage: 'Use DropdownMenu or MenuAnchor', + tooltipMessage: 'Use MenuAnchor or DropdownMenu', child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: const [ ButtonAnchorExample(), rowDivider, @@ -1839,7 +2077,7 @@ class _DropdownMenusState extends State { colDivider, Wrap( alignment: WrapAlignment.spaceAround, - runAlignment: WrapAlignment.start, + runAlignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, spacing: smallSpacing, runSpacing: smallSpacing, diff --git a/experimental/material_3_demo/macos/Flutter/Flutter-Debug.xcconfig b/experimental/material_3_demo/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b60..4b81f9b2d 100644 --- a/experimental/material_3_demo/macos/Flutter/Flutter-Debug.xcconfig +++ b/experimental/material_3_demo/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/experimental/material_3_demo/macos/Flutter/Flutter-Release.xcconfig b/experimental/material_3_demo/macos/Flutter/Flutter-Release.xcconfig index c2efd0b60..5caa9d157 100644 --- a/experimental/material_3_demo/macos/Flutter/Flutter-Release.xcconfig +++ b/experimental/material_3_demo/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/experimental/material_3_demo/macos/Flutter/GeneratedPluginRegistrant.swift b/experimental/material_3_demo/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817a5..8236f5728 100644 --- a/experimental/material_3_demo/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/experimental/material_3_demo/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/experimental/material_3_demo/macos/Podfile b/experimental/material_3_demo/macos/Podfile new file mode 100644 index 000000000..049abe295 --- /dev/null +++ b/experimental/material_3_demo/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/experimental/material_3_demo/macos/Runner.xcodeproj/project.pbxproj b/experimental/material_3_demo/macos/Runner.xcodeproj/project.pbxproj index 34b8722c1..8c64178e0 100644 --- a/experimental/material_3_demo/macos/Runner.xcodeproj/project.pbxproj +++ b/experimental/material_3_demo/macos/Runner.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 29893622E48563911C289557 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13168370F89CE850498E884F /* Pods_Runner.framework */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; @@ -52,9 +53,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 13168370F89CE850498E884F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* material_3_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "material_3_demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* material_3_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = material_3_demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -66,8 +68,11 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 73B8DF92B3D56F290108F695 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + F108BC42B08AF0DCE6FE7E0F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + F7B140583E6057BF7218F5FF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -75,12 +80,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 29893622E48563911C289557 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1CEE48D24C5E4B574B6EA5CE /* Pods */ = { + isa = PBXGroup; + children = ( + F7B140583E6057BF7218F5FF /* Pods-Runner.debug.xcconfig */, + 73B8DF92B3D56F290108F695 /* Pods-Runner.release.xcconfig */, + F108BC42B08AF0DCE6FE7E0F /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( @@ -99,6 +116,7 @@ 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 1CEE48D24C5E4B574B6EA5CE /* Pods */, ); sourceTree = ""; }; @@ -148,6 +166,7 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 13168370F89CE850498E884F /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -159,11 +178,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 62AA8B239FF89DC9F3C6C609 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 9D8B14DF00D7FCC6D93AE630 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -271,6 +292,45 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 62AA8B239FF89DC9F3C6C609 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9D8B14DF00D7FCC6D93AE630 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/experimental/material_3_demo/macos/Runner.xcworkspace/contents.xcworkspacedata b/experimental/material_3_demo/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16e..21a3cc14c 100644 --- a/experimental/material_3_demo/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/experimental/material_3_demo/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/experimental/material_3_demo/pubspec.yaml b/experimental/material_3_demo/pubspec.yaml index 63371e70b..09c335396 100644 --- a/experimental/material_3_demo/pubspec.yaml +++ b/experimental/material_3_demo/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: sdk: flutter cupertino_icons: ^1.0.2 + url_launcher: ^6.1.8 dev_dependencies: flutter_test: diff --git a/experimental/material_3_demo/test/color_screen_test.dart b/experimental/material_3_demo/test/color_screen_test.dart index 92a21673d..a29b089f7 100644 --- a/experimental/material_3_demo/test/color_screen_test.dart +++ b/experimental/material_3_demo/test/color_screen_test.dart @@ -18,8 +18,8 @@ void main() { addTearDown(tester.binding.window.clearPhysicalSizeTestValue); await tester.pumpWidget(const MaterialApp(home: Material3Demo())); - expect(find.text('Light Theme'), findsNothing); - expect(find.text('Dark Theme'), findsNothing); + expect(find.text('Light ColorScheme'), findsNothing); + expect(find.text('Dark ColorScheme'), findsNothing); expect(find.byType(NavigationBar), findsOneWidget); Finder colorIconOnBar = find.descendant( of: find.byType(NavigationBar), @@ -35,8 +35,8 @@ void main() { matching: find.widgetWithIcon(NavigationDestination, Icons.format_paint)); expect(selectedColorIconOnBar, findsOneWidget); - expect(find.text('Light Theme'), findsOneWidget); - expect(find.text('Dark Theme'), findsOneWidget); + expect(find.text('Light ColorScheme'), findsOneWidget); + expect(find.text('Dark ColorScheme'), findsOneWidget); }); testWidgets( @@ -47,9 +47,8 @@ void main() { addTearDown(tester.binding.window.clearPhysicalSizeTestValue); await tester.pumpWidget(const MaterialApp(home: Material3Demo())); await tester.pumpAndSettle(); - expect(find.text('Light Theme'), findsNothing); - expect(find.text('Dark Theme'), findsNothing); - expect(find.byType(NavigationRail), findsOneWidget); + expect(find.text('Light ColorScheme'), findsNothing); + expect(find.text('Dark ColorScheme'), findsNothing); Finder colorIconOnRail = find.descendant( of: find.byType(NavigationRail), matching: find.byIcon(Icons.format_paint_outlined)); @@ -61,16 +60,16 @@ void main() { of: find.byType(NavigationRail), matching: find.byIcon(Icons.format_paint)); expect(selectedColorIconOnRail, findsOneWidget); - expect(find.text('Light Theme'), findsOneWidget); - expect(find.text('Dark Theme'), findsOneWidget); + expect(find.text('Light ColorScheme'), findsOneWidget); + expect(find.text('Dark ColorScheme'), findsOneWidget); }); testWidgets('Color screen shows correct content', (tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold(body: Row(children: const [ColorPalettesScreen()])), )); - expect(find.text('Light Theme'), findsOneWidget); - expect(find.text('Dark Theme'), findsOneWidget); + expect(find.text('Light ColorScheme'), findsOneWidget); + expect(find.text('Dark ColorScheme'), findsOneWidget); expect(find.byType(ColorGroup, skipOffstage: false), findsNWidgets(14)); }); } diff --git a/experimental/material_3_demo/test/component_screen_test.dart b/experimental/material_3_demo/test/component_screen_test.dart index 769b87e81..e5f820995 100644 --- a/experimental/material_3_demo/test/component_screen_test.dart +++ b/experimental/material_3_demo/test/component_screen_test.dart @@ -21,7 +21,7 @@ void main() { expect(find.widgetWithIcon(AppBar, Icons.palette_outlined), findsOneWidget); // Elements on the component screen - // Buttons + // Common buttons expect(find.widgetWithText(ElevatedButton, 'Elevated'), findsNWidgets(2)); expect(find.widgetWithText(FilledButton, 'Filled'), findsNWidgets(2)); expect(find.widgetWithText(FilledButton, 'Filled tonal'), findsNWidgets(2)); @@ -29,13 +29,76 @@ void main() { expect(find.widgetWithText(TextButton, 'Text'), findsNWidgets(2)); expect(find.widgetWithText(Buttons, 'Icon'), findsNWidgets(5)); - // IconButtons + // FABs + expect( + find.byType(FloatingActionButton), + findsNWidgets( + 6)); // 2 more show up in the bottom app bar. 1 more in the navigation rail + expect(find.widgetWithText(FloatingActionButton, 'Create'), findsOneWidget); + + // Icon buttons expect(find.byType(IconToggleButton), findsNWidgets(8)); - // FABs - expect(find.byType(FloatingActionButton), - findsNWidgets(5)); // 2 more shows up in the bottom app bar. - expect(find.widgetWithText(FloatingActionButton, 'Create'), findsOneWidget); + // Segmented buttons + expect(find.byType(SegmentedButton), findsOneWidget); + expect(find.byType(SegmentedButton), findsOneWidget); + + // Badges + expect(find.byType(Badge), findsNWidgets(4)); + + // Progress indicators + Finder circularProgressIndicator = find.byType(CircularProgressIndicator); + expect(circularProgressIndicator, findsOneWidget); + Finder linearProgressIndicator = find.byType(LinearProgressIndicator); + expect(linearProgressIndicator, findsOneWidget); + + // Snackbar + expect(find.widgetWithText(TextButton, 'Show snackbar'), findsOneWidget); + + // Bottom sheet + expect(find.widgetWithText(TextButton, 'Show modal bottom sheet'), + findsOneWidget); + expect( + find.widgetWithText(TextButton, 'Show bottom sheet'), findsOneWidget); + + // Cards + expect(find.widgetWithText(Cards, 'Elevated'), findsOneWidget); + expect(find.widgetWithText(Cards, 'Filled'), findsOneWidget); + expect(find.widgetWithText(Cards, 'Outlined'), findsOneWidget); + + // Dialogs + expect(find.widgetWithText(TextButton, 'Show dialog'), findsOneWidget); + expect(find.widgetWithText(TextButton, 'Show full-screen dialog'), + findsOneWidget); + + // Dividers + expect(find.byKey(const Key('divider')), findsOneWidget); + + // Bottom app bar + expect(find.byType(BottomAppBar), findsOneWidget); + + // Navigation bar + // Third one is off screen in the scaffold + expect(find.byType(NavigationBar), findsNWidgets(3)); + + // Navigation drawer + expect(find.byType(Drawer), findsOneWidget); + expect(find.widgetWithText(TextButton, 'Show modal navigation drawer'), + findsOneWidget); + + // Navigation rail + // Second one is off screen in the scaffold + expect(find.byType(NavigationRail), findsNWidgets(2)); + + // Tabs + expect(find.byType(TabBar), findsOneWidget); + + // Top app bars + expect(find.byType(AppBar), findsNWidgets(6)); + + // Checkboxes + Finder checkboxExample = find.byType(CheckboxListTile); + expect(checkboxExample, findsNWidgets(4)); // Chips expect(find.byType(ActionChip), @@ -43,38 +106,25 @@ void main() { expect(find.byType(FilterChip), findsNWidgets(2)); expect(find.byType(InputChip), findsNWidgets(2)); - // Cards - expect(find.widgetWithText(Cards, 'Elevated'), findsOneWidget); - expect(find.widgetWithText(Cards, 'Filled'), findsOneWidget); - expect(find.widgetWithText(Cards, 'Outlined'), findsOneWidget); + // Menus + expect(find.byType(MenuAnchor), findsNWidgets(5)); + expect(find.byType(DropdownMenu), findsOneWidget); + expect(find.byType(DropdownMenu), findsOneWidget); + + // Radios + Finder radioExample = find.byType(RadioListTile); + expect(radioExample, findsNWidgets(3)); + + // Sliders + expect(find.byType(Slider), findsNWidgets(2)); + + // Switches + expect(find.byType(Switch), findsNWidgets(4)); // TextFields expect(find.widgetWithText(TextField, 'Disabled'), findsNWidgets(2)); expect(find.widgetWithText(TextField, 'Filled'), findsNWidgets(2)); expect(find.widgetWithText(TextField, 'Outlined'), findsNWidgets(2)); - - // Alert Dialog - Finder dialogExample = find.widgetWithText(TextButton, 'Show dialog'); - expect(dialogExample, findsOneWidget); - - // Switches - Finder switchExample = find.byType(Switch); - expect(switchExample, findsNWidgets(4)); - - // Checkboxes - Finder checkboxExample = find.byType(CheckboxListTile); - expect(checkboxExample, findsNWidgets(4)); - - // Radios - // TODO(guidezpl): Figure out why this isn't working - // Finder radioExample = find.byType(RadioListTile); - // expect(radioExample, findsNWidgets(4)); - - // ProgressIndicator - Finder circularProgressIndicator = find.byType(CircularProgressIndicator); - expect(circularProgressIndicator, findsOneWidget); - Finder linearProgressIndicator = find.byType(LinearProgressIndicator); - expect(linearProgressIndicator, findsOneWidget); }); testWidgets( @@ -107,7 +157,7 @@ void main() { // When screen width is greater than or equal to 1000, NavigationRail will show. // At the same time, the NavigationBar will NOT show. - expect(find.byType(NavigationRail), findsOneWidget); + expect(find.byType(NavigationRail), findsNWidgets(2)); expect(find.byType(Tooltip, skipOffstage: false), findsWidgets); expect(find.widgetWithText(NavigationRail, 'Components'), findsOneWidget); expect(find.widgetWithText(NavigationRail, 'Color'), findsOneWidget); @@ -205,7 +255,8 @@ void main() { NavigationDestination, Icons.format_paint_outlined)); await tester.tap(secondScreenIcon); await tester.pumpAndSettle(const Duration(microseconds: 500)); - BuildContext lightThemeText = tester.element(find.text('Light Theme')); + BuildContext lightThemeText = + tester.element(find.text('Light ColorScheme')); expect(Theme.of(lightThemeText).useMaterial3, false); Finder thirdScreenIcon = find.descendant( of: find.byType(NavigationBar), @@ -249,7 +300,9 @@ void main() { BuildContext appBar2 = tester.element(find.byType(AppBar).first); BuildContext body2 = tester.element(find.byType(Scaffold).first); - BuildContext navigationRail2 = tester.element(find.byType(NavigationRail)); + BuildContext navigationRail2 = tester.element( + find.widgetWithIcon(NavigationRail, Icons.format_paint_outlined)); + expect(darkIcon, findsNothing); expect(lightIcon, findsOneWidget); expect(Theme.of(appBar2).brightness, Brightness.dark); @@ -266,13 +319,12 @@ void main() { Finder menuIcon = find.descendant( of: find.byType(AppBar), matching: find.widgetWithIcon(IconButton, Icons.palette_outlined)); - BuildContext appBar = tester.element(find.byType(AppBar).first); + BuildContext appBar = tester + .element(find.widgetWithIcon(AppBar, Icons.palette_outlined).first); BuildContext body = tester.element(find.byType(Scaffold).first); - BuildContext navigationRail = tester.element(find.byType(NavigationRail)); expect(Theme.of(appBar).primaryColor, m3BaseColor); expect(Theme.of(body).primaryColor, m3BaseColor); - expect(Theme.of(navigationRail).primaryColor, m3BaseColor); await tester.tap(menuIcon); await tester.pumpAndSettle(); await tester.tap(find.text('Blue').last); @@ -280,11 +332,9 @@ void main() { BuildContext appBar2 = tester.element(find.byType(AppBar).first); BuildContext body2 = tester.element(find.byType(Scaffold).first); - BuildContext navigationRail2 = tester.element(find.byType(NavigationRail)); ThemeData expectedTheme = ThemeData(colorSchemeSeed: Colors.blue); expect(Theme.of(appBar2).primaryColor, expectedTheme.primaryColor); expect(Theme.of(body2).primaryColor, expectedTheme.primaryColor); - expect(Theme.of(navigationRail2).primaryColor, expectedTheme.primaryColor); }); } diff --git a/experimental/material_3_demo/test/elevation_screen_test.dart b/experimental/material_3_demo/test/elevation_screen_test.dart index 14f3cac2c..737a355a6 100644 --- a/experimental/material_3_demo/test/elevation_screen_test.dart +++ b/experimental/material_3_demo/test/elevation_screen_test.dart @@ -43,7 +43,6 @@ void main() { addTearDown(tester.binding.window.clearPhysicalSizeTestValue); await tester.pumpWidget(const MaterialApp(home: Material3Demo())); expect(find.text('Surface Tint Color Only'), findsNothing); - expect(find.byType(NavigationRail), findsOneWidget); Finder tintIconOnRail = find.descendant( of: find.byType(NavigationRail), matching: find.byIcon(Icons.invert_colors_on_outlined)); diff --git a/experimental/material_3_demo/test/typography_screen_test.dart b/experimental/material_3_demo/test/typography_screen_test.dart index 257a37e5b..234c14b3d 100644 --- a/experimental/material_3_demo/test/typography_screen_test.dart +++ b/experimental/material_3_demo/test/typography_screen_test.dart @@ -42,7 +42,6 @@ void main() { addTearDown(tester.binding.window.clearPhysicalSizeTestValue); await tester.pumpWidget(const MaterialApp(home: Material3Demo())); expect(find.text('Display Large'), findsNothing); - expect(find.byType(NavigationRail), findsOneWidget); Finder textIconOnRail = find.descendant( of: find.byType(NavigationRail), matching: find.byIcon(Icons.text_snippet_outlined)); diff --git a/experimental/material_3_demo/windows/flutter/generated_plugin_registrant.cc b/experimental/material_3_demo/windows/flutter/generated_plugin_registrant.cc index 8b6d4680a..4f7884874 100644 --- a/experimental/material_3_demo/windows/flutter/generated_plugin_registrant.cc +++ b/experimental/material_3_demo/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/experimental/material_3_demo/windows/flutter/generated_plugins.cmake b/experimental/material_3_demo/windows/flutter/generated_plugins.cmake index b93c4c30c..88b22e5c7 100644 --- a/experimental/material_3_demo/windows/flutter/generated_plugins.cmake +++ b/experimental/material_3_demo/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST