Reland "Use semantics label for backbutton and closebutton for Android" (#115776)
* Reland "Use semantics label for backbutton and closebutton for Android" This reverts commit 20a78ed69f45502344010aedff4d915db27072b2. * change to default target platform
This commit is contained in:
parent
7673108d7e
commit
68ce1aeaeb
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
@ -27,22 +28,39 @@ class BackButtonIcon extends StatelessWidget {
|
|||||||
/// the current platform (as obtained from the [Theme]).
|
/// the current platform (as obtained from the [Theme]).
|
||||||
const BackButtonIcon({ super.key });
|
const BackButtonIcon({ super.key });
|
||||||
|
|
||||||
/// Returns the appropriate "back" icon for the given `platform`.
|
@override
|
||||||
static IconData _getIconData(TargetPlatform platform) {
|
Widget build(BuildContext context) {
|
||||||
switch (platform) {
|
final String? semanticsLabel;
|
||||||
|
final IconData data;
|
||||||
|
switch (Theme.of(context).platform) {
|
||||||
case TargetPlatform.android:
|
case TargetPlatform.android:
|
||||||
case TargetPlatform.fuchsia:
|
case TargetPlatform.fuchsia:
|
||||||
case TargetPlatform.linux:
|
case TargetPlatform.linux:
|
||||||
case TargetPlatform.windows:
|
case TargetPlatform.windows:
|
||||||
return Icons.arrow_back;
|
data = Icons.arrow_back;
|
||||||
|
break;
|
||||||
case TargetPlatform.iOS:
|
case TargetPlatform.iOS:
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
return Icons.arrow_back_ios;
|
data = Icons.arrow_back_ios;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// This can't use the platform from Theme because it is the Android OS that
|
||||||
|
// expects the duplicated tooltip and label.
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
semanticsLabel = MaterialLocalizations.of(context).backButtonTooltip;
|
||||||
|
break;
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
semanticsLabel = null;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
return Icon(data, semanticLabel: semanticsLabel);
|
||||||
Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context).platform));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Material Design back button.
|
/// A Material Design back button.
|
||||||
@ -149,8 +167,23 @@ class CloseButton extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
|
final String? semanticsLabel;
|
||||||
|
// This can't use the platform from Theme because it is the Android OS that
|
||||||
|
// expects the duplicated tooltip and label.
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
semanticsLabel = MaterialLocalizations.of(context).closeButtonTooltip;
|
||||||
|
break;
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
semanticsLabel = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: const Icon(Icons.close),
|
icon: Icon(Icons.close, semanticLabel: semanticsLabel),
|
||||||
color: color,
|
color: color,
|
||||||
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
|
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@ -288,10 +288,14 @@ class _SemanticsDebuggerPainter extends CustomPainter {
|
|||||||
|
|
||||||
assert(data.attributedLabel != null);
|
assert(data.attributedLabel != null);
|
||||||
final String message;
|
final String message;
|
||||||
|
// Android will avoid pronouncing duplicating tooltip and label.
|
||||||
|
// Therefore, having two identical strings is the same as having a single
|
||||||
|
// string.
|
||||||
|
final bool shouldIgnoreDuplicatedLabel = defaultTargetPlatform == TargetPlatform.android && data.attributedLabel.string == data.tooltip;
|
||||||
final String tooltipAndLabel = <String>[
|
final String tooltipAndLabel = <String>[
|
||||||
if (data.tooltip.isNotEmpty)
|
if (data.tooltip.isNotEmpty)
|
||||||
data.tooltip,
|
data.tooltip,
|
||||||
if (data.attributedLabel.string.isNotEmpty)
|
if (data.attributedLabel.string.isNotEmpty && !shouldIgnoreDuplicatedLabel)
|
||||||
data.attributedLabel.string,
|
data.attributedLabel.string,
|
||||||
].join('\n');
|
].join('\n');
|
||||||
if (tooltipAndLabel.isEmpty) {
|
if (tooltipAndLabel.isEmpty) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
@ -152,9 +153,21 @@ void main() {
|
|||||||
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
final String? expectedLabel;
|
||||||
|
switch(defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
expectedLabel = 'Back';
|
||||||
|
break;
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
expectedLabel = null;
|
||||||
|
}
|
||||||
expect(tester.getSemantics(find.byType(BackButton)), matchesSemantics(
|
expect(tester.getSemantics(find.byType(BackButton)), matchesSemantics(
|
||||||
tooltip: 'Back',
|
tooltip: 'Back',
|
||||||
|
label: expectedLabel,
|
||||||
isButton: true,
|
isButton: true,
|
||||||
hasEnabledState: true,
|
hasEnabledState: true,
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
@ -162,7 +175,51 @@ void main() {
|
|||||||
isFocusable: true,
|
isFocusable: true,
|
||||||
));
|
));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
}, variant: TargetPlatformVariant.all());
|
||||||
|
|
||||||
|
testWidgets('CloseButton semantics', (WidgetTester tester) async {
|
||||||
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: const Material(child: Text('Home')),
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
'/next': (BuildContext context) {
|
||||||
|
return const Material(
|
||||||
|
child: Center(
|
||||||
|
child: CloseButton(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final String? expectedLabel;
|
||||||
|
switch(defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
expectedLabel = 'Close';
|
||||||
|
break;
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
expectedLabel = null;
|
||||||
|
}
|
||||||
|
expect(tester.getSemantics(find.byType(CloseButton)), matchesSemantics(
|
||||||
|
tooltip: 'Close',
|
||||||
|
label: expectedLabel,
|
||||||
|
isButton: true,
|
||||||
|
hasEnabledState: true,
|
||||||
|
isEnabled: true,
|
||||||
|
hasTapAction: true,
|
||||||
|
isFocusable: true,
|
||||||
|
));
|
||||||
|
handle.dispose();
|
||||||
|
}, variant: TargetPlatformVariant.all());
|
||||||
|
|
||||||
testWidgets('CloseButton color', (WidgetTester tester) async {
|
testWidgets('CloseButton color', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
@ -438,6 +439,33 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('SemanticsDebugger ignores duplicated label and tooltip for Android', (WidgetTester tester) async {
|
||||||
|
final Key child = UniqueKey();
|
||||||
|
final Key debugger = UniqueKey();
|
||||||
|
final bool isPlatformAndroid = defaultTargetPlatform == TargetPlatform.android;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: SemanticsDebugger(
|
||||||
|
key: debugger,
|
||||||
|
child: Material(
|
||||||
|
child: Semantics(
|
||||||
|
container: true,
|
||||||
|
key: child,
|
||||||
|
label: 'text',
|
||||||
|
tooltip: 'text',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
_getMessageShownInSemanticsDebugger(widgetKey: child, debuggerKey: debugger, tester: tester),
|
||||||
|
isPlatformAndroid ? 'text' : 'text\ntext',
|
||||||
|
);
|
||||||
|
}, variant: TargetPlatformVariant.all());
|
||||||
|
|
||||||
testWidgets('SemanticsDebugger textfield', (WidgetTester tester) async {
|
testWidgets('SemanticsDebugger textfield', (WidgetTester tester) async {
|
||||||
final UniqueKey textField = UniqueKey();
|
final UniqueKey textField = UniqueKey();
|
||||||
final UniqueKey debugger = UniqueKey();
|
final UniqueKey debugger = UniqueKey();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user