Skip to content

Commit

Permalink
Cupertino text clear label (#129727)
Browse files Browse the repository at this point in the history
Fixes #123107

Adds a customizable semantic label so that the clear button on the Cupertino text field will be picked up by screen readers.

https://github.com/flutter/flutter/assets/58190796/de31d9dd-923c-402f-a55b-e5cc77ea68bb
  • Loading branch information
MitchellGoodwin authored Dec 15, 2023
1 parent 8c1d723 commit f0051d8
Show file tree
Hide file tree
Showing 92 changed files with 481 additions and 73 deletions.
7 changes: 7 additions & 0 deletions packages/flutter/lib/src/cupertino/localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ abstract class CupertinoLocalizations {
// The global version uses the translated string from the arb file.
String get pasteButtonLabel;

/// The term used for clearing a field.
// The global version uses the translated string from the arb file.
String get clearButtonLabel;

/// Label that appears in the Cupertino toolbar when the spell checker
/// couldn't find any replacements for the current word.
// The global version uses the translated string from the arb file.
Expand Down Expand Up @@ -479,6 +483,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations {
@override
String get pasteButtonLabel => 'Paste';

@override
String get clearButtonLabel => 'Clear';

@override
String get noSpellCheckReplacementsLabel => 'No Replacements Found';

Expand Down
34 changes: 25 additions & 9 deletions packages/flutter/lib/src/cupertino/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'adaptive_text_selection_toolbar.dart';
import 'colors.dart';
import 'desktop_text_selection.dart';
import 'icons.dart';
import 'localizations.dart';
import 'magnifier.dart';
import 'spell_check_suggestions_toolbar.dart';
import 'text_selection.dart';
Expand Down Expand Up @@ -228,6 +229,7 @@ class CupertinoTextField extends StatefulWidget {
this.suffix,
this.suffixMode = OverlayVisibilityMode.always,
this.clearButtonMode = OverlayVisibilityMode.never,
this.clearButtonSemanticLabel,
TextInputType? keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
Expand Down Expand Up @@ -354,6 +356,7 @@ class CupertinoTextField extends StatefulWidget {
this.suffix,
this.suffixMode = OverlayVisibilityMode.always,
this.clearButtonMode = OverlayVisibilityMode.never,
this.clearButtonSemanticLabel,
TextInputType? keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
Expand Down Expand Up @@ -508,6 +511,12 @@ class CupertinoTextField extends StatefulWidget {
/// Defaults to [OverlayVisibilityMode.never].
final OverlayVisibilityMode clearButtonMode;

/// The semantic label for the clear button used by screen readers.
///
/// This will be used by screen reading software to identify the clear button
/// widget. Defaults to "Clear".
final String? clearButtonSemanticLabel;

/// {@macro flutter.widgets.editableText.keyboardType}
final TextInputType keyboardType;

Expand Down Expand Up @@ -829,6 +838,7 @@ class CupertinoTextField extends StatefulWidget {
properties.add(DiagnosticsProperty<OverlayVisibilityMode>('prefix', prefix == null ? null : prefixMode));
properties.add(DiagnosticsProperty<OverlayVisibilityMode>('suffix', suffix == null ? null : suffixMode));
properties.add(DiagnosticsProperty<OverlayVisibilityMode>('clearButtonMode', clearButtonMode));
properties.add(DiagnosticsProperty<String>('clearButtonSemanticLabel', clearButtonSemanticLabel));
properties.add(DiagnosticsProperty<TextInputType>('keyboardType', keyboardType, defaultValue: TextInputType.text));
properties.add(DiagnosticsProperty<TextStyle>('style', style, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
Expand Down Expand Up @@ -1116,15 +1126,21 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
}

Widget _buildClearButton() {
return GestureDetector(
key: _clearGlobalKey,
onTap: widget.enabled ? _onClearButtonTapped : null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: Icon(
CupertinoIcons.clear_thick_circled,
size: 18.0,
color: CupertinoDynamicColor.resolve(_kClearButtonColor, context),
final String clearLabel = widget.clearButtonSemanticLabel ?? CupertinoLocalizations.of(context).clearButtonLabel;

return Semantics(
button: true,
label: clearLabel,
child: GestureDetector(
key: _clearGlobalKey,
onTap: widget.enabled ? _onClearButtonTapped : null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: Icon(
CupertinoIcons.clear_thick_circled,
size: 18.0,
color: CupertinoDynamicColor.resolve(_kClearButtonColor, context),
),
),
),
);
Expand Down
1 change: 1 addition & 0 deletions packages/flutter/test/cupertino/localizations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ void main() {
expect(localizations.modalBarrierDismissLabel, isNotNull);
expect(localizations.searchTextFieldPlaceholderLabel, isNotNull);
expect(localizations.noSpellCheckReplacementsLabel, isNotNull);
expect(localizations.clearButtonLabel, isNotNull);
});

testWidgetsWithLeakTracking('CupertinoLocalizations.of throws', (WidgetTester tester) async {
Expand Down
59 changes: 59 additions & 0 deletions packages/flutter/test/cupertino/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7887,6 +7887,65 @@ void main() {
);
});

testWidgetsWithLeakTracking('Cupertino text field clear button semantics', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: ConstrainedBox(
constraints: BoxConstraints.loose(const Size(200, 200)),
child: const CupertinoTextField(
clearButtonMode: OverlayVisibilityMode.always,
),
),
),
),
);

expect(find.bySemanticsLabel('Clear'), findsOneWidget);

expect(
tester.getSemantics(
find.bySemanticsLabel('Clear').first,
),
matchesSemantics(
isButton: true,
hasTapAction: true,
label: 'Clear'
),
);
});

testWidgetsWithLeakTracking('Cupertino text field clear semantic label', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: ConstrainedBox(
constraints: BoxConstraints.loose(const Size(200, 200)),
child: const CupertinoTextField(
clearButtonMode: OverlayVisibilityMode.always,
clearButtonSemanticLabel: 'Delete Text'
),
),
),
),
);

expect(find.bySemanticsLabel('Clear'), findsNothing);

expect(find.bySemanticsLabel('Delete Text'), findsOneWidget);

expect(
tester.getSemantics(
find.bySemanticsLabel('Delete Text').first,
),
matchesSemantics(
isButton: true,
hasTapAction: true,
label: 'Delete Text'
),
);
});

testWidgetsWithLeakTracking('text selection style 1', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure\nhi\nwassssup!',
Expand Down
3 changes: 2 additions & 1 deletion packages/flutter_localizations/lib/src/l10n/cupertino_af.arb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"menuDismissLabel": "Maak kieslys toe",
"lookUpButtonLabel": "Kyk op",
"searchWebButtonLabel": "Deursoek web",
"shareButtonLabel": "Deel …"
"shareButtonLabel": "Deel …",
"clearButtonLabel": "Clear"
}
3 changes: 2 additions & 1 deletion packages/flutter_localizations/lib/src/l10n/cupertino_am.arb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"menuDismissLabel": "ምናሌን አሰናብት",
"lookUpButtonLabel": "ይመልከቱ",
"searchWebButtonLabel": "ድርን ፈልግ",
"shareButtonLabel": "አጋራ..."
"shareButtonLabel": "አጋራ...",
"clearButtonLabel": "Clear"
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"cutButtonLabel": "قص",
"copyButtonLabel": "نسخ",
"pasteButtonLabel": "لصق",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "اختيار الكل",
"tabSemanticsLabel": "علامة التبويب $tabIndex من $tabCount",
"modalBarrierDismissLabel": "رفض",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "কাট কৰক",
"copyButtonLabel": "প্ৰতিলিপি কৰক",
"pasteButtonLabel": "পে'ষ্ট কৰক",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "সকলো বাছনি কৰক",
"tabSemanticsLabel": "$tabCount টা টেবৰ $tabIndex নম্বৰটো",
"modalBarrierDismissLabel": "অগ্ৰাহ্য কৰক",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Kəsin",
"copyButtonLabel": "Kopyalayın",
"pasteButtonLabel": "Yerləşdirin",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Hamısını seçin",
"tabSemanticsLabel": "Tab $tabIndex/$tabCount",
"modalBarrierDismissLabel": "İmtina edin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"cutButtonLabel": "Выразаць",
"copyButtonLabel": "Капіраваць",
"pasteButtonLabel": "Уставіць",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Выбраць усе",
"tabSemanticsLabel": "Укладка $tabIndex з $tabCount",
"modalBarrierDismissLabel": "Адхіліць",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Изрязване",
"copyButtonLabel": "Копиране",
"pasteButtonLabel": "Поставяне",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Избиране на всички",
"tabSemanticsLabel": "Раздел $tabIndex от $tabCount",
"modalBarrierDismissLabel": "Отхвърляне",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "কাট করুন",
"copyButtonLabel": "কপি করুন",
"pasteButtonLabel": "পেস্ট করুন",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "সব বেছে নিন",
"tabSemanticsLabel": "$tabCount-এর মধ্যে $tabIndex নম্বর ট্যাব",
"modalBarrierDismissLabel": "খারিজ করুন",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"cutButtonLabel": "Izreži",
"copyButtonLabel": "Kopiraj",
"pasteButtonLabel": "Zalijepi",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Odaberi sve",
"tabSemanticsLabel": "Kartica $tabIndex od $tabCount",
"modalBarrierDismissLabel": "Odbaci",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Retalla",
"copyButtonLabel": "Copia",
"pasteButtonLabel": "Enganxa",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Seleccionar-ho tot",
"tabSemanticsLabel": "Pestanya $tabIndex de $tabCount",
"modalBarrierDismissLabel": "Ignora",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"cutButtonLabel": "Vyjmout",
"copyButtonLabel": "Kopírovat",
"pasteButtonLabel": "Vložit",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Vybrat vše",
"tabSemanticsLabel": "Karta $tabIndex z $tabCount",
"modalBarrierDismissLabel": "Zavřít",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"cutButtonLabel": "Torri",
"copyButtonLabel": "Copïo",
"pasteButtonLabel": "Gludo",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Dewis y Cyfan",
"searchTextFieldPlaceholderLabel": "Chwilio",
"modalBarrierDismissLabel": "Diystyru",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Klip",
"copyButtonLabel": "Kopiér",
"pasteButtonLabel": "Indsæt",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Vælg alt",
"tabSemanticsLabel": "Fane $tabIndex af $tabCount",
"modalBarrierDismissLabel": "Afvis",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Ausschneiden",
"copyButtonLabel": "Kopieren",
"pasteButtonLabel": "Einsetzen",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Alle auswählen",
"tabSemanticsLabel": "Tab $tabIndex von $tabCount",
"modalBarrierDismissLabel": "Schließen",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"cutButtonLabel": "Ausschneiden",
"copyButtonLabel": "Kopieren",
"pasteButtonLabel": "Einsetzen",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Alles auswählen",
"modalBarrierDismissLabel": "Schliessen"
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"cutButtonLabel": "Αποκοπή",
"copyButtonLabel": "Αντιγραφή",
"pasteButtonLabel": "Επικόλληση",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Επιλογή όλων",
"tabSemanticsLabel": "Καρτέλα $tabIndex από $tabCount",
"modalBarrierDismissLabel": "Παράβλεψη",
Expand Down
5 changes: 5 additions & 0 deletions packages/flutter_localizations/lib/src/l10n/cupertino_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@
"description": "The label for paste buttons and menu items. The reference abbreviation is what iOS shows on text selection toolbars."
},

"clearButtonLabel": "Clear",
"@clearButtonLabel": {
"description": "The label for clear buttons and menu items."
},

"selectAllButtonLabel": "Select All",
"@selectAllButtonLabel": {
"description": "The label for select-all buttons and menu items. The reference abbreviation is what iOS shows on text selection toolbars."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cutButtonLabel": "Cut",
"copyButtonLabel": "Copy",
"pasteButtonLabel": "Paste",
"clearButtonLabel": "Clear",
"selectAllButtonLabel": "Select all",
"modalBarrierDismissLabel": "Dismiss"
}
3 changes: 2 additions & 1 deletion packages/flutter_localizations/lib/src/l10n/cupertino_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"menuDismissLabel": "Cerrar menú",
"lookUpButtonLabel": "Buscador visual",
"searchWebButtonLabel": "Buscar en la Web",
"shareButtonLabel": "Compartir..."
"shareButtonLabel": "Compartir...",
"clearButtonLabel": "Clear"
}
3 changes: 2 additions & 1 deletion packages/flutter_localizations/lib/src/l10n/cupertino_et.arb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"menuDismissLabel": "Sulge menüü",
"lookUpButtonLabel": "Look Up",
"searchWebButtonLabel": "Otsi veebist",
"shareButtonLabel": "Jaga …"
"shareButtonLabel": "Jaga …",
"clearButtonLabel": "Clear"
}
3 changes: 2 additions & 1 deletion packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"menuDismissLabel": "Baztertu menua",
"lookUpButtonLabel": "Bilatu",
"searchWebButtonLabel": "Bilatu sarean",
"shareButtonLabel": "Partekatu..."
"shareButtonLabel": "Partekatu...",
"clearButtonLabel": "Clear"
}
Loading

0 comments on commit f0051d8

Please sign in to comment.