mirror of
https://github.com/flutter/flutter
synced 2024-10-02 14:34:22 +00:00
Adds more a11y use cases (#136761)
This commit is contained in:
parent
464e751a78
commit
ffc042326a
|
@ -44,9 +44,22 @@ class App extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => HomePageState();
|
||||
}
|
||||
|
||||
class HomePageState extends State<HomePage> {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget _buildUseCaseItem(int index, UseCase useCase) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
|
@ -69,6 +82,7 @@ class HomePage extends StatelessWidget {
|
|||
appBar: AppBar(title: const Text('Accessibility Assessments')),
|
||||
body: Center(
|
||||
child: ListView(
|
||||
controller: scrollController,
|
||||
children: List<Widget>.generate(
|
||||
useCases.length,
|
||||
(int index) => _buildUseCaseItem(index, useCases[index]),
|
||||
|
|
75
dev/a11y_assessments/lib/use_cases/auto_complete.dart
Normal file
75
dev/a11y_assessments/lib/use_cases/auto_complete.dart
Normal file
|
@ -0,0 +1,75 @@
|
|||
// 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 'use_cases.dart';
|
||||
|
||||
class AutoCompleteUseCase extends UseCase {
|
||||
|
||||
@override
|
||||
String get name => 'AutoComplete';
|
||||
|
||||
@override
|
||||
String get route => '/auto-complete';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const _MainWidget();
|
||||
}
|
||||
|
||||
class _MainWidget extends StatefulWidget {
|
||||
const _MainWidget();
|
||||
|
||||
@override
|
||||
State<_MainWidget> createState() => _MainWidgetState();
|
||||
}
|
||||
|
||||
class _MainWidgetState extends State<_MainWidget> {
|
||||
static const List<String> _kOptions = <String>[
|
||||
'apple',
|
||||
'banana',
|
||||
'lemon',
|
||||
];
|
||||
|
||||
static Widget _fieldViewBuilder(BuildContext context, TextEditingController textEditingController, FocusNode focusNode, VoidCallback onFieldSubmitted) {
|
||||
return TextFormField(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
controller: textEditingController,
|
||||
onFieldSubmitted: (String value) {
|
||||
onFieldSubmitted();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('AutoComplete'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Type below to autocomplete the following possible results: $_kOptions.'),
|
||||
Autocomplete<String>(
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
if (textEditingValue.text == '') {
|
||||
return const Iterable<String>.empty();
|
||||
}
|
||||
return _kOptions.where((String option) {
|
||||
return option.contains(textEditingValue.text.toLowerCase());
|
||||
});
|
||||
},
|
||||
fieldViewBuilder: _fieldViewBuilder,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
49
dev/a11y_assessments/lib/use_cases/badge.dart
Normal file
49
dev/a11y_assessments/lib/use_cases/badge.dart
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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 'use_cases.dart';
|
||||
|
||||
class BadgeUseCase extends UseCase {
|
||||
|
||||
@override
|
||||
String get name => 'Badge';
|
||||
|
||||
@override
|
||||
String get route => '/badge';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const MainWidget();
|
||||
}
|
||||
|
||||
class MainWidget extends StatefulWidget {
|
||||
const MainWidget({super.key});
|
||||
|
||||
@override
|
||||
State<MainWidget> createState() => MainWidgetState();
|
||||
}
|
||||
|
||||
class MainWidgetState extends State<MainWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('Badge'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Badge(
|
||||
label: Text(
|
||||
'5',
|
||||
semanticsLabel: '5 new messages',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
child: Icon(Icons.mail, semanticLabel: 'Messages'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
74
dev/a11y_assessments/lib/use_cases/material_banner.dart
Normal file
74
dev/a11y_assessments/lib/use_cases/material_banner.dart
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 'use_cases.dart';
|
||||
|
||||
class MaterialBannerUseCase extends UseCase {
|
||||
|
||||
@override
|
||||
String get name => 'MaterialBanner';
|
||||
|
||||
@override
|
||||
String get route => '/material_banner';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const MainWidget();
|
||||
}
|
||||
|
||||
class MainWidget extends StatefulWidget {
|
||||
const MainWidget({super.key});
|
||||
|
||||
@override
|
||||
State<MainWidget> createState() => MainWidgetState();
|
||||
}
|
||||
|
||||
class MainWidgetState extends State<MainWidget> {
|
||||
double currentSliderValue = 20;
|
||||
ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason>? controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
VoidCallback? onPress;
|
||||
if (controller == null) {
|
||||
onPress = () {
|
||||
setState(() {
|
||||
controller = ScaffoldMessenger.of(context).showMaterialBanner(
|
||||
MaterialBanner(
|
||||
padding: const EdgeInsets.all(20),
|
||||
content: const Text('Hello, I am a Material Banner'),
|
||||
leading: const Icon(Icons.agriculture_outlined),
|
||||
backgroundColor: Colors.green,
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
controller!.close();
|
||||
setState(() {
|
||||
controller = null;
|
||||
});
|
||||
},
|
||||
child: const Text('DISMISS'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('MaterialBanner'),
|
||||
),
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
autofocus: true,
|
||||
onPressed: onPress,
|
||||
child: const Text('Show a MaterialBanner'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
79
dev/a11y_assessments/lib/use_cases/navigation_bar.dart
Normal file
79
dev/a11y_assessments/lib/use_cases/navigation_bar.dart
Normal file
|
@ -0,0 +1,79 @@
|
|||
// 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 'use_cases.dart';
|
||||
|
||||
class NavigationBarUseCase extends UseCase {
|
||||
|
||||
@override
|
||||
String get name => 'NavigationBar';
|
||||
|
||||
@override
|
||||
String get route => '/navigation-bar';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const MainWidget();
|
||||
}
|
||||
|
||||
class MainWidget extends StatefulWidget {
|
||||
const MainWidget({super.key});
|
||||
|
||||
@override
|
||||
State<MainWidget> createState() => MainWidgetState();
|
||||
}
|
||||
|
||||
class MainWidgetState extends State<MainWidget> {
|
||||
int currentPageIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('NavigationBar'),
|
||||
),
|
||||
bottomNavigationBar: NavigationBar(
|
||||
onDestinationSelected: (int index) {
|
||||
setState(() {
|
||||
currentPageIndex = index;
|
||||
});
|
||||
},
|
||||
indicatorColor: Colors.amber[800],
|
||||
selectedIndex: currentPageIndex,
|
||||
destinations: const <Widget>[
|
||||
NavigationDestination(
|
||||
selectedIcon: Icon(Icons.home),
|
||||
icon: Icon(Icons.home_outlined),
|
||||
label: 'Home',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.business),
|
||||
label: 'Business',
|
||||
),
|
||||
NavigationDestination(
|
||||
selectedIcon: Icon(Icons.school),
|
||||
icon: Icon(Icons.school_outlined),
|
||||
label: 'School',
|
||||
),
|
||||
],
|
||||
),
|
||||
body: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: const Text('Page 1'),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: const Text('Page 2'),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: const Text('Page 3'),
|
||||
),
|
||||
][currentPageIndex],
|
||||
);
|
||||
}
|
||||
}
|
55
dev/a11y_assessments/lib/use_cases/text_button.dart
Normal file
55
dev/a11y_assessments/lib/use_cases/text_button.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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 'use_cases.dart';
|
||||
|
||||
class TextButtonUseCase extends UseCase {
|
||||
|
||||
@override
|
||||
String get name => 'TextButton';
|
||||
|
||||
@override
|
||||
String get route => '/text-button';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const MainWidget();
|
||||
}
|
||||
|
||||
class MainWidget extends StatefulWidget {
|
||||
const MainWidget({super.key});
|
||||
|
||||
@override
|
||||
State<MainWidget> createState() => MainWidgetState();
|
||||
}
|
||||
|
||||
class MainWidgetState extends State<MainWidget> {
|
||||
double currentSliderValue = 20;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('TextButton'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () { },
|
||||
child: const Text('Text button'),
|
||||
),
|
||||
const TextButton(
|
||||
onPressed: null,
|
||||
child: Text('Text button disabled'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,10 +4,15 @@
|
|||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'auto_complete.dart';
|
||||
import 'badge.dart';
|
||||
import 'check_box_list_tile.dart';
|
||||
import 'date_picker.dart';
|
||||
import 'dialog.dart';
|
||||
import 'material_banner.dart';
|
||||
import 'navigation_bar.dart';
|
||||
import 'slider.dart';
|
||||
import 'text_button.dart';
|
||||
import 'text_field.dart';
|
||||
import 'text_field_password.dart';
|
||||
|
||||
|
@ -24,4 +29,9 @@ final List<UseCase> useCases = <UseCase>[
|
|||
TextFieldUseCase(),
|
||||
TextFieldPasswordUseCase(),
|
||||
DatePickerUseCase(),
|
||||
AutoCompleteUseCase(),
|
||||
BadgeUseCase(),
|
||||
MaterialBannerUseCase(),
|
||||
NavigationBarUseCase(),
|
||||
TextButtonUseCase(),
|
||||
];
|
||||
|
|
|
@ -11,6 +11,11 @@ void main() {
|
|||
for (final UseCase useCase in useCases) {
|
||||
testWidgets('testing accessibility guideline for ${useCase.name}', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const App());
|
||||
final ScrollController controller = tester.state<HomePageState>(find.byType(HomePage)).scrollController;
|
||||
while (find.byKey(Key(useCase.name)).evaluate().isEmpty) {
|
||||
controller.jumpTo(controller.offset + 600);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
await tester.tap(find.byKey(Key(useCase.name)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
|
19
dev/a11y_assessments/test/auto_complete_test.dart
Normal file
19
dev/a11y_assessments/test/auto_complete_test.dart
Normal file
|
@ -0,0 +1,19 @@
|
|||
// 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:a11y_assessments/use_cases/auto_complete.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('auto complete can run', (WidgetTester tester) async {
|
||||
await pumpsUseCase(tester, AutoCompleteUseCase());
|
||||
await tester.enterText(find.byType(TextFormField), 'a');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('apple'), findsOneWidget);
|
||||
});
|
||||
}
|
16
dev/a11y_assessments/test/badge_test.dart
Normal file
16
dev/a11y_assessments/test/badge_test.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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:a11y_assessments/use_cases/badge.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('badge can run', (WidgetTester tester) async {
|
||||
await pumpsUseCase(tester, BadgeUseCase());
|
||||
expect(find.semantics.byLabel('5 new messages'), findsOne);
|
||||
expect(find.semantics.byLabel('Messages'), findsOne);
|
||||
});
|
||||
}
|
23
dev/a11y_assessments/test/material_banner_test.dart
Normal file
23
dev/a11y_assessments/test/material_banner_test.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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:a11y_assessments/use_cases/material_banner.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('material banner can run', (WidgetTester tester) async {
|
||||
await pumpsUseCase(tester, MaterialBannerUseCase());
|
||||
expect(find.text('Show a MaterialBanner'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Show a MaterialBanner'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Hello, I am a Material Banner'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('DISMISS'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Hello, I am a Material Banner'), findsNothing);
|
||||
});
|
||||
}
|
23
dev/a11y_assessments/test/navigation_bar_test.dart
Normal file
23
dev/a11y_assessments/test/navigation_bar_test.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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:a11y_assessments/use_cases/navigation_bar.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('navigation bar can run', (WidgetTester tester) async {
|
||||
await pumpsUseCase(tester, NavigationBarUseCase());
|
||||
expect(find.text('Page 1'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Business'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Page 2'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('School'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Page 3'), findsOneWidget);
|
||||
});
|
||||
}
|
16
dev/a11y_assessments/test/text_button_test.dart
Normal file
16
dev/a11y_assessments/test/text_button_test.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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:a11y_assessments/use_cases/text_button.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('text button can run', (WidgetTester tester) async {
|
||||
await pumpsUseCase(tester, TextButtonUseCase());
|
||||
expect(find.text('Text button'), findsOneWidget);
|
||||
expect(find.text('Text button disabled'), findsOneWidget);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue