diff --git a/.gitignore b/.gitignore index e8c8e1c67d..6fe5ae66c7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ node_modules package-lock.json pubspec.lock tmp/ + +# Temporary as codelabs used to be a submodule +examples/codelabs diff --git a/.gitmodules b/.gitmodules index 0aac8b8cc9..e870af4f0e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,3 @@ path = site-shared url = https://github.com/dart-lang/site-shared branch = main -[submodule "examples/codelabs"] - path = examples/codelabs - url = https://github.com/flutter/codelabs diff --git a/analysis_options.yaml b/analysis_options.yaml index 8387f452a3..93582dfeb5 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,2 +1,2 @@ analyzer: - exclude: [flutter, site-shared, src, tmp, 'examples/codelabs'] + exclude: [flutter, site-shared, src, tmp] diff --git a/examples/accessibility/analysis_options.yaml b/examples/accessibility/analysis_options.yaml new file mode 100644 index 0000000000..eee60e0f5a --- /dev/null +++ b/examples/accessibility/analysis_options.yaml @@ -0,0 +1,5 @@ +# Take our settings from the example_utils analysis_options.yaml file. +# If necessary for a particular example, this file can also include +# overrides for individual lints. + +include: package:example_utils/analysis.yaml diff --git a/examples/accessibility/lib/main.dart b/examples/accessibility/lib/main.dart new file mode 100644 index 0000000000..f4aa07e146 --- /dev/null +++ b/examples/accessibility/lib/main.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +void main() => runApp(const AccessibleApp()); + +class AccessibleApp extends StatelessWidget { + const AccessibleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Your accessible app', + home: Scaffold( + appBar: AppBar( + title: const Text('Your accessible app'), + ), + ), + ); + } +} diff --git a/examples/accessibility/pubspec.yaml b/examples/accessibility/pubspec.yaml new file mode 100644 index 0000000000..14d7e77a2c --- /dev/null +++ b/examples/accessibility/pubspec.yaml @@ -0,0 +1,20 @@ +name: your_accessible_app +description: A Flutter project to contain accessibility-related code excerpts. +version: 1.0.0 +publish_to: none + +environment: + sdk: ^3.5.0 + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + example_utils: + path: ../example_utils + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/examples/accessibility/test/a11y_test.dart b/examples/accessibility/test/a11y_test.dart new file mode 100644 index 0000000000..48369d2237 --- /dev/null +++ b/examples/accessibility/test/a11y_test.dart @@ -0,0 +1,26 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:your_accessible_app/main.dart'; + +void main() { + testWidgets('Follows a11y guidelines', (tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget(AccessibleApp()); + + // Checks that tappable nodes have a minimum size of 48 by 48 pixels + // for Android. + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + + // Checks that tappable nodes have a minimum size of 44 by 44 pixels + // for iOS. + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + + // Checks that touch targets with a tap or long press action are labeled. + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + + // Checks whether semantic nodes meet the minimum text contrast levels. + // The recommended text contrast is 3:1 for larger text + // (18 point and above regular). + await expectLater(tester, meetsGuideline(textContrastGuideline)); + handle.dispose(); + }); +} diff --git a/examples/codelabs b/examples/codelabs deleted file mode 160000 index 6ee198e098..0000000000 --- a/examples/codelabs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ee198e098488302fc67997f5f7797ecf281940b diff --git a/src/content/cookbook/navigation/set-up-app-links.md b/src/content/cookbook/navigation/set-up-app-links.md index 0fadec9543..2dc8c48813 100644 --- a/src/content/cookbook/navigation/set-up-app-links.md +++ b/src/content/cookbook/navigation/set-up-app-links.md @@ -1,13 +1,10 @@ --- title: Set up app links for Android -description: How set up universal links for an iOS application built with Flutter -js: - - defer: true - url: /assets/js/inject_dartpad.js +description: >- + Learn how to set up app links for an + Android application built with Flutter. --- - - Deep linking is a mechanism for launching an app with a URI. This URI contains scheme, host, and path, and opens the app to a specific screen. @@ -21,7 +18,7 @@ Learn more and see a demo at [Validate deep links][]. [Validate deep links]: /tools/devtools/deep-links -A _app link_ is a type of deep link that uses +An _app link_ is a type of deep link that uses `http` or `https` and is exclusive to Android devices. Setting up app links requires one to own a web domain. @@ -35,14 +32,14 @@ This example uses the [go_router][] package to handle the routing. The Flutter team maintains the `go_router` package. It provides a simple API to handle complex routing scenarios. -1. To create a new application, type `flutter create `: + 1. To create a new application, type `flutter create `: - ```shell + ```console $ flutter create deeplink_cookbook ``` -2. To include `go_router` package in your app, - add a dependency for `go_router` to the project: + 2. To include `go_router` package in your app, + add a dependency for `go_router` to the project: To add the `go_router` package as a dependency, run `flutter pub add`: @@ -51,11 +48,10 @@ It provides a simple API to handle complex routing scenarios. $ flutter pub add go_router ``` -3. To handle the routing, - create a `GoRouter` object in the `main.dart` file: + 3. To handle the routing, + create a `GoRouter` object in the `main.dart` file: - - ```dartpad title="Flutter GoRouter hands-on example in DartPad" run="true" + ```dart title="main.dart" import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -84,9 +80,9 @@ It provides a simple API to handle complex routing scenarios. ## 2. Modify AndroidManifest.xml -1. Open the Flutter project with VS Code or Android Studio. -2. Navigate to `android/app/src/main/AndroidManifest.xml` file. -3. Add the following metadata tag and intent filter inside the + 1. Open the Flutter project with VS Code or Android Studio. + 2. Navigate to `android/app/src/main/AndroidManifest.xml` file. + 3. Add the following metadata tag and intent filter inside the `` tag with `.MainActivity`. Replace `example.com` with your own web domain. @@ -102,14 +98,14 @@ It provides a simple API to handle complex routing scenarios. ``` - :::note - The metadata tag flutter_deeplinking_enabled opts - into Flutter's default deeplink handler. - If you are using the third-party plugins, - such as [uni_links][], setting this metadata tag will - break these plugins. Omit this metadata tag - if you prefer to use third-party plugins. - ::: + :::note + The metadata tag `flutter_deeplinking_enabled` opts + into Flutter's default deeplink handler. + If you are using the third-party plugins, + such as [uni_links][], setting this metadata tag will + break these plugins. Omit this metadata tag + if you prefer to use third-party plugins. + ::: ## 3. Hosting assetlinks.json file @@ -164,15 +160,15 @@ The hosted file should look similar to this: }] ``` -1. Set the `package_name` value to your Android application ID. + 1. Set the `package_name` value to your Android application ID. -2. Set sha256_cert_fingerprints to the value you got - from the previous step. + 2. Set sha256_cert_fingerprints to the value you got + from the previous step. -3. Host the file at a URL that resembles the following: - `/.well-known/assetlinks.json` + 3. Host the file at a URL that resembles the following: + `/.well-known/assetlinks.json` -4. Verify that your browser can access this file. + 4. Verify that your browser can access this file. :::note If you have multiple flavors, you can have many sha256_cert_fingerprint diff --git a/src/content/cookbook/navigation/set-up-universal-links.md b/src/content/cookbook/navigation/set-up-universal-links.md index 8f52f8f074..b9ddfd8adc 100644 --- a/src/content/cookbook/navigation/set-up-universal-links.md +++ b/src/content/cookbook/navigation/set-up-universal-links.md @@ -1,13 +1,10 @@ --- title: Set up universal links for iOS -description: How set up universal links for an iOS application built with Flutter -js: - - defer: true - url: /assets/js/inject_dartpad.js +description: >- + Learn how to set up universal links for an + iOS application built with Flutter. --- - - Deep linking allows an app user to launch an app with a URI. This URI contains scheme, host, and path, and opens the app to a specific screen. @@ -38,7 +35,7 @@ It provides a simple API to handle complex routing scenarios. 1. To create a new application, type `flutter create `. - ```shell + ```console $ flutter create deeplink_cookbook ``` @@ -51,8 +48,7 @@ It provides a simple API to handle complex routing scenarios. 3. To handle the routing, create a `GoRouter` object in the `main.dart` file: - - ```dartpad title="Flutter GoRouter hands-on example in DartPad" run="true" + ```dart title="main.dart" import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -90,8 +86,7 @@ It provides a simple API to handle complex routing scenarios. 1. In the Xcode Navigator, expand **Runner** then click **Info**. - Xcode info.Plist screenshot @@ -111,7 +106,7 @@ It provides a simple API to handle complex routing scenarios. flutter deeplinking enabled screenshot :::note @@ -162,7 +157,7 @@ capability. To add associated domains, choose the IDE tab. {% endtab %} {% tab "Other editors" %} -1. Open the `ios/Runner/Runner.entitlements` XML file in your preferred IDE. +1. Open the `ios/Runner/Runner.entitlements` XML file in your preferred editor. 1. Add an associated domain inside the `` tag. @@ -181,8 +176,8 @@ capability. To add associated domains, choose the IDE tab. 1. Save the `ios/Runner/Runner.entitlements` file. -To check that the associated domains you created are available, perform -the following steps. +To check that the associated domains you created are available, +perform the following steps: 1. Launch Xcode if necessary. @@ -207,8 +202,10 @@ You have finished configuring the application for deep linking. ## Associate your app with your web domain You need to host an `apple-app-site-association` file in the web domain. -This file tells the mobile browser which iOS application to open instead of the browser. -To create the file, find the `appID` of the Flutter app you created in the previous section. +This file tells the mobile browser which +iOS application to open instead of the browser. +To create the file, find the `appID` of the Flutter app you +created in the previous section. ### Locate components of the `appID` @@ -273,8 +270,8 @@ this file should resemble the following content: 1. Verify that your browser can access this file. :::note -If you have more than one scheme/flavor, you can add more than one appID -into appIDs fields +If you have more than one scheme/flavor, you can +add more than one `appID` into the `appIDs` field. ::: ## Test the universal link @@ -282,8 +279,7 @@ into appIDs fields Test a universal link using a physical iOS device or the Simulator. :::note -It might take up to 24 hours before Apple's -[Content Delivery Network](https://en.wikipedia.org/wiki/Content_delivery_network) (CDN) +It might take up to 24 hours before Apple's [Content Delivery Network][] (CDN) requests the `apple-app-site-association` (AASA) file from your web domain. Until the CDN requests the file, the universal link won't work. To bypass Apple's CDN, check out the [alternate mode section][]. @@ -321,6 +317,8 @@ To bypass Apple's CDN, check out the [alternate mode section][]. alt="Deeplinked Simulator screenshot" width="50%" /> +[Content Delivery Network]: https://en.wikipedia.org/wiki/Content_delivery_network + ## Find the source code You can find the source code for the [deeplink_cookbook][] diff --git a/src/content/ui/accessibility-and-internationalization/accessibility.md b/src/content/ui/accessibility-and-internationalization/accessibility.md index 6d762a93ab..87d68a7385 100644 --- a/src/content/ui/accessibility-and-internationalization/accessibility.md +++ b/src/content/ui/accessibility-and-internationalization/accessibility.md @@ -230,41 +230,49 @@ Test your app using Flutter's [Accessibility Guideline API][]. This API checks if your app's UI meets Flutter's accessibility recommendations. These cover recommendations for text contrast, target size, and target labels. -The following example shows how to use the Guideline API on Name Generator. -You created this app as part of the -[Write your first Flutter app](/get-started/codelab) codelab. -Each button on the app's main screen serves as a tappable target -with text represented in 18 point. - - - -```dart -final SemanticsHandle handle = tester.ensureSemantics(); -await tester.pumpWidget(MyApp()); - -// Checks that tappable nodes have a minimum size of 48 by 48 pixels -// for Android. -await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); - -// Checks that tappable nodes have a minimum size of 44 by 44 pixels -// for iOS. -await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); +The following snippet shows how to use the Guideline API on +a sample widget named `AccessibleApp`: -// Checks that touch targets with a tap or long press action are labeled. -await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + +```dart title="test/a11y_test.dart" +import 'package:flutter_test/flutter_test.dart'; +import 'package:your_accessible_app/main.dart'; -// Checks whether semantic nodes meet the minimum text contrast levels. -// The recommended text contrast is 3:1 for larger text -// (18 point and above regular). -await expectLater(tester, meetsGuideline(textContrastGuideline)); -handle.dispose(); +void main() { + testWidgets('Follows a11y guidelines', (tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget(AccessibleApp()); + + // Checks that tappable nodes have a minimum size of 48 by 48 pixels + // for Android. + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + + // Checks that tappable nodes have a minimum size of 44 by 44 pixels + // for iOS. + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + + // Checks that touch targets with a tap or long press action are labeled. + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + + // Checks whether semantic nodes meet the minimum text contrast levels. + // The recommended text contrast is 3:1 for larger text + // (18 point and above regular). + await expectLater(tester, meetsGuideline(textContrastGuideline)); + handle.dispose(); + }); +} ``` -You can add Guideline API tests -in `test/widget_test.dart` of your app directory, or as a separate test -file (such as `test/a11y_test.dart` in the case of the Name Generator). +To try these tests out, run them on the app you create in the +[Write your first Flutter app](/get-started/codelab) codelab. +Each button on that app's main screen serves as a tappable target +with text rendered in an 18 point font. + +You can add Guideline API tests alongside other [widget tests][], +or in a separate file, such as `test/a11y_test.dart` in this example. [Accessibility Guideline API]: {{site.api}}/flutter/flutter_test/AccessibilityGuideline-class.html +[widget tests]: /testing/overview#widget-tests ## Testing accessibility on web diff --git a/tool/flutter_site/lib/src/commands/format_dart.dart b/tool/flutter_site/lib/src/commands/format_dart.dart index 91f6bd8fd2..6fd978e277 100644 --- a/tool/flutter_site/lib/src/commands/format_dart.dart +++ b/tool/flutter_site/lib/src/commands/format_dart.dart @@ -42,9 +42,7 @@ int formatDart({bool justCheck = false}) { .listSync() .whereType() .map((e) => e.path) - .where((e) => - path.basename(e) != 'codelabs' && - !path.basename(e).startsWith('.')), + .where((e) => !path.basename(e).startsWith('.')), ]; final dartFormatOutput = Process.runSync(Platform.resolvedExecutable, [ diff --git a/tool/flutter_site/lib/src/utils.dart b/tool/flutter_site/lib/src/utils.dart index be940971ed..ddb1dd66aa 100644 --- a/tool/flutter_site/lib/src/utils.dart +++ b/tool/flutter_site/lib/src/utils.dart @@ -51,10 +51,9 @@ extension ArgResultExtensions on ArgResults? { /// A collection of the paths of all Dart projects with /// a pubspec.yaml file in the `/examples` directory, -/// excluding ones in hidden directories or codelabs. +/// excluding ones in hidden directories. final List exampleProjectDirectories = findNestedDirectoriesWithPubspec( Directory('examples'), - skipPaths: {path.join('examples', 'codelabs')}, skipHidden: true, )..sort();