Unverified Commit 0f2b1a3b authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Refactor chip class and move independent chips into separate classes (#101507)

parent 06754712
...@@ -45,6 +45,10 @@ export 'src/material/checkbox.dart'; ...@@ -45,6 +45,10 @@ export 'src/material/checkbox.dart';
export 'src/material/checkbox_list_tile.dart'; export 'src/material/checkbox_list_tile.dart';
export 'src/material/checkbox_theme.dart'; export 'src/material/checkbox_theme.dart';
export 'src/material/chip.dart'; export 'src/material/chip.dart';
export 'src/material/chip_action.dart';
export 'src/material/chip_choice.dart';
export 'src/material/chip_filter.dart';
export 'src/material/chip_input.dart';
export 'src/material/chip_theme.dart'; export 'src/material/chip_theme.dart';
export 'src/material/circle_avatar.dart'; export 'src/material/circle_avatar.dart';
export 'src/material/color_scheme.dart'; export 'src/material/color_scheme.dart';
......
...@@ -659,777 +659,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri ...@@ -659,777 +659,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
} }
} }
/// A material design input chip.
///
/// Input chips represent a complex piece of information, such as an entity
/// (person, place, or thing) or conversational text, in a compact form.
///
/// Input chips can be made selectable by setting [onSelected], deletable by
/// setting [onDeleted], and pressable like a button with [onPressed]. They have
/// a [label], and they can have a leading icon (see [avatar]) and a trailing
/// icon ([deleteIcon]). Colors and padding can be customized.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// Input chips work together with other UI elements. They can appear:
///
/// * In a [Wrap] widget.
/// * In a horizontally scrollable list, like a [ListView] whose
/// scrollDirection is [Axis.horizontal].
///
/// {@tool snippet}
///
/// ```dart
/// InputChip(
/// avatar: CircleAvatar(
/// backgroundColor: Colors.grey.shade800,
/// child: const Text('AB'),
/// ),
/// label: const Text('Aaron Burr'),
/// onPressed: () {
/// print('I am the one thing in life.');
/// }
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class InputChip extends StatelessWidget
implements
ChipAttributes,
DeletableChipAttributes,
SelectableChipAttributes,
CheckmarkableChipAttributes,
DisabledChipAttributes,
TappableChipAttributes {
/// Creates an [InputChip].
///
/// The [onPressed] and [onSelected] callbacks must not both be specified at
/// the same time.
///
/// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior]
/// arguments must not be null. The [pressElevation] and [elevation] must be
/// null or non-negative. Typically, [pressElevation] is greater than
/// [elevation].
const InputChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.selected = false,
this.isEnabled = true,
this.onSelected,
this.deleteIcon,
this.onDeleted,
this.deleteIconColor,
this.deleteButtonTooltipMessage,
this.onPressed,
this.pressElevation,
this.disabledColor,
this.selectedColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.showCheckmark,
this.checkmarkColor,
this.avatarBorder = const CircleBorder(),
@Deprecated(
'Migrate to deleteButtonTooltipMessage. '
'This feature was deprecated after v2.10.0-0.3.pre.'
)
this.useDeleteButtonTooltip = true,
}) : assert(selected != null),
assert(isEnabled != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final bool selected;
@override
final bool isEnabled;
@override
final ValueChanged<bool>? onSelected;
@override
final Widget? deleteIcon;
@override
final VoidCallback? onDeleted;
@override
final Color? deleteIconColor;
@override
final String? deleteButtonTooltipMessage;
@override
final VoidCallback? onPressed;
@override
final double? pressElevation;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final bool? showCheckmark;
@override
final Color? checkmarkColor;
@override
final ShapeBorder avatarBorder;
@override
@Deprecated(
'Migrate to deleteButtonTooltipMessage. '
'This feature was deprecated after v2.10.0-0.3.pre.'
)
final bool useDeleteButtonTooltip;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle,
labelPadding: labelPadding,
deleteIcon: deleteIcon,
onDeleted: onDeleted,
deleteIconColor: deleteIconColor,
useDeleteButtonTooltip: useDeleteButtonTooltip,
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
onSelected: onSelected,
onPressed: onPressed,
pressElevation: pressElevation,
selected: selected,
disabledColor: disabledColor,
selectedColor: selectedColor,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
backgroundColor: backgroundColor,
padding: padding,
visualDensity: visualDensity,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
showCheckmark: showCheckmark,
checkmarkColor: checkmarkColor,
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
avatarBorder: avatarBorder,
);
}
}
/// A material design choice chip.
///
/// [ChoiceChip]s represent a single choice from a set. Choice chips contain
/// related descriptive text or categories.
///
/// Requires one of its ancestors to be a [Material] widget. The [selected] and
/// [label] arguments must not be null.
///
/// {@tool snippet}
///
/// ```dart
/// class MyThreeOptions extends StatefulWidget {
/// const MyThreeOptions({Key? key}) : super(key: key);
///
/// @override
/// State<MyThreeOptions> createState() => _MyThreeOptionsState();
/// }
///
/// class _MyThreeOptionsState extends State<MyThreeOptions> {
/// int? _value = 1;
///
/// @override
/// Widget build(BuildContext context) {
/// return Wrap(
/// children: List<Widget>.generate(
/// 3,
/// (int index) {
/// return ChoiceChip(
/// label: Text('Item $index'),
/// selected: _value == index,
/// onSelected: (bool selected) {
/// setState(() {
/// _value = selected ? index : null;
/// });
/// },
/// );
/// },
/// ).toList(),
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class ChoiceChip extends StatelessWidget
implements
ChipAttributes,
SelectableChipAttributes,
DisabledChipAttributes {
/// Create a chip that acts like a radio button.
///
/// The [label], [selected], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const ChoiceChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.onSelected,
this.pressElevation,
required this.selected,
this.selectedColor,
this.disabledColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final ValueChanged<bool>? onSelected;
@override
final double? pressElevation;
@override
final bool selected;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ChipThemeData chipTheme = ChipTheme.of(context);
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle ?? (selected ? chipTheme.secondaryLabelStyle : null),
labelPadding: labelPadding,
onSelected: onSelected,
pressElevation: pressElevation,
selected: selected,
showCheckmark: false,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
disabledColor: disabledColor,
selectedColor: selectedColor ?? chipTheme.secondarySelectedColor,
backgroundColor: backgroundColor,
padding: padding,
visualDensity: visualDensity,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
avatarBorder: avatarBorder,
);
}
}
/// A material design filter chip.
///
/// Filter chips use tags or descriptive words as a way to filter content.
///
/// Filter chips are a good alternative to [Checkbox] or [Switch] widgets.
/// Unlike these alternatives, filter chips allow for clearly delineated and
/// exposed options in a compact area.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// {@tool snippet}
///
/// ```dart
/// class ActorFilterEntry {
/// const ActorFilterEntry(this.name, this.initials);
/// final String name;
/// final String initials;
/// }
///
/// class CastFilter extends StatefulWidget {
/// const CastFilter({Key? key}) : super(key: key);
///
/// @override
/// State createState() => CastFilterState();
/// }
///
/// class CastFilterState extends State<CastFilter> {
/// final List<ActorFilterEntry> _cast = <ActorFilterEntry>[
/// const ActorFilterEntry('Aaron Burr', 'AB'),
/// const ActorFilterEntry('Alexander Hamilton', 'AH'),
/// const ActorFilterEntry('Eliza Hamilton', 'EH'),
/// const ActorFilterEntry('James Madison', 'JM'),
/// ];
/// final List<String> _filters = <String>[];
///
/// Iterable<Widget> get actorWidgets {
/// return _cast.map((ActorFilterEntry actor) {
/// return Padding(
/// padding: const EdgeInsets.all(4.0),
/// child: FilterChip(
/// avatar: CircleAvatar(child: Text(actor.initials)),
/// label: Text(actor.name),
/// selected: _filters.contains(actor.name),
/// onSelected: (bool value) {
/// setState(() {
/// if (value) {
/// _filters.add(actor.name);
/// } else {
/// _filters.removeWhere((String name) {
/// return name == actor.name;
/// });
/// }
/// });
/// },
/// ),
/// );
/// });
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// Wrap(
/// children: actorWidgets.toList(),
/// ),
/// Text('Look for: ${_filters.join(', ')}'),
/// ],
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class FilterChip extends StatelessWidget
implements
ChipAttributes,
SelectableChipAttributes,
CheckmarkableChipAttributes,
DisabledChipAttributes {
/// Create a chip that acts like a checkbox.
///
/// The [selected], [label], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const FilterChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.selected = false,
required this.onSelected,
this.pressElevation,
this.disabledColor,
this.selectedColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.showCheckmark,
this.checkmarkColor,
this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final bool selected;
@override
final ValueChanged<bool>? onSelected;
@override
final double? pressElevation;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final bool? showCheckmark;
@override
final Color? checkmarkColor;
@override
final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle,
labelPadding: labelPadding,
onSelected: onSelected,
pressElevation: pressElevation,
selected: selected,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
backgroundColor: backgroundColor,
disabledColor: disabledColor,
selectedColor: selectedColor,
padding: padding,
visualDensity: visualDensity,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
showCheckmark: showCheckmark,
checkmarkColor: checkmarkColor,
avatarBorder: avatarBorder,
);
}
}
/// A material design action chip.
///
/// Action chips are a set of options which trigger an action related to primary
/// content. Action chips should appear dynamically and contextually in a UI.
///
/// Action chips can be tapped to trigger an action or show progress and
/// confirmation. They cannot be disabled; if the action is not applicable, the
/// chip should not be included in the interface. (This contrasts with buttons,
/// where unavailable choices are usually represented as disabled controls.)
///
/// Action chips are displayed after primary content, such as below a card or
/// persistently at the bottom of a screen.
///
/// The material button widgets, [ElevatedButton], [TextButton], and
/// [OutlinedButton], are an alternative to action chips, which should appear
/// statically and consistently in a UI.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// {@tool snippet}
///
/// ```dart
/// ActionChip(
/// avatar: CircleAvatar(
/// backgroundColor: Colors.grey.shade800,
/// child: const Text('AB'),
/// ),
/// label: const Text('Aaron Burr'),
/// onPressed: () {
/// print('If you stand for nothing, Burr, what’ll you fall for?');
/// }
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes {
/// Create a chip that acts like a button.
///
/// The [label], [onPressed], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const ActionChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
required this.onPressed,
this.pressElevation,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
}) : assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(
onPressed != null,
'Rather than disabling an ActionChip by setting onPressed to null, '
'remove it from the interface entirely.',
),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final VoidCallback onPressed;
@override
final double? pressElevation;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
onPressed: onPressed,
pressElevation: pressElevation,
tooltip: tooltip,
labelStyle: labelStyle,
backgroundColor: backgroundColor,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
padding: padding,
visualDensity: visualDensity,
labelPadding: labelPadding,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
);
}
}
/// A raw material design chip. /// A raw material design chip.
/// ///
/// This serves as the basis for all of the chip widget types to aggregate. /// This serves as the basis for all of the chip widget types to aggregate.
......
// 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/widgets.dart';
import 'chip.dart';
import 'debug.dart';
import 'theme_data.dart';
/// A material design action chip.
///
/// Action chips are a set of options which trigger an action related to primary
/// content. Action chips should appear dynamically and contextually in a UI.
///
/// Action chips can be tapped to trigger an action or show progress and
/// confirmation. They cannot be disabled; if the action is not applicable, the
/// chip should not be included in the interface. (This contrasts with buttons,
/// where unavailable choices are usually represented as disabled controls.)
///
/// Action chips are displayed after primary content, such as below a card or
/// persistently at the bottom of a screen.
///
/// The material button widgets, [ElevatedButton], [TextButton], and
/// [OutlinedButton], are an alternative to action chips, which should appear
/// statically and consistently in a UI.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// {@tool snippet}
///
/// ```dart
/// ActionChip(
/// avatar: CircleAvatar(
/// backgroundColor: Colors.grey.shade800,
/// child: const Text('AB'),
/// ),
/// label: const Text('Aaron Burr'),
/// onPressed: () {
/// print('If you stand for nothing, Burr, what’ll you fall for?');
/// }
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes {
/// Create a chip that acts like a button.
///
/// The [label], [onPressed], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const ActionChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
required this.onPressed,
this.pressElevation,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
}) : assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(
onPressed != null,
'Rather than disabling an ActionChip by setting onPressed to null, '
'remove it from the interface entirely.',
),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final VoidCallback onPressed;
@override
final double? pressElevation;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
onPressed: onPressed,
pressElevation: pressElevation,
tooltip: tooltip,
labelStyle: labelStyle,
backgroundColor: backgroundColor,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
padding: padding,
visualDensity: visualDensity,
labelPadding: labelPadding,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
);
}
}
// 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/widgets.dart';
import 'chip.dart';
import 'chip_theme.dart';
import 'debug.dart';
import 'theme_data.dart';
/// A material design choice chip.
///
/// [ChoiceChip]s represent a single choice from a set. Choice chips contain
/// related descriptive text or categories.
///
/// Requires one of its ancestors to be a [Material] widget. The [selected] and
/// [label] arguments must not be null.
///
/// {@tool snippet}
///
/// ```dart
/// class MyThreeOptions extends StatefulWidget {
/// const MyThreeOptions({Key? key}) : super(key: key);
///
/// @override
/// State<MyThreeOptions> createState() => _MyThreeOptionsState();
/// }
///
/// class _MyThreeOptionsState extends State<MyThreeOptions> {
/// int? _value = 1;
///
/// @override
/// Widget build(BuildContext context) {
/// return Wrap(
/// children: List<Widget>.generate(
/// 3,
/// (int index) {
/// return ChoiceChip(
/// label: Text('Item $index'),
/// selected: _value == index,
/// onSelected: (bool selected) {
/// setState(() {
/// _value = selected ? index : null;
/// });
/// },
/// );
/// },
/// ).toList(),
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class ChoiceChip extends StatelessWidget
implements
ChipAttributes,
SelectableChipAttributes,
DisabledChipAttributes {
/// Create a chip that acts like a radio button.
///
/// The [label], [selected], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const ChoiceChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.onSelected,
this.pressElevation,
required this.selected,
this.selectedColor,
this.disabledColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final ValueChanged<bool>? onSelected;
@override
final double? pressElevation;
@override
final bool selected;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ChipThemeData chipTheme = ChipTheme.of(context);
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle ?? (selected ? chipTheme.secondaryLabelStyle : null),
labelPadding: labelPadding,
onSelected: onSelected,
pressElevation: pressElevation,
selected: selected,
showCheckmark: false,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
disabledColor: disabledColor,
selectedColor: selectedColor ?? chipTheme.secondarySelectedColor,
backgroundColor: backgroundColor,
padding: padding,
visualDensity: visualDensity,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
avatarBorder: avatarBorder,
);
}
}
// 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/widgets.dart';
import 'chip.dart';
import 'debug.dart';
import 'theme_data.dart';
/// A material design filter chip.
///
/// Filter chips use tags or descriptive words as a way to filter content.
///
/// Filter chips are a good alternative to [Checkbox] or [Switch] widgets.
/// Unlike these alternatives, filter chips allow for clearly delineated and
/// exposed options in a compact area.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// {@tool snippet}
///
/// ```dart
/// class ActorFilterEntry {
/// const ActorFilterEntry(this.name, this.initials);
/// final String name;
/// final String initials;
/// }
///
/// class CastFilter extends StatefulWidget {
/// const CastFilter({Key? key}) : super(key: key);
///
/// @override
/// State createState() => CastFilterState();
/// }
///
/// class CastFilterState extends State<CastFilter> {
/// final List<ActorFilterEntry> _cast = <ActorFilterEntry>[
/// const ActorFilterEntry('Aaron Burr', 'AB'),
/// const ActorFilterEntry('Alexander Hamilton', 'AH'),
/// const ActorFilterEntry('Eliza Hamilton', 'EH'),
/// const ActorFilterEntry('James Madison', 'JM'),
/// ];
/// final List<String> _filters = <String>[];
///
/// Iterable<Widget> get actorWidgets {
/// return _cast.map((ActorFilterEntry actor) {
/// return Padding(
/// padding: const EdgeInsets.all(4.0),
/// child: FilterChip(
/// avatar: CircleAvatar(child: Text(actor.initials)),
/// label: Text(actor.name),
/// selected: _filters.contains(actor.name),
/// onSelected: (bool value) {
/// setState(() {
/// if (value) {
/// _filters.add(actor.name);
/// } else {
/// _filters.removeWhere((String name) {
/// return name == actor.name;
/// });
/// }
/// });
/// },
/// ),
/// );
/// });
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// Wrap(
/// children: actorWidgets.toList(),
/// ),
/// Text('Look for: ${_filters.join(', ')}'),
/// ],
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [InputChip], a chip that represents a complex piece of information, such
/// as an entity (person, place, or thing) or conversational text, in a
/// compact form.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class FilterChip extends StatelessWidget
implements
ChipAttributes,
SelectableChipAttributes,
CheckmarkableChipAttributes,
DisabledChipAttributes {
/// Create a chip that acts like a checkbox.
///
/// The [selected], [label], [autofocus], and [clipBehavior] arguments must
/// not be null. The [pressElevation] and [elevation] must be null or
/// non-negative. Typically, [pressElevation] is greater than [elevation].
const FilterChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.selected = false,
required this.onSelected,
this.pressElevation,
this.disabledColor,
this.selectedColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.showCheckmark,
this.checkmarkColor,
this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final bool selected;
@override
final ValueChanged<bool>? onSelected;
@override
final double? pressElevation;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final bool? showCheckmark;
@override
final Color? checkmarkColor;
@override
final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle,
labelPadding: labelPadding,
onSelected: onSelected,
pressElevation: pressElevation,
selected: selected,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
backgroundColor: backgroundColor,
disabledColor: disabledColor,
selectedColor: selectedColor,
padding: padding,
visualDensity: visualDensity,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
showCheckmark: showCheckmark,
checkmarkColor: checkmarkColor,
avatarBorder: avatarBorder,
);
}
}
// 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/widgets.dart';
import 'chip.dart';
import 'debug.dart';
import 'theme_data.dart';
/// A material design input chip.
///
/// Input chips represent a complex piece of information, such as an entity
/// (person, place, or thing) or conversational text, in a compact form.
///
/// Input chips can be made selectable by setting [onSelected], deletable by
/// setting [onDeleted], and pressable like a button with [onPressed]. They have
/// a [label], and they can have a leading icon (see [avatar]) and a trailing
/// icon ([deleteIcon]). Colors and padding can be customized.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// Input chips work together with other UI elements. They can appear:
///
/// * In a [Wrap] widget.
/// * In a horizontally scrollable list, like a [ListView] whose
/// scrollDirection is [Axis.horizontal].
///
/// {@tool snippet}
///
/// ```dart
/// InputChip(
/// avatar: CircleAvatar(
/// backgroundColor: Colors.grey.shade800,
/// child: const Text('AB'),
/// ),
/// label: const Text('Aaron Burr'),
/// onPressed: () {
/// print('I am the one thing in life.');
/// }
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Chip], a chip that displays information and can be deleted.
/// * [ChoiceChip], allows a single selection from a set of options. Choice
/// chips contain related descriptive text or categories.
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
/// * [ActionChip], represents an action related to primary content.
/// * [CircleAvatar], which shows images or initials of people.
/// * [Wrap], A widget that displays its children in multiple horizontal or
/// vertical runs.
/// * <https://material.io/design/components/chips.html>
class InputChip extends StatelessWidget
implements
ChipAttributes,
DeletableChipAttributes,
SelectableChipAttributes,
CheckmarkableChipAttributes,
DisabledChipAttributes,
TappableChipAttributes {
/// Creates an [InputChip].
///
/// The [onPressed] and [onSelected] callbacks must not both be specified at
/// the same time.
///
/// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior]
/// arguments must not be null. The [pressElevation] and [elevation] must be
/// null or non-negative. Typically, [pressElevation] is greater than
/// [elevation].
const InputChip({
Key? key,
this.avatar,
required this.label,
this.labelStyle,
this.labelPadding,
this.selected = false,
this.isEnabled = true,
this.onSelected,
this.deleteIcon,
this.onDeleted,
this.deleteIconColor,
this.deleteButtonTooltipMessage,
this.onPressed,
this.pressElevation,
this.disabledColor,
this.selectedColor,
this.tooltip,
this.side,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.backgroundColor,
this.padding,
this.visualDensity,
this.materialTapTargetSize,
this.elevation,
this.shadowColor,
this.selectedShadowColor,
this.showCheckmark,
this.checkmarkColor,
this.avatarBorder = const CircleBorder(),
@Deprecated(
'Migrate to deleteButtonTooltipMessage. '
'This feature was deprecated after v2.10.0-0.3.pre.'
)
this.useDeleteButtonTooltip = true,
}) : assert(selected != null),
assert(isEnabled != null),
assert(label != null),
assert(clipBehavior != null),
assert(autofocus != null),
assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
super(key: key);
@override
final Widget? avatar;
@override
final Widget label;
@override
final TextStyle? labelStyle;
@override
final EdgeInsetsGeometry? labelPadding;
@override
final bool selected;
@override
final bool isEnabled;
@override
final ValueChanged<bool>? onSelected;
@override
final Widget? deleteIcon;
@override
final VoidCallback? onDeleted;
@override
final Color? deleteIconColor;
@override
final String? deleteButtonTooltipMessage;
@override
final VoidCallback? onPressed;
@override
final double? pressElevation;
@override
final Color? disabledColor;
@override
final Color? selectedColor;
@override
final String? tooltip;
@override
final BorderSide? side;
@override
final OutlinedBorder? shape;
@override
final Clip clipBehavior;
@override
final FocusNode? focusNode;
@override
final bool autofocus;
@override
final Color? backgroundColor;
@override
final EdgeInsetsGeometry? padding;
@override
final VisualDensity? visualDensity;
@override
final MaterialTapTargetSize? materialTapTargetSize;
@override
final double? elevation;
@override
final Color? shadowColor;
@override
final Color? selectedShadowColor;
@override
final bool? showCheckmark;
@override
final Color? checkmarkColor;
@override
final ShapeBorder avatarBorder;
@override
@Deprecated(
'Migrate to deleteButtonTooltipMessage. '
'This feature was deprecated after v2.10.0-0.3.pre.'
)
final bool useDeleteButtonTooltip;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return RawChip(
avatar: avatar,
label: label,
labelStyle: labelStyle,
labelPadding: labelPadding,
deleteIcon: deleteIcon,
onDeleted: onDeleted,
deleteIconColor: deleteIconColor,
useDeleteButtonTooltip: useDeleteButtonTooltip,
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
onSelected: onSelected,
onPressed: onPressed,
pressElevation: pressElevation,
selected: selected,
disabledColor: disabledColor,
selectedColor: selectedColor,
tooltip: tooltip,
side: side,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
autofocus: autofocus,
backgroundColor: backgroundColor,
padding: padding,
visualDensity: visualDensity,
materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
shadowColor: shadowColor,
selectedShadowColor: selectedShadowColor,
showCheckmark: showCheckmark,
checkmarkColor: checkmarkColor,
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
avatarBorder: avatarBorder,
);
}
}
// 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 'package:flutter_test/flutter_test.dart';
/// Adds the basic requirements for a Chip.
Widget wrapForChip({
required Widget child,
TextDirection textDirection = TextDirection.ltr,
double textScaleFactor = 1.0,
Brightness brightness = Brightness.light,
}) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: Directionality(
textDirection: textDirection,
child: MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
child: Material(child: child),
),
),
);
}
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
// There should be two Material widgets, first Material is from the "_wrapForChip" and
// last Material is from the "RawChip".
expect(materials.length, 2);
// The last Material from `RawChip` should have the clip behavior.
expect(materials.last.clipBehavior, clipBehavior);
}
void main() {
testWidgets('ActionChip can be tapped', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: ActionChip(
onPressed: () { },
label: const Text('action chip'),
),
),
),
);
await tester.tap(find.byType(ActionChip));
expect(tester.takeException(), null);
});
testWidgets('ActionChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, onPressed: () { })));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, clipBehavior: Clip.antiAlias, onPressed: () { })));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
}
// 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 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
RenderBox getMaterialBox(WidgetTester tester) {
return tester.firstRenderObject<RenderBox>(
find.descendant(
of: find.byType(RawChip),
matching: find.byType(CustomPaint),
),
);
}
Material getMaterial(WidgetTester tester) {
return tester.widget<Material>(
find.descendant(
of: find.byType(RawChip),
matching: find.byType(Material),
),
);
}
DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) {
return tester.widget(
find.ancestor(
of: find.text(labelText),
matching: find.byType(DefaultTextStyle),
).first,
);
}
/// Adds the basic requirements for a Chip.
Widget wrapForChip({
required Widget child,
TextDirection textDirection = TextDirection.ltr,
double textScaleFactor = 1.0,
Brightness brightness = Brightness.light,
}) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: Directionality(
textDirection: textDirection,
child: MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
child: Material(child: child),
),
),
);
}
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
// There should be two Material widgets, first Material is from the "_wrapForChip" and
// last Material is from the "RawChip".
expect(materials.length, 2);
// The last Material from `RawChip` should have the clip behavior.
expect(materials.last.clipBehavior, clipBehavior);
}
void main() {
testWidgets('ChoiceChip defaults', (WidgetTester tester) async {
Widget buildFrame(Brightness brightness) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: const Scaffold(
body: Center(
child: ChoiceChip(
label: Text('Chip A'),
selected: true,
),
),
),
);
}
await tester.pumpWidget(buildFrame(Brightness.light));
expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xde000000);
await tester.pumpWidget(buildFrame(Brightness.dark));
await tester.pumpAndSettle(); // Theme transition animation
expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xdeffffff);
});
testWidgets('ChoiceChip can be tapped', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: ChoiceChip(
selected: false,
label: Text('choice chip'),
),
),
),
);
await tester.tap(find.byType(ChoiceChip));
expect(tester.takeException(), null);
});
testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false)));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
}
// 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 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
/// Adds the basic requirements for a Chip.
Widget wrapForChip({
required Widget child,
TextDirection textDirection = TextDirection.ltr,
double textScaleFactor = 1.0,
Brightness brightness = Brightness.light,
}) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: Directionality(
textDirection: textDirection,
child: MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
child: Material(child: child),
),
),
);
}
Future<void> pumpCheckmarkChip(
WidgetTester tester, {
required Widget chip,
Color? themeColor,
Brightness brightness = Brightness.light,
}) async {
await tester.pumpWidget(
wrapForChip(
brightness: brightness,
child: Builder(
builder: (BuildContext context) {
final ChipThemeData chipTheme = ChipTheme.of(context);
return ChipTheme(
data: themeColor == null ? chipTheme : chipTheme.copyWith(
checkmarkColor: themeColor,
),
child: chip,
);
},
),
),
);
}
Widget selectedFilterChip({ Color? checkmarkColor }) {
return FilterChip(
label: const Text('InputChip'),
selected: true,
showCheckmark: true,
checkmarkColor: checkmarkColor,
onSelected: (bool _) { },
);
}
void expectCheckmarkColor(Finder finder, Color color) {
expect(
finder,
paints
// The first path that is painted is the selection overlay. We do not care
// how it is painted but it has to be added it to this pattern so that the
// check mark can be checked next.
..path()
// The second path that is painted is the check mark.
..path(color: color),
);
}
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
// There should be two Material widgets, first Material is from the "_wrapForChip" and
// last Material is from the "RawChip".
expect(materials.length, 2);
// The last Material from `RawChip` should have the clip behavior.
expect(materials.last.clipBehavior, clipBehavior);
}
void main() {
testWidgets('FilterChip can be tapped', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: FilterChip(
onSelected: (bool valueChanged) { },
label: const Text('filter chip'),
),
),
),
);
await tester.tap(find.byType(FilterChip));
expect(tester.takeException(), null);
});
testWidgets('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedFilterChip(),
);
expectCheckmarkColor(
find.byType(FilterChip),
Colors.black.withAlpha(0xde),
);
});
testWidgets('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedFilterChip(),
brightness: Brightness.dark,
);
expectCheckmarkColor(
find.byType(FilterChip),
Colors.white.withAlpha(0xde),
);
});
testWidgets('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedFilterChip(),
themeColor: const Color(0xff00ff00),
);
expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xff00ff00),
);
});
testWidgets('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedFilterChip(checkmarkColor: const Color(0xff00ff00)),
);
expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xff00ff00),
);
});
testWidgets('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedFilterChip(checkmarkColor: const Color(0xffff0000)),
themeColor: const Color(0xff00ff00),
);
expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xffff0000),
);
});
testWidgets('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { })));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { }, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
}
// 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 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
/// Adds the basic requirements for a Chip.
Widget wrapForChip({
required Widget child,
TextDirection textDirection = TextDirection.ltr,
double textScaleFactor = 1.0,
Brightness brightness = Brightness.light,
}) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: Directionality(
textDirection: textDirection,
child: MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
child: Material(child: child),
),
),
);
}
Widget selectedInputChip({ Color? checkmarkColor }) {
return InputChip(
label: const Text('InputChip'),
selected: true,
showCheckmark: true,
checkmarkColor: checkmarkColor,
);
}
Future<void> pumpCheckmarkChip(
WidgetTester tester, {
required Widget chip,
Color? themeColor,
Brightness brightness = Brightness.light,
}) async {
await tester.pumpWidget(
wrapForChip(
brightness: brightness,
child: Builder(
builder: (BuildContext context) {
final ChipThemeData chipTheme = ChipTheme.of(context);
return ChipTheme(
data: themeColor == null ? chipTheme : chipTheme.copyWith(
checkmarkColor: themeColor,
),
child: chip,
);
},
),
),
);
}
void expectCheckmarkColor(Finder finder, Color color) {
expect(
finder,
paints
// The first path that is painted is the selection overlay. We do not care
// how it is painted but it has to be added it to this pattern so that the
// check mark can be checked next.
..path()
// The second path that is painted is the check mark.
..path(color: color),
);
}
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
// There should be two Material widgets, first Material is from the "_wrapForChip" and
// last Material is from the "RawChip".
expect(materials.length, 2);
// The last Material from `RawChip` should have the clip behavior.
expect(materials.last.clipBehavior, clipBehavior);
}
void main() {
testWidgets('InputChip can be tapped', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: InputChip(
label: Text('input chip'),
),
),
),
);
await tester.tap(find.byType(InputChip));
expect(tester.takeException(), null);
});
testWidgets('loses focus when disabled', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'InputChip');
await tester.pumpWidget(
wrapForChip(
child: InputChip(
focusNode: focusNode,
autofocus: true,
shape: const RoundedRectangleBorder(),
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
onPressed: () { },
),
),
);
await tester.pump();
expect(focusNode.hasPrimaryFocus, isTrue);
await tester.pumpWidget(
wrapForChip(
child: InputChip(
focusNode: focusNode,
autofocus: true,
shape: const RoundedRectangleBorder(),
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
),
),
);
await tester.pump();
expect(focusNode.hasPrimaryFocus, isFalse);
});
testWidgets('cannot be traversed to when disabled', (WidgetTester tester) async {
final FocusNode focusNode1 = FocusNode(debugLabel: 'InputChip 1');
final FocusNode focusNode2 = FocusNode(debugLabel: 'InputChip 2');
await tester.pumpWidget(
wrapForChip(
child: Column(
children: <Widget>[
InputChip(
focusNode: focusNode1,
autofocus: true,
label: const Text('Chip A'),
onPressed: () { },
),
InputChip(
focusNode: focusNode2,
autofocus: true,
label: const Text('Chip B'),
),
],
),
),
);
await tester.pump();
expect(focusNode1.hasPrimaryFocus, isTrue);
expect(focusNode2.hasPrimaryFocus, isFalse);
expect(focusNode1.nextFocus(), isTrue);
await tester.pump();
expect(focusNode1.hasPrimaryFocus, isTrue);
expect(focusNode2.hasPrimaryFocus, isFalse);
});
testWidgets('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedInputChip(),
);
expectCheckmarkColor(
find.byType(InputChip),
Colors.black.withAlpha(0xde),
);
});
testWidgets('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedInputChip(),
brightness: Brightness.dark,
);
expectCheckmarkColor(
find.byType(InputChip),
Colors.white.withAlpha(0xde),
);
});
testWidgets('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedInputChip(),
themeColor: const Color(0xff00ff00),
);
expectCheckmarkColor(
find.byType(InputChip),
const Color(0xff00ff00),
);
});
testWidgets('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedInputChip(checkmarkColor: const Color(0xff00ff00)),
);
expectCheckmarkColor(
find.byType(InputChip),
const Color(0xff00ff00),
);
});
testWidgets('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
await pumpCheckmarkChip(
tester,
chip: selectedInputChip(checkmarkColor: const Color(0xffff0000)),
themeColor: const Color(0xff00ff00),
);
expectCheckmarkColor(
find.byType(InputChip),
const Color(0xffff0000),
);
});
testWidgets('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(wrapForChip(child: const InputChip(label: label)));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(wrapForChip(child: const InputChip(label: label, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
}
...@@ -71,7 +71,7 @@ double getDeleteDrawerProgress(WidgetTester tester) => getRenderChip(tester)?.de ...@@ -71,7 +71,7 @@ double getDeleteDrawerProgress(WidgetTester tester) => getRenderChip(tester)?.de
double getEnableProgress(WidgetTester tester) => getRenderChip(tester)?.enableAnimation?.value as double; double getEnableProgress(WidgetTester tester) => getRenderChip(tester)?.enableAnimation?.value as double;
/// Adds the basic requirements for a Chip. /// Adds the basic requirements for a Chip.
Widget _wrapForChip({ Widget wrapForChip({
required Widget child, required Widget child,
TextDirection textDirection = TextDirection.ltr, TextDirection textDirection = TextDirection.ltr,
double textScaleFactor = 1.0, double textScaleFactor = 1.0,
...@@ -93,7 +93,7 @@ Widget _wrapForChip({ ...@@ -93,7 +93,7 @@ Widget _wrapForChip({
/// further constraining the size of its child, the label widget. /// further constraining the size of its child, the label widget.
/// Optionally, adding an avatar or delete icon to the chip should not /// Optionally, adding an avatar or delete icon to the chip should not
/// cause the chip or label to exceed its constrained height. /// cause the chip or label to exceed its constrained height.
Future<void> _testConstrainedLabel( Future<void> testConstrainedLabel(
WidgetTester tester, { WidgetTester tester, {
CircleAvatar? avatar, CircleAvatar? avatar,
VoidCallback? onDeleted, VoidCallback? onDeleted,
...@@ -105,7 +105,7 @@ Future<void> _testConstrainedLabel( ...@@ -105,7 +105,7 @@ Future<void> _testConstrainedLabel(
final Key labelKey = UniqueKey(); final Key labelKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Center( child: Center(
child: SizedBox( child: SizedBox(
width: chipParentWidth, width: chipParentWidth,
...@@ -133,65 +133,9 @@ Future<void> _testConstrainedLabel( ...@@ -133,65 +133,9 @@ Future<void> _testConstrainedLabel(
expect(chipSize.height, chipParentHeight); expect(chipSize.height, chipParentHeight);
} }
Widget _selectedInputChip({ Color? checkmarkColor }) { void doNothing() {}
return InputChip(
label: const Text('InputChip'),
selected: true,
showCheckmark: true,
checkmarkColor: checkmarkColor,
);
}
Widget _selectedFilterChip({ Color? checkmarkColor }) {
return FilterChip(
label: const Text('InputChip'),
selected: true,
showCheckmark: true,
checkmarkColor: checkmarkColor,
onSelected: (bool _) { },
);
}
Future<void> _pumpCheckmarkChip(
WidgetTester tester, {
required Widget chip,
Color? themeColor,
Brightness brightness = Brightness.light,
}) async {
await tester.pumpWidget(
_wrapForChip(
brightness: brightness,
child: Builder(
builder: (BuildContext context) {
final ChipThemeData chipTheme = ChipTheme.of(context);
return ChipTheme(
data: themeColor == null ? chipTheme : chipTheme.copyWith(
checkmarkColor: themeColor,
),
child: chip,
);
},
),
),
);
}
void _expectCheckmarkColor(Finder finder, Color color) { Widget chipWithOptionalDeleteButton({
expect(
finder,
paints
// The first path that is painted is the selection overlay. We do not care
// how it is painted but it has to be added it to this pattern so that the
// check mark can be checked next.
..path()
// The second path that is painted is the check mark.
..path(color: color),
);
}
void _doNothing() {}
Widget _chipWithOptionalDeleteButton({
Key? deleteButtonKey, Key? deleteButtonKey,
Key? labelKey, Key? labelKey,
required bool deletable, required bool deletable,
...@@ -199,16 +143,16 @@ Widget _chipWithOptionalDeleteButton({ ...@@ -199,16 +143,16 @@ Widget _chipWithOptionalDeleteButton({
bool useDeleteButtonTooltip = true, bool useDeleteButtonTooltip = true,
String? chipTooltip, String? chipTooltip,
String? deleteButtonTooltipMessage, String? deleteButtonTooltipMessage,
VoidCallback? onPressed = _doNothing, VoidCallback? onPressed = doNothing,
}) { }) {
return _wrapForChip( return wrapForChip(
textDirection: textDirection, textDirection: textDirection,
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
RawChip( RawChip(
tooltip: chipTooltip, tooltip: chipTooltip,
onPressed: onPressed, onPressed: onPressed,
onDeleted: deletable ? _doNothing : null, onDeleted: deletable ? doNothing : null,
deleteIcon: Icon(Icons.close, key: deleteButtonKey), deleteIcon: Icon(Icons.close, key: deleteButtonKey),
useDeleteButtonTooltip: useDeleteButtonTooltip, useDeleteButtonTooltip: useDeleteButtonTooltip,
deleteButtonTooltipMessage: deleteButtonTooltipMessage, deleteButtonTooltipMessage: deleteButtonTooltipMessage,
...@@ -347,44 +291,11 @@ void main() { ...@@ -347,44 +291,11 @@ void main() {
expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing); expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing);
}); });
testWidgets('ChoiceChip defaults', (WidgetTester tester) async {
Widget buildFrame(Brightness brightness) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: const Scaffold(
body: Center(
child: ChoiceChip(
label: Text('Chip A'),
selected: true,
),
),
),
);
}
await tester.pumpWidget(buildFrame(Brightness.light));
expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xde000000);
await tester.pumpWidget(buildFrame(Brightness.dark));
await tester.pumpAndSettle(); // Theme transition animation
expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xdeffffff);
});
testWidgets('Chip control test', (WidgetTester tester) async { testWidgets('Chip control test', (WidgetTester tester) async {
final FeedbackTester feedback = FeedbackTester(); final FeedbackTester feedback = FeedbackTester();
final List<String> deletedChipLabels = <String>[]; final List<String> deletedChipLabels = <String>[];
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -438,7 +349,7 @@ void main() { ...@@ -438,7 +349,7 @@ void main() {
final Key labelKey = UniqueKey(); final Key labelKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Center( child: Center(
child: SizedBox( child: SizedBox(
width: 500.0, width: 500.0,
...@@ -469,7 +380,7 @@ void main() { ...@@ -469,7 +380,7 @@ void main() {
'Chip constrains the size of the label widget when it exceeds the ' 'Chip constrains the size of the label widget when it exceeds the '
'available space', 'available space',
(WidgetTester tester) async { (WidgetTester tester) async {
await _testConstrainedLabel(tester); await testConstrainedLabel(tester);
}, },
); );
...@@ -477,7 +388,7 @@ void main() { ...@@ -477,7 +388,7 @@ void main() {
'Chip constrains the size of the label widget when it exceeds the ' 'Chip constrains the size of the label widget when it exceeds the '
'available space and the avatar is present', 'available space and the avatar is present',
(WidgetTester tester) async { (WidgetTester tester) async {
await _testConstrainedLabel( await testConstrainedLabel(
tester, tester,
avatar: const CircleAvatar(child: Text('A')), avatar: const CircleAvatar(child: Text('A')),
); );
...@@ -488,7 +399,7 @@ void main() { ...@@ -488,7 +399,7 @@ void main() {
'Chip constrains the size of the label widget when it exceeds the ' 'Chip constrains the size of the label widget when it exceeds the '
'available space and the delete icon is present', 'available space and the delete icon is present',
(WidgetTester tester) async { (WidgetTester tester) async {
await _testConstrainedLabel( await testConstrainedLabel(
tester, tester,
onDeleted: () { }, onDeleted: () { },
); );
...@@ -499,7 +410,7 @@ void main() { ...@@ -499,7 +410,7 @@ void main() {
'Chip constrains the size of the label widget when it exceeds the ' 'Chip constrains the size of the label widget when it exceeds the '
'available space and both avatar and delete icons are present', 'available space and both avatar and delete icons are present',
(WidgetTester tester) async { (WidgetTester tester) async {
await _testConstrainedLabel( await testConstrainedLabel(
tester, tester,
avatar: const CircleAvatar(child: Text('A')), avatar: const CircleAvatar(child: Text('A')),
onDeleted: () { }, onDeleted: () { },
...@@ -585,7 +496,7 @@ void main() { ...@@ -585,7 +496,7 @@ void main() {
testWidgets('Chip in row works ok', (WidgetTester tester) async { testWidgets('Chip in row works ok', (WidgetTester tester) async {
const TextStyle style = TextStyle(fontFamily: 'Ahem', fontSize: 10.0); const TextStyle style = TextStyle(fontFamily: 'Ahem', fontSize: 10.0);
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Row( child: Row(
children: const <Widget>[ children: const <Widget>[
Chip(label: Text('Test'), labelStyle: style), Chip(label: Text('Test'), labelStyle: style),
...@@ -596,7 +507,7 @@ void main() { ...@@ -596,7 +507,7 @@ void main() {
expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0)); expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0));
expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0)); expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0));
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Row( child: Row(
children: const <Widget>[ children: const <Widget>[
Flexible(child: Chip(label: Text('Test'), labelStyle: style)), Flexible(child: Chip(label: Text('Test'), labelStyle: style)),
...@@ -607,7 +518,7 @@ void main() { ...@@ -607,7 +518,7 @@ void main() {
expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0)); expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0));
expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0)); expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0));
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Row( child: Row(
children: const <Widget>[ children: const <Widget>[
Expanded(child: Chip(label: Text('Test'), labelStyle: style)), Expanded(child: Chip(label: Text('Test'), labelStyle: style)),
...@@ -621,7 +532,7 @@ void main() { ...@@ -621,7 +532,7 @@ void main() {
testWidgets('Chip responds to materialTapTargetSize', (WidgetTester tester) async { testWidgets('Chip responds to materialTapTargetSize', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: const <Widget>[ children: const <Widget>[
Chip( Chip(
...@@ -645,7 +556,7 @@ void main() { ...@@ -645,7 +556,7 @@ void main() {
final UniqueKey deleteKey = UniqueKey(); final UniqueKey deleteKey = UniqueKey();
bool calledDelete = false; bool calledDelete = false;
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -670,7 +581,7 @@ void main() { ...@@ -670,7 +581,7 @@ void main() {
calledDelete = false; calledDelete = false;
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -719,7 +630,7 @@ void main() { ...@@ -719,7 +630,7 @@ void main() {
); );
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: test, child: test,
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
), ),
...@@ -727,7 +638,7 @@ void main() { ...@@ -727,7 +638,7 @@ void main() {
await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(const Duration(milliseconds: 500));
expect(tester.getCenter(find.text('ABC')).dx, greaterThan(tester.getCenter(find.byKey(iconKey)).dx)); expect(tester.getCenter(find.text('ABC')).dx, greaterThan(tester.getCenter(find.byKey(iconKey)).dx));
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: test, child: test,
), ),
); );
...@@ -737,7 +648,7 @@ void main() { ...@@ -737,7 +648,7 @@ void main() {
testWidgets('Chip responds to textScaleFactor', (WidgetTester tester) async { testWidgets('Chip responds to textScaleFactor', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: const <Widget>[ children: const <Widget>[
Chip( Chip(
...@@ -767,7 +678,7 @@ void main() { ...@@ -767,7 +678,7 @@ void main() {
expect(tester.getSize(find.byType(Chip).last), anyOf(const Size(132.0, 48.0), const Size(131.0, 48.0))); expect(tester.getSize(find.byType(Chip).last), anyOf(const Size(132.0, 48.0), const Size(131.0, 48.0)));
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
textScaleFactor: 3.0, textScaleFactor: 3.0,
child: Column( child: Column(
children: const <Widget>[ children: const <Widget>[
...@@ -795,7 +706,7 @@ void main() { ...@@ -795,7 +706,7 @@ void main() {
// Check that individual text scales are taken into account. // Check that individual text scales are taken into account.
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: const <Widget>[ children: const <Widget>[
Chip( Chip(
...@@ -824,7 +735,7 @@ void main() { ...@@ -824,7 +735,7 @@ void main() {
final Key keyA = GlobalKey(); final Key keyA = GlobalKey();
final Key keyB = GlobalKey(); final Key keyB = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -857,7 +768,7 @@ void main() { ...@@ -857,7 +768,7 @@ void main() {
testWidgets('Avatars can be non-circle avatar widgets', (WidgetTester tester) async { testWidgets('Avatars can be non-circle avatar widgets', (WidgetTester tester) async {
final Key keyA = GlobalKey(); final Key keyA = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -875,7 +786,7 @@ void main() { ...@@ -875,7 +786,7 @@ void main() {
testWidgets('Delete icons can be non-icon widgets', (WidgetTester tester) async { testWidgets('Delete icons can be non-icon widgets', (WidgetTester tester) async {
final Key keyA = GlobalKey(); final Key keyA = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -895,7 +806,7 @@ void main() { ...@@ -895,7 +806,7 @@ void main() {
final GlobalKey keyA = GlobalKey(); final GlobalKey keyA = GlobalKey();
final GlobalKey keyB = GlobalKey(); final GlobalKey keyB = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Overlay( child: Overlay(
initialEntries: <OverlayEntry>[ initialEntries: <OverlayEntry>[
OverlayEntry( OverlayEntry(
...@@ -931,7 +842,7 @@ void main() { ...@@ -931,7 +842,7 @@ void main() {
final GlobalKey keyA = GlobalKey(); final GlobalKey keyA = GlobalKey();
final GlobalKey keyB = GlobalKey(); final GlobalKey keyB = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Overlay( child: Overlay(
initialEntries: <OverlayEntry>[ initialEntries: <OverlayEntry>[
...@@ -969,7 +880,7 @@ void main() { ...@@ -969,7 +880,7 @@ void main() {
final GlobalKey labelKey = GlobalKey(); final GlobalKey labelKey = GlobalKey();
Future<void> pushChip({ Widget? avatar }) async { Future<void> pushChip({ Widget? avatar }) async {
return tester.pumpWidget( return tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
RawChip( RawChip(
...@@ -1083,7 +994,7 @@ void main() { ...@@ -1083,7 +994,7 @@ void main() {
bool wasDeleted = false; bool wasDeleted = false;
Future<void> pushChip({ bool deletable = false }) async { Future<void> pushChip({ bool deletable = false }) async {
return tester.pumpWidget( return tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
StatefulBuilder(builder: (BuildContext context, StateSetter setState) { StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
...@@ -1199,7 +1110,7 @@ void main() { ...@@ -1199,7 +1110,7 @@ void main() {
bool deletePressed = false; bool deletePressed = false;
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
RawChip( RawChip(
...@@ -1234,7 +1145,7 @@ void main() { ...@@ -1234,7 +1145,7 @@ void main() {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
...@@ -1283,7 +1194,7 @@ void main() { ...@@ -1283,7 +1194,7 @@ void main() {
final GlobalKey deleteButtonKey = GlobalKey(); final GlobalKey deleteButtonKey = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
...@@ -1316,7 +1227,7 @@ void main() { ...@@ -1316,7 +1227,7 @@ void main() {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
...@@ -1369,7 +1280,7 @@ void main() { ...@@ -1369,7 +1280,7 @@ void main() {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
onPressed: null, onPressed: null,
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
...@@ -1424,7 +1335,7 @@ void main() { ...@@ -1424,7 +1335,7 @@ void main() {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
...@@ -1453,7 +1364,7 @@ void main() { ...@@ -1453,7 +1364,7 @@ void main() {
final UniqueKey labelKey = UniqueKey(); final UniqueKey labelKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
labelKey: labelKey, labelKey: labelKey,
deletable: false, deletable: false,
), ),
...@@ -1507,7 +1418,7 @@ void main() { ...@@ -1507,7 +1418,7 @@ void main() {
final UniqueKey labelKey = UniqueKey(); final UniqueKey labelKey = UniqueKey();
Future<void> pushChip({ Widget? avatar, bool selectable = false }) async { Future<void> pushChip({ Widget? avatar, bool selectable = false }) async {
return tester.pumpWidget( return tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
StatefulBuilder(builder: (BuildContext context, StateSetter setState) { StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
...@@ -1587,7 +1498,7 @@ void main() { ...@@ -1587,7 +1498,7 @@ void main() {
final UniqueKey labelKey = UniqueKey(); final UniqueKey labelKey = UniqueKey();
Future<void> pushChip({ bool selectable = false }) async { Future<void> pushChip({ bool selectable = false }) async {
return tester.pumpWidget( return tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
StatefulBuilder(builder: (BuildContext context, StateSetter setState) { StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
...@@ -1660,7 +1571,7 @@ void main() { ...@@ -1660,7 +1571,7 @@ void main() {
final UniqueKey labelKey = UniqueKey(); final UniqueKey labelKey = UniqueKey();
Future<void> pushChip({ Widget? avatar, bool selectable = false }) async { Future<void> pushChip({ Widget? avatar, bool selectable = false }) async {
return tester.pumpWidget( return tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Wrap( child: Wrap(
children: <Widget>[ children: <Widget>[
StatefulBuilder(builder: (BuildContext context, StateSetter setState) { StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
...@@ -1719,7 +1630,7 @@ void main() { ...@@ -1719,7 +1630,7 @@ void main() {
final ChipThemeData chipTheme = theme.chipTheme; final ChipThemeData chipTheme = theme.chipTheme;
Widget buildChip(ChipThemeData data) { Widget buildChip(ChipThemeData data) {
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: theme, data: theme,
child: const InputChip( child: const InputChip(
...@@ -1748,7 +1659,7 @@ void main() { ...@@ -1748,7 +1659,7 @@ void main() {
); );
Widget buildChip() { Widget buildChip() {
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: theme, data: theme,
child: const Chip( child: const Chip(
...@@ -1769,7 +1680,7 @@ void main() { ...@@ -1769,7 +1680,7 @@ void main() {
testWidgets('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async { testWidgets('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async {
Widget buildChip() { Widget buildChip() {
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: ThemeData.light().copyWith( data: ThemeData.light().copyWith(
chipTheme: const ChipThemeData( chipTheme: const ChipThemeData(
...@@ -1789,7 +1700,7 @@ void main() { ...@@ -1789,7 +1700,7 @@ void main() {
testWidgets('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async { testWidgets('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async {
Widget buildChip() { Widget buildChip() {
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: ThemeData(fontFamily: 'MyFont'), data: ThemeData(fontFamily: 'MyFont'),
child: const DefaultTextStyle( child: const DefaultTextStyle(
...@@ -1814,7 +1725,7 @@ void main() { ...@@ -1814,7 +1725,7 @@ void main() {
testWidgets('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { testWidgets('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async {
final Key key1 = UniqueKey(); final Key key1 = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Theme( child: Theme(
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded), data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded),
child: Center( child: Center(
...@@ -1831,7 +1742,7 @@ void main() { ...@@ -1831,7 +1742,7 @@ void main() {
final Key key2 = UniqueKey(); final Key key2 = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Theme( child: Theme(
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap),
child: Center( child: Center(
...@@ -1868,7 +1779,7 @@ void main() { ...@@ -1868,7 +1779,7 @@ void main() {
bool showCheckmark = true, bool showCheckmark = true,
}) { }) {
chipTheme ??= defaultChipTheme; chipTheme ??= defaultChipTheme;
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: themeData, data: themeData,
child: ChipTheme( child: ChipTheme(
...@@ -2450,7 +2361,7 @@ void main() { ...@@ -2450,7 +2361,7 @@ void main() {
testWidgets('can be tapped outside of chip delete icon', (WidgetTester tester) async { testWidgets('can be tapped outside of chip delete icon', (WidgetTester tester) async {
bool deleted = false; bool deleted = false;
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Chip( Chip(
...@@ -2474,20 +2385,6 @@ void main() { ...@@ -2474,20 +2385,6 @@ void main() {
}); });
testWidgets('Chips can be tapped', (WidgetTester tester) async { testWidgets('Chips can be tapped', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: ChoiceChip(
selected: false,
label: Text('choice chip'),
),
),
),
);
await tester.tap(find.byType(ChoiceChip));
expect(tester.takeException(), null);
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Material( home: Material(
...@@ -2500,47 +2397,6 @@ void main() { ...@@ -2500,47 +2397,6 @@ void main() {
await tester.tap(find.byType(RawChip)); await tester.tap(find.byType(RawChip));
expect(tester.takeException(), null); expect(tester.takeException(), null);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: ActionChip(
onPressed: () { },
label: const Text('action chip'),
),
),
),
);
await tester.tap(find.byType(ActionChip));
expect(tester.takeException(), null);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: FilterChip(
onSelected: (bool valueChanged) { },
label: const Text('filter chip'),
),
),
),
);
await tester.tap(find.byType(FilterChip));
expect(tester.takeException(), null);
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: InputChip(
label: Text('input chip'),
),
),
),
);
await tester.tap(find.byType(InputChip));
expect(tester.takeException(), null);
}); });
testWidgets('Chip elevation and shadow color work correctly', (WidgetTester tester) async { testWidgets('Chip elevation and shadow color work correctly', (WidgetTester tester) async {
...@@ -2554,7 +2410,7 @@ void main() { ...@@ -2554,7 +2410,7 @@ void main() {
InputChip inputChip = const InputChip(label: Text('Label')); InputChip inputChip = const InputChip(label: Text('Label'));
Widget buildChip(ChipThemeData data) { Widget buildChip(ChipThemeData data) {
return _wrapForChip( return wrapForChip(
child: Theme( child: Theme(
data: theme, data: theme,
child: inputChip, child: inputChip,
...@@ -2596,7 +2452,7 @@ void main() { ...@@ -2596,7 +2452,7 @@ void main() {
testWidgets('can be tapped outside of chip body', (WidgetTester tester) async { testWidgets('can be tapped outside of chip body', (WidgetTester tester) async {
bool pressed = false; bool pressed = false;
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
InputChip( InputChip(
...@@ -2620,7 +2476,7 @@ void main() { ...@@ -2620,7 +2476,7 @@ void main() {
testWidgets('is hitTestable', (WidgetTester tester) async { testWidgets('is hitTestable', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
_wrapForChip( wrapForChip(
child: InputChip( child: InputChip(
shape: const RoundedRectangleBorder(), shape: const RoundedRectangleBorder(),
avatar: const CircleAvatar(child: Text('A')), avatar: const CircleAvatar(child: Text('A')),
...@@ -2641,51 +2497,15 @@ void main() { ...@@ -2641,51 +2497,15 @@ void main() {
testWidgets('Chip clipBehavior properly passes through to the Material', (WidgetTester tester) async { testWidgets('Chip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label'); const Text label = Text('label');
await tester.pumpWidget(_wrapForChip(child: const Chip(label: label))); await tester.pumpWidget(wrapForChip(child: const Chip(label: label)));
checkChipMaterialClipBehavior(tester, Clip.none); checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(_wrapForChip(child: const Chip(label: label, clipBehavior: Clip.antiAlias))); await tester.pumpWidget(wrapForChip(child: const Chip(label: label, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(_wrapForChip(child: const ChoiceChip(label: label, selected: false)));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(_wrapForChip(child: const ChoiceChip(label: label, selected: false, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
testWidgets('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(_wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { })));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(_wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { }, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
testWidgets('ActionChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(_wrapForChip(child: ActionChip(label: label, onPressed: () { })));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(_wrapForChip(child: ActionChip(label: label, clipBehavior: Clip.antiAlias, onPressed: () { })));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
testWidgets('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
const Text label = Text('label');
await tester.pumpWidget(_wrapForChip(child: const InputChip(label: label)));
checkChipMaterialClipBehavior(tester, Clip.none);
await tester.pumpWidget(_wrapForChip(child: const InputChip(label: label, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias); checkChipMaterialClipBehavior(tester, Clip.antiAlias);
}); });
testWidgets('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async { testWidgets('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async {
await tester.pumpWidget(_wrapForChip(child: const FilterChip( await tester.pumpWidget(wrapForChip(child: const FilterChip(
avatar: CircleAvatar(child: Text('t')), avatar: CircleAvatar(child: Text('t')),
label: Text('test'), label: Text('test'),
selected: true, selected: true,
...@@ -3198,71 +3018,6 @@ void main() { ...@@ -3198,71 +3018,6 @@ void main() {
expect(find.byType(RawChip), paints..drrect(color: selectedBorderSide.color)); expect(find.byType(RawChip), paints..drrect(color: selectedBorderSide.color));
}); });
testWidgets('loses focus when disabled', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'InputChip');
await tester.pumpWidget(
_wrapForChip(
child: InputChip(
focusNode: focusNode,
autofocus: true,
shape: const RoundedRectangleBorder(),
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
onPressed: () { },
),
),
);
await tester.pump();
expect(focusNode.hasPrimaryFocus, isTrue);
await tester.pumpWidget(
_wrapForChip(
child: InputChip(
focusNode: focusNode,
autofocus: true,
shape: const RoundedRectangleBorder(),
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
),
),
);
await tester.pump();
expect(focusNode.hasPrimaryFocus, isFalse);
});
testWidgets('cannot be traversed to when disabled', (WidgetTester tester) async {
final FocusNode focusNode1 = FocusNode(debugLabel: 'InputChip 1');
final FocusNode focusNode2 = FocusNode(debugLabel: 'InputChip 2');
await tester.pumpWidget(
_wrapForChip(
child: Column(
children: <Widget>[
InputChip(
focusNode: focusNode1,
autofocus: true,
label: const Text('Chip A'),
onPressed: () { },
),
InputChip(
focusNode: focusNode2,
autofocus: true,
label: const Text('Chip B'),
),
],
),
),
);
await tester.pump();
expect(focusNode1.hasPrimaryFocus, isTrue);
expect(focusNode2.hasPrimaryFocus, isFalse);
expect(focusNode1.nextFocus(), isTrue);
await tester.pump();
expect(focusNode1.hasPrimaryFocus, isTrue);
expect(focusNode2.hasPrimaryFocus, isFalse);
});
testWidgets('Chip responds to density changes.', (WidgetTester tester) async { testWidgets('Chip responds to density changes.', (WidgetTester tester) async {
const Key key = Key('test'); const Key key = Key('test');
const Key textKey = Key('test text'); const Key textKey = Key('test text');
...@@ -3368,135 +3123,9 @@ void main() { ...@@ -3368,135 +3123,9 @@ void main() {
expect(box.size, equals(const Size(128, 24.0 + 16.0))); expect(box.size, equals(const Size(128, 24.0 + 16.0)));
}); });
testWidgets('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedInputChip(),
);
_expectCheckmarkColor(
find.byType(InputChip),
Colors.black.withAlpha(0xde),
);
});
testWidgets('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedFilterChip(),
);
_expectCheckmarkColor(
find.byType(FilterChip),
Colors.black.withAlpha(0xde),
);
});
testWidgets('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedInputChip(),
brightness: Brightness.dark,
);
_expectCheckmarkColor(
find.byType(InputChip),
Colors.white.withAlpha(0xde),
);
});
testWidgets('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedFilterChip(),
brightness: Brightness.dark,
);
_expectCheckmarkColor(
find.byType(FilterChip),
Colors.white.withAlpha(0xde),
);
});
testWidgets('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedInputChip(),
themeColor: const Color(0xff00ff00),
);
_expectCheckmarkColor(
find.byType(InputChip),
const Color(0xff00ff00),
);
});
testWidgets('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedFilterChip(),
themeColor: const Color(0xff00ff00),
);
_expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xff00ff00),
);
});
testWidgets('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedInputChip(checkmarkColor: const Color(0xff00ff00)),
);
_expectCheckmarkColor(
find.byType(InputChip),
const Color(0xff00ff00),
);
});
testWidgets('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedFilterChip(checkmarkColor: const Color(0xff00ff00)),
);
_expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xff00ff00),
);
});
testWidgets('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedInputChip(checkmarkColor: const Color(0xffff0000)),
themeColor: const Color(0xff00ff00),
);
_expectCheckmarkColor(
find.byType(InputChip),
const Color(0xffff0000),
);
});
testWidgets('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
await _pumpCheckmarkChip(
tester,
chip: _selectedFilterChip(checkmarkColor: const Color(0xffff0000)),
themeColor: const Color(0xff00ff00),
);
_expectCheckmarkColor(
find.byType(FilterChip),
const Color(0xffff0000),
);
});
testWidgets('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async { testWidgets('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
deletable: true, deletable: true,
useDeleteButtonTooltip: false, useDeleteButtonTooltip: false,
), ),
...@@ -3522,7 +3151,7 @@ void main() { ...@@ -3522,7 +3151,7 @@ void main() {
testWidgets('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async { testWidgets('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
deleteButtonTooltipMessage: '', deleteButtonTooltipMessage: '',
...@@ -3547,7 +3176,7 @@ void main() { ...@@ -3547,7 +3176,7 @@ void main() {
testWidgets('Disabling delete button tooltip does not disable chip tooltip', (WidgetTester tester) async { testWidgets('Disabling delete button tooltip does not disable chip tooltip', (WidgetTester tester) async {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
deleteButtonTooltipMessage: '', deleteButtonTooltipMessage: '',
...@@ -3575,7 +3204,7 @@ void main() { ...@@ -3575,7 +3204,7 @@ void main() {
testWidgets('Triggering delete button tooltip does not trigger Chip tooltip', (WidgetTester tester) async { testWidgets('Triggering delete button tooltip does not trigger Chip tooltip', (WidgetTester tester) async {
final UniqueKey deleteButtonKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
_chipWithOptionalDeleteButton( chipWithOptionalDeleteButton(
deleteButtonKey: deleteButtonKey, deleteButtonKey: deleteButtonKey,
deletable: true, deletable: true,
chipTooltip: 'Chip Tooltip', chipTooltip: 'Chip Tooltip',
...@@ -3601,7 +3230,7 @@ void main() { ...@@ -3601,7 +3230,7 @@ void main() {
testWidgets('intrinsicHeight implementation meets constraints', (WidgetTester tester) async { testWidgets('intrinsicHeight implementation meets constraints', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/49478. // Regression test for https://github.com/flutter/flutter/issues/49478.
await tester.pumpWidget(_wrapForChip( await tester.pumpWidget(wrapForChip(
child: const Chip( child: const Chip(
label: Text('text'), label: Text('text'),
padding: EdgeInsets.symmetric(horizontal: 20), padding: EdgeInsets.symmetric(horizontal: 20),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment