diff --git a/packages/material_ui/example/lib/app/app.snippet.0.dart b/packages/material_ui/example/lib/app/app.snippet.0.dart new file mode 100644 index 000000000000..a65dd6233328 --- /dev/null +++ b/packages/material_ui/example/lib/app/app.snippet.0.dart @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [MaterialApp]. + +class MaterialAppExample extends StatelessWidget { + const MaterialAppExample({super.key}); + + @override + Widget build(BuildContext context) { + return + // #region body + MaterialApp( + home: Scaffold(appBar: AppBar(title: const Text('Home'))), + debugShowCheckedModeBanner: false, + ) + // #endregion body + ; + } +} diff --git a/packages/material_ui/example/lib/app/app.snippet.1.dart b/packages/material_ui/example/lib/app/app.snippet.1.dart new file mode 100644 index 000000000000..62c0f5c818b1 --- /dev/null +++ b/packages/material_ui/example/lib/app/app.snippet.1.dart @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [MaterialApp]. + +class MaterialAppExample extends StatelessWidget { + const MaterialAppExample({super.key}); + + @override + Widget build(BuildContext context) { + return + // #region body + MaterialApp( + routes: { + '/': (BuildContext context) { + return Scaffold(appBar: AppBar(title: const Text('Home Route'))); + }, + '/about': (BuildContext context) { + return Scaffold(appBar: AppBar(title: const Text('About Route'))); + }, + }, + ) + // #endregion body + ; + } +} diff --git a/packages/material_ui/example/lib/app/app.snippet.2.dart b/packages/material_ui/example/lib/app/app.snippet.2.dart new file mode 100644 index 000000000000..3c401962976c --- /dev/null +++ b/packages/material_ui/example/lib/app/app.snippet.2.dart @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [MaterialApp]. + +class MaterialAppExample extends StatelessWidget { + const MaterialAppExample({super.key}); + + @override + Widget build(BuildContext context) { + return + // #region body + MaterialApp( + theme: ThemeData( + brightness: Brightness.dark, + primaryColor: Colors.blueGrey, + ), + home: Scaffold(appBar: AppBar(title: const Text('MaterialApp Theme'))), + ) + // #endregion body + ; + } +} diff --git a/packages/material_ui/example/lib/app/app.snippet.3.dart b/packages/material_ui/example/lib/app/app.snippet.3.dart new file mode 100644 index 000000000000..ad697219ff9a --- /dev/null +++ b/packages/material_ui/example/lib/app/app.snippet.3.dart @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [MaterialApp.shortcuts]. + +class MaterialAppExample extends StatelessWidget { + const MaterialAppExample({super.key}); + + // #region body + @override + Widget build(BuildContext context) { + return WidgetsApp( + shortcuts: { + ...WidgetsApp.defaultShortcuts, + const SingleActivator(LogicalKeyboardKey.keyE): + const ActivateIntent(), + }, + color: const Color(0xFFFF0000), + builder: (BuildContext context, Widget? child) { + return const Placeholder(); + }, + ); + } + // #endregion body +} diff --git a/packages/material_ui/example/lib/app/app.snippet.4.dart b/packages/material_ui/example/lib/app/app.snippet.4.dart new file mode 100644 index 000000000000..4f1ced905f23 --- /dev/null +++ b/packages/material_ui/example/lib/app/app.snippet.4.dart @@ -0,0 +1,35 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:material_ui/material_ui.dart'; + +/// Flutter code sample for [MaterialApp.actions]. + +class MaterialAppExample extends StatelessWidget { + const MaterialAppExample({super.key, this.onActivated}); + + final VoidCallback? onActivated; + + // #region body + @override + Widget build(BuildContext context) { + return WidgetsApp( + actions: >{ + ...WidgetsApp.defaultActions, + ActivateIntent: CallbackAction( + onInvoke: (Intent intent) { + // Do something here... + onActivated?.call(); + return null; + }, + ), + }, + color: const Color(0xFFFF0000), + builder: (BuildContext context, Widget? child) { + return const Placeholder(); + }, + ); + } + // #endregion body +} diff --git a/packages/material_ui/example/test/app/app.snippet.0_test.dart b/packages/material_ui/example/test/app/app.snippet.0_test.dart new file mode 100644 index 000000000000..02008f7c5a6b --- /dev/null +++ b/packages/material_ui/example/test/app/app.snippet.0_test.dart @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/app/app.snippet.0.dart' as example; + +void main() { + testWidgets( + 'MaterialApp displays home route and disables debug mode banner', + (WidgetTester tester) async { + await tester.pumpWidget(const example.MaterialAppExample()); + + expect(find.byType(CheckedModeBanner), findsNothing); + expect(find.widgetWithText(AppBar, 'Home'), findsOneWidget); + }, + ); +} diff --git a/packages/material_ui/example/test/app/app.snippet.1_test.dart b/packages/material_ui/example/test/app/app.snippet.1_test.dart new file mode 100644 index 000000000000..4e381bb9c8fe --- /dev/null +++ b/packages/material_ui/example/test/app/app.snippet.1_test.dart @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/app/app.snippet.1.dart' as example; + +void main() { + testWidgets('MaterialApp routes map navigates between Home and About', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.MaterialAppExample()); + + expect(find.widgetWithText(AppBar, 'Home Route'), findsOneWidget); + expect(find.widgetWithText(AppBar, 'About Route'), findsNothing); + + final BuildContext context = tester.element(find.text('Home Route')); + Navigator.of(context).pushNamed('/about'); + await tester.pumpAndSettle(); + + expect(find.widgetWithText(AppBar, 'About Route'), findsOneWidget); + }); +} diff --git a/packages/material_ui/example/test/app/app.snippet.2_test.dart b/packages/material_ui/example/test/app/app.snippet.2_test.dart new file mode 100644 index 000000000000..f94ec1338efa --- /dev/null +++ b/packages/material_ui/example/test/app/app.snippet.2_test.dart @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/app/app.snippet.2.dart' as example; + +void main() { + testWidgets('MaterialApp applies custom ThemeData', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.MaterialAppExample()); + + expect(find.widgetWithText(AppBar, 'MaterialApp Theme'), findsOneWidget); + + final BuildContext context = tester.element(find.text('MaterialApp Theme')); + final ThemeData theme = Theme.of(context); + expect(theme.brightness, Brightness.dark); + expect(theme.primaryColor, Colors.blueGrey); + }); +} diff --git a/packages/material_ui/example/test/app/app.snippet.3_test.dart b/packages/material_ui/example/test/app/app.snippet.3_test.dart new file mode 100644 index 000000000000..a0ebae078129 --- /dev/null +++ b/packages/material_ui/example/test/app/app.snippet.3_test.dart @@ -0,0 +1,38 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/app/app.snippet.3.dart' as example; + +void main() { + testWidgets('WidgetsApp shortcuts maps select key to ActivateIntent', ( + WidgetTester tester, + ) async { + bool invoked = false; + await tester.pumpWidget( + Actions( + actions: >{ + ActivateIntent: CallbackAction( + onInvoke: (ActivateIntent intent) { + invoked = true; + return null; + }, + ), + }, + child: const example.MaterialAppExample(), + ), + ); + + final Element placeholderElement = tester.element(find.byType(Placeholder)); + final FocusNode focusNode = Focus.of(placeholderElement); + focusNode.canRequestFocus = true; + focusNode.requestFocus(); + await tester.pump(); + + await tester.sendKeyEvent(LogicalKeyboardKey.keyE); + expect(invoked, isTrue); + }); +} diff --git a/packages/material_ui/example/test/app/app.snippet.4_test.dart b/packages/material_ui/example/test/app/app.snippet.4_test.dart new file mode 100644 index 000000000000..df416704ee0b --- /dev/null +++ b/packages/material_ui/example/test/app/app.snippet.4_test.dart @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; +import 'package:material_ui_examples/app/app.snippet.4.dart' as example; + +void main() { + testWidgets('WidgetsApp actions handles ActivateIntent', ( + WidgetTester tester, + ) async { + bool activated = false; + await tester.pumpWidget( + example.MaterialAppExample( + onActivated: () { + activated = true; + }, + ), + ); + + final Element placeholderElement = tester.element(find.byType(Placeholder)); + final FocusNode focusNode = Focus.of(placeholderElement); + focusNode.canRequestFocus = true; + focusNode.requestFocus(); + await tester.pump(); + + await tester.sendKeyEvent(LogicalKeyboardKey.space); + expect(activated, isTrue); + }); +} diff --git a/packages/material_ui/lib/src/app.dart b/packages/material_ui/lib/src/app.dart index e3fd207a4c2d..dbc6918accbd 100644 --- a/packages/material_ui/lib/src/app.dart +++ b/packages/material_ui/lib/src/app.dart @@ -120,81 +120,32 @@ enum ThemeMode { /// /// /// -// TODO(framework): Add unit tests to this code snippet. -// https://github.com/flutter/flutter/issues/188530 -/// /// This example shows how to create a [MaterialApp] that disables the "debug" /// banner with a [home] route that will be displayed when the app is launched. /// /// ![The MaterialApp displays a Scaffold ](https://flutter.github.io/assets-for-api-docs/assets/material/basic_material_app.png) /// -/// ```dart -/// MaterialApp( -/// home: Scaffold( -/// appBar: AppBar( -/// title: const Text('Home'), -/// ), -/// ), -/// debugShowCheckedModeBanner: false, -/// ) -/// ``` +/// {@example /example/lib/app/app.snippet.0.dart#body indent=strip} /// /// /// /// /// -// TODO(framework): Add unit tests to this code snippet. -// https://github.com/flutter/flutter/issues/188530 -/// /// This example shows how to create a [MaterialApp] that uses the [routes] /// `Map` to define the "home" route and an "about" route. /// -/// ```dart -/// MaterialApp( -/// routes: { -/// '/': (BuildContext context) { -/// return Scaffold( -/// appBar: AppBar( -/// title: const Text('Home Route'), -/// ), -/// ); -/// }, -/// '/about': (BuildContext context) { -/// return Scaffold( -/// appBar: AppBar( -/// title: const Text('About Route'), -/// ), -/// ); -/// } -/// }, -/// ) -/// ``` +/// {@example /example/lib/app/app.snippet.1.dart#body indent=strip} /// /// /// /// /// -// TODO(framework): Add unit tests to this code snippet. -// https://github.com/flutter/flutter/issues/188530 -/// /// This example shows how to create a [MaterialApp] that defines a [theme] that /// will be used for material widgets in the app. /// /// ![The MaterialApp displays a Scaffold with a dark background and a blue / grey AppBar at the top](https://flutter.github.io/assets-for-api-docs/assets/material/theme_material_app.png) /// -/// ```dart -/// MaterialApp( -/// theme: ThemeData( -/// brightness: Brightness.dark, -/// primaryColor: Colors.blueGrey -/// ), -/// home: Scaffold( -/// appBar: AppBar( -/// title: const Text('MaterialApp Theme'), -/// ), -/// ), -/// ) -/// ``` +/// {@example /example/lib/app/app.snippet.2.dart#body indent=strip} /// /// /// @@ -695,31 +646,15 @@ class MaterialApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.shortcuts} /// /// - // TODO(framework): Add unit tests to this code snippet. - // https://github.com/flutter/flutter/issues/188530 - /// /// This example shows how to add a single shortcut for - /// [LogicalKeyboardKey.select] to the default shortcuts without needing to + /// [LogicalKeyboardKey.keyE] to the default shortcuts without needing to /// add your own [Shortcuts] widget. /// /// Alternatively, you could insert a [Shortcuts] widget with just the mapping /// you want to add between the [WidgetsApp] and its child and get the same /// effect. /// - /// ```dart - /// Widget build(BuildContext context) { - /// return WidgetsApp( - /// shortcuts: { - /// ... WidgetsApp.defaultShortcuts, - /// const SingleActivator(LogicalKeyboardKey.select): const ActivateIntent(), - /// }, - /// color: const Color(0xFFFF0000), - /// builder: (BuildContext context, Widget? child) { - /// return const Placeholder(); - /// }, - /// ); - /// } - /// ``` + /// {@example /example/lib/app/app.snippet.3.dart#body indent=strip} /// /// /// {@macro flutter.widgets.widgetsApp.shortcuts.seeAlso} @@ -728,9 +663,6 @@ class MaterialApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.actions} /// /// - // TODO(framework): Add unit tests to this code snippet. - // https://github.com/flutter/flutter/issues/188530 - /// /// This example shows how to add a single action handling an /// [ActivateAction] to the default actions without needing to /// add your own [Actions] widget. @@ -739,25 +671,7 @@ class MaterialApp extends StatefulWidget { /// you want to add between the [WidgetsApp] and its child and get the same /// effect. /// - /// ```dart - /// Widget build(BuildContext context) { - /// return WidgetsApp( - /// actions: >{ - /// ... WidgetsApp.defaultActions, - /// ActivateAction: CallbackAction( - /// onInvoke: (Intent intent) { - /// // Do something here... - /// return null; - /// }, - /// ), - /// }, - /// color: const Color(0xFFFF0000), - /// builder: (BuildContext context, Widget? child) { - /// return const Placeholder(); - /// }, - /// ); - /// } - /// ``` + /// {@example /example/lib/app/app.snippet.4.dart#body indent=strip} /// /// /// {@macro flutter.widgets.widgetsApp.actions.seeAlso}