mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
Widget state properties (#142151)
Fixes #138270. Moves the majority of the logic of MaterialStateProperties down to the widgets layer, then has the existing Material classes pull from the widgets versions.
This commit is contained in:
parent
3236957f02
commit
6190c5eea1
|
@ -358,13 +358,13 @@ class _TextButtonExampleState extends State<TextButtonExample> {
|
|||
},
|
||||
style: TextButton.styleFrom(
|
||||
overlayColor: Colors.transparent,
|
||||
foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
|
||||
foregroundBuilder: (BuildContext context, Set<WidgetState> states, Widget? child) {
|
||||
late final ImageProvider image;
|
||||
if (currentAction != null) {
|
||||
image = runningImage;
|
||||
} else if (states.contains(MaterialState.pressed)) {
|
||||
} else if (states.contains(WidgetState.pressed)) {
|
||||
image = pressedImage;
|
||||
} else if (states.contains(MaterialState.hovered)) {
|
||||
} else if (states.contains(WidgetState.hovered)) {
|
||||
image = hoveredImage;
|
||||
} else {
|
||||
image = defaultImage;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/15303
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * Material (general): fix_material.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * Material (general): fix_material.yaml
|
||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * ThemeData: fix_theme_data.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/48547
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
# * Material (general): fix_material.yaml
|
||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * WidgetState: fix_widget_state.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/87281
|
||||
|
|
129
packages/flutter/lib/fix_data/fix_material/fix_widget_state.yaml
Normal file
129
packages/flutter/lib/fix_data/fix_material/fix_widget_state.yaml
Normal file
|
@ -0,0 +1,129 @@
|
|||
# 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.
|
||||
|
||||
# For details regarding the *Flutter Fix* feature, see
|
||||
# https://flutter.dev/docs/development/tools/flutter-fix
|
||||
|
||||
# Please add new fixes to the top of the file, separated by one blank line
|
||||
# from other fixes. In a comment, include a link to the PR where the change
|
||||
# requiring the fix was made.
|
||||
|
||||
# Every fix must be tested. See the flutter/packages/flutter/test_fixes/README.md
|
||||
# file for instructions on testing these data driven fixes.
|
||||
|
||||
# For documentation about this file format, see
|
||||
# https://dart.dev/go/data-driven-fixes.
|
||||
|
||||
# * Fixes in this file are for the MaterialState enum and classes from the Material library. *
|
||||
# For fixes to
|
||||
# * AppBar: fix_app_bar.yaml
|
||||
# * AppBarTheme: fix_app_bar_theme.yaml
|
||||
# * ColorScheme: fix_color_scheme.yaml
|
||||
# * Material (general): fix_material.yaml
|
||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||
# * TextTheme: fix_text_theme.yaml
|
||||
# * ThemeDate: fix_theme_data.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetState'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
enum: 'MaterialState'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetState'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetPropertyResolver'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
typedef: 'MaterialPropertyResolver'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetPropertyResolver'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateColor'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateColor'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateColor'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateMouseCursor'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateMouseCursor'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateMouseCursor'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateBorderSide'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateBorderSide'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateBorderSide'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateOutlinedBorder'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateOutlinedBorder'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateOutlinedBorder'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateTextStyle'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateTextStyle'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateTextStyle'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStateProperty'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStateProperty'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStateProperty'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStatePropertyAll'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStatePropertyAll'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStatePropertyAll'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
- title: "Replace with 'WidgetStatesController'"
|
||||
date: 2024-02-01
|
||||
element:
|
||||
uris: [ 'material.dart', 'widgets.dart' ]
|
||||
class: 'MaterialStatesController'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'WidgetStatesController'
|
||||
|
||||
# Before adding a new fix: read instructions at the top of this file.
|
|
@ -2,9 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'input_border.dart';
|
||||
|
||||
|
@ -20,6 +18,9 @@ import 'input_border.dart';
|
|||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetState], a general non-Material version that can be used
|
||||
/// interchangebly with `MaterialState`. They functionally work the same,
|
||||
/// except [WidgetState] can be used outside of Material.
|
||||
/// * [MaterialStateProperty], an interface for objects that "resolve" to
|
||||
/// different values depending on a widget's material state.
|
||||
/// {@template flutter.material.MaterialStateProperty.implementations}
|
||||
|
@ -45,62 +46,26 @@ import 'input_border.dart';
|
|||
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
||||
/// a [TextStyle] or a [MaterialStateProperty<TextStyle>].
|
||||
/// {@endtemplate}
|
||||
enum MaterialState {
|
||||
/// The state when the user drags their mouse cursor over the given widget.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#hover.
|
||||
hovered,
|
||||
|
||||
/// The state when the user navigates with the keyboard to a given widget.
|
||||
///
|
||||
/// This can also sometimes be triggered when a widget is tapped. For example,
|
||||
/// when a [TextField] is tapped, it becomes [focused].
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#focus.
|
||||
focused,
|
||||
|
||||
/// The state when the user is actively pressing down on the given widget.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#pressed.
|
||||
pressed,
|
||||
|
||||
/// The state when this widget is being dragged from one place to another by
|
||||
/// the user.
|
||||
///
|
||||
/// https://material.io/design/interaction/states.html#dragged.
|
||||
dragged,
|
||||
|
||||
/// The state when this item has been selected.
|
||||
///
|
||||
/// This applies to things that can be toggled (such as chips and checkboxes)
|
||||
/// and things that are selected from a set of options (such as tabs and radio buttons).
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#selected.
|
||||
selected,
|
||||
|
||||
/// The state when this widget overlaps the content of a scrollable below.
|
||||
///
|
||||
/// Used by [AppBar] to indicate that the primary scrollable's
|
||||
/// content has scrolled up and behind the app bar.
|
||||
scrolledUnder,
|
||||
|
||||
/// The state when this widget is disabled and cannot be interacted with.
|
||||
///
|
||||
/// Disabled widgets should not respond to hover, focus, press, or drag
|
||||
/// interactions.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#disabled.
|
||||
disabled,
|
||||
|
||||
/// The state when the widget has entered some form of invalid state.
|
||||
///
|
||||
/// See https://material.io/design/interaction/states.html#usage.
|
||||
error,
|
||||
}
|
||||
@Deprecated(
|
||||
'Use WidgetState instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialState = WidgetState;
|
||||
|
||||
/// Signature for the function that returns a value of type `T` based on a given
|
||||
/// set of states.
|
||||
typedef MaterialPropertyResolver<T> = T Function(Set<MaterialState> states);
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetPropertyResolver], the non-Material form of `MaterialPropertyResolver`
|
||||
/// that can be used interchangably with `MaterialPropertyResolver.
|
||||
@Deprecated(
|
||||
'Use WidgetPropertyResolver instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialPropertyResolver<T> = WidgetPropertyResolver<T>;
|
||||
|
||||
/// Defines a [Color] that is also a [MaterialStateProperty].
|
||||
///
|
||||
|
@ -149,55 +114,17 @@ typedef MaterialPropertyResolver<T> = T Function(Set<MaterialState> states);
|
|||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
abstract class MaterialStateColor extends Color implements MaterialStateProperty<Color> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const MaterialStateColor(super.defaultValue);
|
||||
|
||||
/// Creates a [MaterialStateColor] from a [MaterialPropertyResolver<Color>]
|
||||
/// callback function.
|
||||
///
|
||||
/// If used as a regular color, the color resolved in the default state (the
|
||||
/// empty set of states) will be used.
|
||||
/// See also
|
||||
///
|
||||
/// The given callback parameter must return a non-null color in the default
|
||||
/// state.
|
||||
static MaterialStateColor resolveWith(MaterialPropertyResolver<Color> callback) => _MaterialStateColor(callback);
|
||||
|
||||
/// Returns a [Color] that's to be used when a Material component is in the
|
||||
/// specified state.
|
||||
@override
|
||||
Color resolve(Set<MaterialState> states);
|
||||
|
||||
/// A constant whose value is [Colors.transparent] for all states.
|
||||
static const MaterialStateColor transparent = _MaterialStateColorTransparent();
|
||||
}
|
||||
|
||||
/// A [MaterialStateColor] created from a [MaterialPropertyResolver<Color>]
|
||||
/// callback alone.
|
||||
///
|
||||
/// If used as a regular color, the color resolved in the default state will
|
||||
/// be used.
|
||||
///
|
||||
/// Used by [MaterialStateColor.resolveWith].
|
||||
class _MaterialStateColor extends MaterialStateColor {
|
||||
_MaterialStateColor(this._resolve) : super(_resolve(_defaultStates).value);
|
||||
|
||||
final MaterialPropertyResolver<Color> _resolve;
|
||||
|
||||
/// The default state for a Material component, the empty set of interaction states.
|
||||
static const Set<MaterialState> _defaultStates = <MaterialState>{};
|
||||
|
||||
@override
|
||||
Color resolve(Set<MaterialState> states) => _resolve(states);
|
||||
}
|
||||
|
||||
class _MaterialStateColorTransparent extends MaterialStateColor {
|
||||
const _MaterialStateColorTransparent() : super(0x00000000);
|
||||
|
||||
@override
|
||||
Color resolve(Set<MaterialState> states) => const Color(0x00000000);
|
||||
}
|
||||
/// * [WidgetStateColor], the non-Material version that can be used
|
||||
/// interchangably with `MaterialStateColor`.
|
||||
@Deprecated(
|
||||
'Use WidgetStateColor instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateColor = WidgetStateColor;
|
||||
|
||||
/// Defines a [MouseCursor] whose value depends on a set of [MaterialState]s which
|
||||
/// represent the interactive state of a component.
|
||||
|
@ -225,76 +152,17 @@ class _MaterialStateColorTransparent extends MaterialStateColor {
|
|||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStateMouseCursor], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStateMouseCursor`.
|
||||
/// * [MouseCursor] for introduction on the mouse cursor system.
|
||||
/// * [SystemMouseCursors], which defines cursors that are supported by
|
||||
/// native platforms.
|
||||
abstract class MaterialStateMouseCursor extends MouseCursor implements MaterialStateProperty<MouseCursor> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const MaterialStateMouseCursor();
|
||||
|
||||
@protected
|
||||
@override
|
||||
MouseCursorSession createSession(int device) {
|
||||
return resolve(<MaterialState>{}).createSession(device);
|
||||
}
|
||||
|
||||
/// Returns a [MouseCursor] that's to be used when a Material component is in
|
||||
/// the specified state.
|
||||
///
|
||||
/// This method should never return null.
|
||||
@override
|
||||
MouseCursor resolve(Set<MaterialState> states);
|
||||
|
||||
/// A mouse cursor for clickable material widgets, which resolves differently
|
||||
/// when the widget is disabled.
|
||||
///
|
||||
/// By default this cursor resolves to [SystemMouseCursors.click]. If the widget is
|
||||
/// disabled, the cursor resolves to [SystemMouseCursors.basic].
|
||||
///
|
||||
/// This cursor is the default for many Material widgets.
|
||||
static const MaterialStateMouseCursor clickable = _EnabledAndDisabledMouseCursor(
|
||||
enabledCursor: SystemMouseCursors.click,
|
||||
disabledCursor: SystemMouseCursors.basic,
|
||||
name: 'clickable',
|
||||
);
|
||||
|
||||
/// A mouse cursor for material widgets related to text, which resolves differently
|
||||
/// when the widget is disabled.
|
||||
///
|
||||
/// By default this cursor resolves to [SystemMouseCursors.text]. If the widget is
|
||||
/// disabled, the cursor resolves to [SystemMouseCursors.basic].
|
||||
///
|
||||
/// This cursor is the default for many Material widgets.
|
||||
static const MaterialStateMouseCursor textable = _EnabledAndDisabledMouseCursor(
|
||||
enabledCursor: SystemMouseCursors.text,
|
||||
disabledCursor: SystemMouseCursors.basic,
|
||||
name: 'textable',
|
||||
);
|
||||
}
|
||||
|
||||
class _EnabledAndDisabledMouseCursor extends MaterialStateMouseCursor {
|
||||
const _EnabledAndDisabledMouseCursor({
|
||||
required this.enabledCursor,
|
||||
required this.disabledCursor,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
final MouseCursor enabledCursor;
|
||||
final MouseCursor disabledCursor;
|
||||
final String name;
|
||||
|
||||
@override
|
||||
MouseCursor resolve(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
return disabledCursor;
|
||||
}
|
||||
return enabledCursor;
|
||||
}
|
||||
|
||||
@override
|
||||
String get debugDescription => 'MaterialStateMouseCursor($name)';
|
||||
}
|
||||
@Deprecated(
|
||||
'Use WidgetStateMouseCursor instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateMouseCursor = WidgetStateMouseCursor;
|
||||
|
||||
/// Defines a [BorderSide] whose value depends on a set of [MaterialState]s
|
||||
/// which represent the interactive state of a component.
|
||||
|
@ -316,72 +184,17 @@ class _EnabledAndDisabledMouseCursor extends MaterialStateMouseCursor {
|
|||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [MaterialStateBorderSide], otherwise only the default state will be used.
|
||||
abstract class MaterialStateBorderSide extends BorderSide implements MaterialStateProperty<BorderSide?> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const MaterialStateBorderSide();
|
||||
|
||||
/// Creates a [MaterialStateBorderSide] from a
|
||||
/// [MaterialPropertyResolver<BorderSide?>] callback function.
|
||||
///
|
||||
/// If used as a regular [BorderSide], the border resolved in the default state
|
||||
/// (the empty set of states) will be used.
|
||||
/// See also:
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```dart
|
||||
/// ChipTheme(
|
||||
/// data: Theme.of(context).chipTheme.copyWith(
|
||||
/// side: MaterialStateBorderSide.resolveWith((Set<MaterialState> states) {
|
||||
/// if (states.contains(MaterialState.selected)) {
|
||||
/// return const BorderSide(color: Colors.red);
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }),
|
||||
/// ),
|
||||
/// child: const Chip(
|
||||
/// label: Text('Transceiver'),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ```
|
||||
///
|
||||
/// Alternatively:
|
||||
///
|
||||
/// ```dart
|
||||
/// Chip(
|
||||
/// label: const Text('Transceiver'),
|
||||
/// side: MaterialStateBorderSide.resolveWith((Set<MaterialState> states) {
|
||||
/// if (states.contains(MaterialState.selected)) {
|
||||
/// return const BorderSide(color: Colors.red);
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }),
|
||||
/// ),
|
||||
/// ```
|
||||
const factory MaterialStateBorderSide.resolveWith(MaterialPropertyResolver<BorderSide?> callback) = _MaterialStateBorderSide;
|
||||
|
||||
/// Returns a [BorderSide] that's to be used when a Material component is
|
||||
/// in the specified state. Return null to defer to the default value of the
|
||||
/// widget or theme.
|
||||
@override
|
||||
BorderSide? resolve(Set<MaterialState> states);
|
||||
}
|
||||
|
||||
/// A [MaterialStateBorderSide] created from a
|
||||
/// [MaterialPropertyResolver<BorderSide>] callback alone.
|
||||
///
|
||||
/// If used as a regular side, the side resolved in the default state will
|
||||
/// be used.
|
||||
///
|
||||
/// Used by [MaterialStateBorderSide.resolveWith].
|
||||
class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
||||
const _MaterialStateBorderSide(this._resolve);
|
||||
|
||||
final MaterialPropertyResolver<BorderSide?> _resolve;
|
||||
|
||||
@override
|
||||
BorderSide? resolve(Set<MaterialState> states) => _resolve(states);
|
||||
}
|
||||
/// * [WidgetStateBorderSide], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStateBorderSide`.
|
||||
@Deprecated(
|
||||
'Use WidgetStateBorderSide instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateBorderSide = WidgetStateBorderSide;
|
||||
|
||||
/// Defines an [OutlinedBorder] whose value depends on a set of [MaterialState]s
|
||||
/// which represent the interactive state of a component.
|
||||
|
@ -403,18 +216,15 @@ class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
|||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStateOutlinedBorder], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStateOutlinedBorder`.
|
||||
/// * [ShapeBorder] the base class for shape outlines.
|
||||
abstract class MaterialStateOutlinedBorder extends OutlinedBorder implements MaterialStateProperty<OutlinedBorder?> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const MaterialStateOutlinedBorder();
|
||||
|
||||
/// Returns an [OutlinedBorder] that's to be used when a Material component is
|
||||
/// in the specified state. Return null to defer to the default value of the
|
||||
/// widget or theme.
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<MaterialState> states);
|
||||
}
|
||||
@Deprecated(
|
||||
'Use WidgetStateOutlinedBorder instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateOutlinedBorder = WidgetStateOutlinedBorder;
|
||||
|
||||
/// Defines a [TextStyle] that is also a [MaterialStateProperty].
|
||||
///
|
||||
|
@ -441,42 +251,17 @@ abstract class MaterialStateOutlinedBorder extends OutlinedBorder implements Mat
|
|||
/// [MaterialStateTextStyle] and override its [resolve] method. You'll also need
|
||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||
/// at compile-time what its default color is.
|
||||
abstract class MaterialStateTextStyle extends TextStyle implements MaterialStateProperty<TextStyle> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const MaterialStateTextStyle();
|
||||
|
||||
/// Creates a [MaterialStateTextStyle] from a [MaterialPropertyResolver<TextStyle>]
|
||||
/// callback function.
|
||||
///
|
||||
/// If used as a regular text style, the style resolved in the default state (the
|
||||
/// empty set of states) will be used.
|
||||
/// See also:
|
||||
///
|
||||
/// The given callback parameter must return a non-null text style in the default
|
||||
/// state.
|
||||
const factory MaterialStateTextStyle.resolveWith(MaterialPropertyResolver<TextStyle> callback) = _MaterialStateTextStyle;
|
||||
|
||||
/// Returns a [TextStyle] that's to be used when a Material component is in the
|
||||
/// specified state.
|
||||
@override
|
||||
TextStyle resolve(Set<MaterialState> states);
|
||||
}
|
||||
|
||||
/// A [MaterialStateTextStyle] created from a [MaterialPropertyResolver<TextStyle>]
|
||||
/// callback alone.
|
||||
///
|
||||
/// If used as a regular text style, the style resolved in the default state will
|
||||
/// be used.
|
||||
///
|
||||
/// Used by [MaterialStateTextStyle.resolveWith].
|
||||
class _MaterialStateTextStyle extends MaterialStateTextStyle {
|
||||
const _MaterialStateTextStyle(this._resolve);
|
||||
|
||||
final MaterialPropertyResolver<TextStyle> _resolve;
|
||||
|
||||
@override
|
||||
TextStyle resolve(Set<MaterialState> states) => _resolve(states);
|
||||
}
|
||||
/// * [WidgetStateTextStyle], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStateTextStyle`.
|
||||
@Deprecated(
|
||||
'Use WidgetStateTextStyle instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateTextStyle = WidgetStateTextStyle;
|
||||
|
||||
/// Defines a [OutlineInputBorder] that is also a [MaterialStateProperty].
|
||||
///
|
||||
|
@ -634,106 +419,29 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord
|
|||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStateProperty], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStateProperty`.
|
||||
/// {@macro flutter.material.MaterialStateProperty.implementations}
|
||||
abstract class MaterialStateProperty<T> {
|
||||
/// Returns a value of type `T` that depends on [states].
|
||||
///
|
||||
/// Widgets like [TextButton] and [ElevatedButton] apply this method to their
|
||||
/// current [MaterialState]s to compute colors and other visual parameters
|
||||
/// at build time.
|
||||
T resolve(Set<MaterialState> states);
|
||||
|
||||
/// Resolves the value for the given set of states if `value` is a
|
||||
/// [MaterialStateProperty], otherwise returns the value itself.
|
||||
///
|
||||
/// This is useful for widgets that have parameters which can optionally be a
|
||||
/// [MaterialStateProperty]. For example, [InkWell.mouseCursor] can be a
|
||||
/// [MouseCursor] or a [MaterialStateProperty<MouseCursor>].
|
||||
static T resolveAs<T>(T value, Set<MaterialState> states) {
|
||||
if (value is MaterialStateProperty<T>) {
|
||||
final MaterialStateProperty<T> property = value;
|
||||
return property.resolve(states);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Convenience method for creating a [MaterialStateProperty] from a
|
||||
/// [MaterialPropertyResolver] function alone.
|
||||
static MaterialStateProperty<T> resolveWith<T>(MaterialPropertyResolver<T> callback) => _MaterialStatePropertyWith<T>(callback);
|
||||
|
||||
/// Convenience method for creating a [MaterialStateProperty] that resolves
|
||||
/// to a single value for all states.
|
||||
///
|
||||
/// If you need a const value, use [MaterialStatePropertyAll] directly.
|
||||
///
|
||||
// TODO(darrenaustin): Deprecate this when we have the ability to create
|
||||
// a dart fix that will replace this with MaterialStatePropertyAll:
|
||||
// https://github.com/dart-lang/sdk/issues/49056.
|
||||
static MaterialStateProperty<T> all<T>(T value) => MaterialStatePropertyAll<T>(value);
|
||||
|
||||
/// Linearly interpolate between two [MaterialStateProperty]s.
|
||||
static MaterialStateProperty<T?>? lerp<T>(
|
||||
MaterialStateProperty<T>? a,
|
||||
MaterialStateProperty<T>? b,
|
||||
double t,
|
||||
T? Function(T?, T?, double) lerpFunction,
|
||||
) {
|
||||
// Avoid creating a _LerpProperties object for a common case.
|
||||
if (a == null && b == null) {
|
||||
return null;
|
||||
}
|
||||
return _LerpProperties<T>(a, b, t, lerpFunction);
|
||||
}
|
||||
}
|
||||
|
||||
class _LerpProperties<T> implements MaterialStateProperty<T?> {
|
||||
const _LerpProperties(this.a, this.b, this.t, this.lerpFunction);
|
||||
|
||||
final MaterialStateProperty<T>? a;
|
||||
final MaterialStateProperty<T>? b;
|
||||
final double t;
|
||||
final T? Function(T?, T?, double) lerpFunction;
|
||||
|
||||
@override
|
||||
T? resolve(Set<MaterialState> states) {
|
||||
final T? resolvedA = a?.resolve(states);
|
||||
final T? resolvedB = b?.resolve(states);
|
||||
return lerpFunction(resolvedA, resolvedB, t);
|
||||
}
|
||||
}
|
||||
|
||||
class _MaterialStatePropertyWith<T> implements MaterialStateProperty<T> {
|
||||
_MaterialStatePropertyWith(this._resolve);
|
||||
|
||||
final MaterialPropertyResolver<T> _resolve;
|
||||
|
||||
@override
|
||||
T resolve(Set<MaterialState> states) => _resolve(states);
|
||||
}
|
||||
@Deprecated(
|
||||
'Use WidgetStateProperty instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStateProperty<T> = WidgetStateProperty<T>;
|
||||
|
||||
/// Convenience class for creating a [MaterialStateProperty] that
|
||||
/// resolves to the given value for all states.
|
||||
class MaterialStatePropertyAll<T> implements MaterialStateProperty<T> {
|
||||
|
||||
/// Constructs a [MaterialStateProperty] that always resolves to the given
|
||||
/// value.
|
||||
const MaterialStatePropertyAll(this.value);
|
||||
|
||||
/// The value of the property that will be used for all states.
|
||||
final T value;
|
||||
|
||||
@override
|
||||
T resolve(Set<MaterialState> states) => value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (value is double) {
|
||||
return 'MaterialStatePropertyAll(${debugFormatDouble(value as double)})';
|
||||
} else {
|
||||
return 'MaterialStatePropertyAll($value)';
|
||||
}
|
||||
}
|
||||
}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStatePropertyAll], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStatePropertyAll`.
|
||||
@Deprecated(
|
||||
'Use WidgetStatePropertyAll instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStatePropertyAll<T> = WidgetStatePropertyAll<T>;
|
||||
|
||||
/// Manages a set of [MaterialState]s and notifies listeners of changes.
|
||||
///
|
||||
|
@ -762,16 +470,14 @@ class MaterialStatePropertyAll<T> implements MaterialStateProperty<T> {
|
|||
/// depend on [MaterialStatesController] may call [update] in their build method.
|
||||
/// In such cases, listener's that call `setState` - during the build phase - will cause
|
||||
/// an error.
|
||||
class MaterialStatesController extends ValueNotifier<Set<MaterialState>> {
|
||||
/// Creates a MaterialStatesController.
|
||||
MaterialStatesController([Set<MaterialState>? value]) : super(<MaterialState>{...?value});
|
||||
|
||||
/// Adds [state] to [value] if [add] is true, and removes it otherwise,
|
||||
/// and notifies listeners if [value] has changed.
|
||||
void update(MaterialState state, bool add) {
|
||||
final bool valueChanged = add ? value.add(state) : value.remove(state);
|
||||
if (valueChanged) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStatesController], the non-Material version that can be used
|
||||
/// interchangeably with `MaterialStatesController`.
|
||||
@Deprecated(
|
||||
'Use WidgetStatesController instead. '
|
||||
'Moved to the Widgets layer to make code available outside of Material. '
|
||||
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||
)
|
||||
typedef MaterialStatesController = WidgetStatesController;
|
||||
|
|
633
packages/flutter/lib/src/widgets/widget_state.dart
Normal file
633
packages/flutter/lib/src/widgets/widget_state.dart
Normal file
|
@ -0,0 +1,633 @@
|
|||
// 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/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
// Examples can assume:
|
||||
// late BuildContext context;
|
||||
|
||||
/// Interactive states that some of the widgets can take on when receiving input
|
||||
/// from the user.
|
||||
///
|
||||
/// States are defined by https://material.io/design/interaction/states.html#usage,
|
||||
/// but are not limited to the Material design system or library.
|
||||
///
|
||||
/// Some widgets track their current state in a `Set<WidgetState>`.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialState], the Material specific version of `WidgetState`.
|
||||
/// * [WidgetStateProperty], an interface for objects that "resolve" to
|
||||
/// different values depending on a widget's state.
|
||||
/// {@template flutter.widgets.WidgetStateProperty.implementations}
|
||||
/// * [WidgetStateColor], a [Color] that implements `WidgetStateProperty`
|
||||
/// which is used in APIs that need to accept either a [Color] or a
|
||||
/// `WidgetStateProperty<Color>`.
|
||||
/// * [WidgetStateMouseCursor], a [MouseCursor] that implements
|
||||
/// `WidgetStateProperty` which is used in APIs that need to accept either
|
||||
/// a [MouseCursor] or a [WidgetStateProperty<MouseCursor>].
|
||||
/// * [WidgetStateOutlinedBorder], an [OutlinedBorder] that implements
|
||||
/// `WidgetStateProperty` which is used in APIs that need to accept either
|
||||
/// an [OutlinedBorder] or a [WidgetStateProperty<OutlinedBorder>].
|
||||
/// * [WidgetStateBorderSide], a [BorderSide] that implements
|
||||
/// `WidgetStateProperty` which is used in APIs that need to accept either
|
||||
/// a [BorderSide] or a [WidgetStateProperty<BorderSide>].
|
||||
/// * [WidgetStateTextStyle], a [TextStyle] that implements
|
||||
/// `WidgetStateProperty` which is used in APIs that need to accept either
|
||||
/// a [TextStyle] or a [WidgetStateProperty<TextStyle>].
|
||||
/// {@endtemplate}
|
||||
enum WidgetState {
|
||||
/// The state when the user drags their mouse cursor over the given widget.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#hover.
|
||||
hovered,
|
||||
|
||||
/// The state when the user navigates with the keyboard to a given widget.
|
||||
///
|
||||
/// This can also sometimes be triggered when a widget is tapped. For example,
|
||||
/// when a [TextField] is tapped, it becomes [focused].
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#focus.
|
||||
focused,
|
||||
|
||||
/// The state when the user is actively pressing down on the given widget.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#pressed.
|
||||
pressed,
|
||||
|
||||
/// The state when this widget is being dragged from one place to another by
|
||||
/// the user.
|
||||
///
|
||||
/// https://material.io/design/interaction/states.html#dragged.
|
||||
dragged,
|
||||
|
||||
/// The state when this item has been selected.
|
||||
///
|
||||
/// This applies to things that can be toggled (such as chips and checkboxes)
|
||||
/// and things that are selected from a set of options (such as tabs and radio buttons).
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#selected.
|
||||
selected,
|
||||
|
||||
/// The state when this widget overlaps the content of a scrollable below.
|
||||
///
|
||||
/// Used by [AppBar] to indicate that the primary scrollable's
|
||||
/// content has scrolled up and behind the app bar.
|
||||
scrolledUnder,
|
||||
|
||||
/// The state when this widget is disabled and cannot be interacted with.
|
||||
///
|
||||
/// Disabled widgets should not respond to hover, focus, press, or drag
|
||||
/// interactions.
|
||||
///
|
||||
/// See: https://material.io/design/interaction/states.html#disabled.
|
||||
disabled,
|
||||
|
||||
/// The state when the widget has entered some form of invalid state.
|
||||
///
|
||||
/// See https://material.io/design/interaction/states.html#usage.
|
||||
error,
|
||||
}
|
||||
|
||||
/// Signature for the function that returns a value of type `T` based on a given
|
||||
/// set of states.
|
||||
typedef WidgetPropertyResolver<T> = T Function(Set<WidgetState> states);
|
||||
|
||||
/// Defines a [Color] that is also a [WidgetStateProperty].
|
||||
///
|
||||
/// This class exists to enable widgets with [Color] valued properties
|
||||
/// to also accept [WidgetStateProperty<Color>] values. A widget
|
||||
/// state color property represents a color which depends on
|
||||
/// a widget's "interactive state". This state is represented as a
|
||||
/// [Set] of [WidgetState]s, like [WidgetState.pressed],
|
||||
/// [WidgetState.focused] and [WidgetState.hovered].
|
||||
///
|
||||
/// [WidgetStateColor] should only be used with widgets that document
|
||||
/// their support, like [TimePickerThemeData.dayPeriodColor].
|
||||
///
|
||||
/// To use a [WidgetStateColor], you can either:
|
||||
/// 1. Create a subclass of [WidgetStateColor] and implement the abstract `resolve` method.
|
||||
/// 2. Use [WidgetStateColor.resolveWith] and pass in a callback that
|
||||
/// will be used to resolve the color in the given states.
|
||||
///
|
||||
/// If a [WidgetStateColor] is used for a property or a parameter that doesn't
|
||||
/// support resolving [WidgetStateProperty<Color>]s, then its default color
|
||||
/// value will be used for all states.
|
||||
///
|
||||
/// To define a `const` [WidgetStateColor], you'll need to extend
|
||||
/// [WidgetStateColor] and override its [resolve] method. You'll also need
|
||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||
/// at compile-time what its default color is.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// This example defines a [WidgetStateColor] with a const constructor.
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyColor extends WidgetStateColor {
|
||||
/// const MyColor() : super(_defaultColor);
|
||||
///
|
||||
/// static const int _defaultColor = 0xcafefeed;
|
||||
/// static const int _pressedColor = 0xdeadbeef;
|
||||
///
|
||||
/// @override
|
||||
/// Color resolve(Set<WidgetState> states) {
|
||||
/// if (states.contains(WidgetState.pressed)) {
|
||||
/// return const Color(_pressedColor);
|
||||
/// }
|
||||
/// return const Color(_defaultColor);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStateColor], the Material specific version of `WidgetStateColor`.
|
||||
abstract class WidgetStateColor extends Color implements WidgetStateProperty<Color> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const WidgetStateColor(super.defaultValue);
|
||||
|
||||
/// Creates a [WidgetStateColor] from a [WidgetPropertyResolver<Color>]
|
||||
/// callback function.
|
||||
///
|
||||
/// If used as a regular color, the color resolved in the default state (the
|
||||
/// empty set of states) will be used.
|
||||
///
|
||||
/// The given callback parameter must return a non-null color in the default
|
||||
/// state.
|
||||
static WidgetStateColor resolveWith(WidgetPropertyResolver<Color> callback) => _WidgetStateColor(callback);
|
||||
|
||||
/// Returns a [Color] that's to be used when a component is in the specified
|
||||
/// state.
|
||||
@override
|
||||
Color resolve(Set<WidgetState> states);
|
||||
|
||||
/// A constant whose value is transparent for all states.
|
||||
static const WidgetStateColor transparent = _WidgetStateColorTransparent();
|
||||
}
|
||||
|
||||
class _WidgetStateColor extends WidgetStateColor {
|
||||
_WidgetStateColor(this._resolve) : super(_resolve(_defaultStates).value);
|
||||
|
||||
final WidgetPropertyResolver<Color> _resolve;
|
||||
|
||||
static const Set<WidgetState> _defaultStates = <WidgetState>{};
|
||||
|
||||
@override
|
||||
Color resolve(Set<WidgetState> states) => _resolve(states);
|
||||
}
|
||||
|
||||
class _WidgetStateColorTransparent extends WidgetStateColor {
|
||||
const _WidgetStateColorTransparent() : super(0x00000000);
|
||||
|
||||
@override
|
||||
Color resolve(Set<WidgetState> states) => const Color(0x00000000);
|
||||
}
|
||||
|
||||
/// Defines a [MouseCursor] whose value depends on a set of [WidgetState]s which
|
||||
/// represent the interactive state of a component.
|
||||
///
|
||||
/// This kind of [MouseCursor] is useful when the set of interactive
|
||||
/// actions a widget supports varies with its state. For example, a
|
||||
/// mouse pointer hovering over a disabled [ListTile] should not
|
||||
/// display [SystemMouseCursors.click], since a disabled list tile
|
||||
/// doesn't respond to mouse clicks. [ListTile]'s default mouse cursor
|
||||
/// is a [WidgetStateMouseCursor.clickable], which resolves to
|
||||
/// [SystemMouseCursors.basic] when the button is disabled.
|
||||
///
|
||||
/// To use a [WidgetStateMouseCursor], you should create a subclass of
|
||||
/// [WidgetStateMouseCursor] and implement the abstract `resolve` method.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This example defines a mouse cursor that resolves to
|
||||
/// [SystemMouseCursors.forbidden] when its widget is disabled.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/material_state/material_state_mouse_cursor.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [WidgetStateMouseCursor], otherwise only the default state will be used.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStateMouseCursor], the Material specific version of
|
||||
/// `WidgetStateMouseCursor`.
|
||||
/// * [MouseCursor] for introduction on the mouse cursor system.
|
||||
/// * [SystemMouseCursors], which defines cursors that are supported by
|
||||
/// native platforms.
|
||||
abstract class WidgetStateMouseCursor extends MouseCursor implements WidgetStateProperty<MouseCursor> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const WidgetStateMouseCursor();
|
||||
|
||||
@protected
|
||||
@override
|
||||
MouseCursorSession createSession(int device) {
|
||||
return resolve(<WidgetState>{}).createSession(device);
|
||||
}
|
||||
|
||||
/// Returns a [MouseCursor] that's to be used when a component is in the
|
||||
/// specified state.
|
||||
@override
|
||||
MouseCursor resolve(Set<WidgetState> states);
|
||||
|
||||
/// A mouse cursor for clickable widgets, which resolves differently when the
|
||||
/// widget is disabled.
|
||||
///
|
||||
/// By default this cursor resolves to [SystemMouseCursors.click]. If the widget is
|
||||
/// disabled, the cursor resolves to [SystemMouseCursors.basic].
|
||||
///
|
||||
/// This cursor is the default for many widgets.
|
||||
static const WidgetStateMouseCursor clickable = _EnabledAndDisabledMouseCursor(
|
||||
enabledCursor: SystemMouseCursors.click,
|
||||
disabledCursor: SystemMouseCursors.basic,
|
||||
name: 'clickable',
|
||||
);
|
||||
|
||||
/// A mouse cursor for widgets related to text, which resolves differently
|
||||
/// when the widget is disabled.
|
||||
///
|
||||
/// By default this cursor resolves to [SystemMouseCursors.text]. If the widget is
|
||||
/// disabled, the cursor resolves to [SystemMouseCursors.basic].
|
||||
///
|
||||
/// This cursor is the default for many widgets.
|
||||
static const WidgetStateMouseCursor textable = _EnabledAndDisabledMouseCursor(
|
||||
enabledCursor: SystemMouseCursors.text,
|
||||
disabledCursor: SystemMouseCursors.basic,
|
||||
name: 'textable',
|
||||
);
|
||||
}
|
||||
|
||||
class _EnabledAndDisabledMouseCursor extends WidgetStateMouseCursor {
|
||||
const _EnabledAndDisabledMouseCursor({
|
||||
required this.enabledCursor,
|
||||
required this.disabledCursor,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
final MouseCursor enabledCursor;
|
||||
final MouseCursor disabledCursor;
|
||||
final String name;
|
||||
|
||||
@override
|
||||
MouseCursor resolve(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return disabledCursor;
|
||||
}
|
||||
return enabledCursor;
|
||||
}
|
||||
|
||||
@override
|
||||
String get debugDescription => 'WidgetStateMouseCursor($name)';
|
||||
}
|
||||
|
||||
/// Defines a [BorderSide] whose value depends on a set of [WidgetState]s
|
||||
/// which represent the interactive state of a component.
|
||||
///
|
||||
/// To use a [WidgetStateBorderSide], you should create a subclass of a
|
||||
/// [WidgetStateBorderSide] and override the abstract `resolve` method.
|
||||
///
|
||||
/// This class enables existing widget implementations with [BorderSide]
|
||||
/// properties to be extended to also effectively support `WidgetStateProperty<BorderSide>`
|
||||
/// property values. [WidgetStateBorderSide] should only be used with widgets that document
|
||||
/// their support, like [ActionChip.side].
|
||||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [WidgetStateBorderSide], otherwise only the default state will be used.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStateBorderSide], the Material specific version of
|
||||
/// `WidgetStateBorderSide`.
|
||||
abstract class WidgetStateBorderSide extends BorderSide implements WidgetStateProperty<BorderSide?> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const WidgetStateBorderSide();
|
||||
|
||||
/// Creates a [WidgetStateBorderSide] from a
|
||||
/// [WidgetPropertyResolver<BorderSide?>] callback function.
|
||||
///
|
||||
/// If used as a regular [BorderSide], the border resolved in the default state
|
||||
/// (the empty set of states) will be used.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```dart
|
||||
/// ChipTheme(
|
||||
/// data: Theme.of(context).chipTheme.copyWith(
|
||||
/// side: WidgetStateBorderSide.resolveWith((Set<WidgetState> states) {
|
||||
/// if (states.contains(WidgetState.selected)) {
|
||||
/// return const BorderSide(color: Colors.red);
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }),
|
||||
/// ),
|
||||
/// child: const Chip(
|
||||
/// label: Text('Transceiver'),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ```
|
||||
///
|
||||
/// Alternatively:
|
||||
///
|
||||
/// ```dart
|
||||
/// Chip(
|
||||
/// label: const Text('Transceiver'),
|
||||
/// side: WidgetStateBorderSide.resolveWith((Set<WidgetState> states) {
|
||||
/// if (states.contains(WidgetState.selected)) {
|
||||
/// return const BorderSide(color: Colors.red);
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }),
|
||||
/// ),
|
||||
/// ```
|
||||
const factory WidgetStateBorderSide.resolveWith(WidgetPropertyResolver<BorderSide?> callback) = _WidgetStateBorderSide;
|
||||
|
||||
/// Returns a [BorderSide] that's to be used when a Material component is
|
||||
/// in the specified state. Return null to defer to the default value of the
|
||||
/// widget or theme.
|
||||
@override
|
||||
BorderSide? resolve(Set<WidgetState> states);
|
||||
}
|
||||
|
||||
class _WidgetStateBorderSide extends WidgetStateBorderSide {
|
||||
const _WidgetStateBorderSide(this._resolve);
|
||||
|
||||
final WidgetPropertyResolver<BorderSide?> _resolve;
|
||||
|
||||
@override
|
||||
BorderSide? resolve(Set<WidgetState> states) => _resolve(states);
|
||||
}
|
||||
|
||||
/// Defines an [OutlinedBorder] whose value depends on a set of [WidgetState]s
|
||||
/// which represent the interactive state of a component.
|
||||
///
|
||||
/// To use a [WidgetStateOutlinedBorder], you should create a subclass of an
|
||||
/// [OutlinedBorder] and implement [WidgetStateOutlinedBorder]'s abstract
|
||||
/// `resolve` method.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This example defines a subclass of [RoundedRectangleBorder] and an
|
||||
/// implementation of [WidgetStateOutlinedBorder], that resolves to
|
||||
/// [RoundedRectangleBorder] when its widget is selected.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/material_state/material_state_outlined_border.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [WidgetStateOutlinedBorder], otherwise only the default state will be used.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ShapeBorder] the base class for shape outlines.
|
||||
/// * [MaterialStateOutlinedBorder], the Material specific version of
|
||||
/// `WidgetStateOutlinedBorder`.
|
||||
abstract class WidgetStateOutlinedBorder extends OutlinedBorder implements WidgetStateProperty<OutlinedBorder?> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const WidgetStateOutlinedBorder();
|
||||
|
||||
/// Returns an [OutlinedBorder] that's to be used when a component is in the
|
||||
/// specified state. Return null to defer to the default value of the widget
|
||||
/// or theme.
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<WidgetState> states);
|
||||
}
|
||||
|
||||
/// Defines a [TextStyle] that is also a [WidgetStateProperty].
|
||||
///
|
||||
/// This class exists to enable widgets with [TextStyle] valued properties
|
||||
/// to also accept [WidgetStateProperty<TextStyle>] values. A widget
|
||||
/// state text style property represents a text style which depends on
|
||||
/// a widget's "interactive state". This state is represented as a
|
||||
/// [Set] of [WidgetState]s, like [WidgetState.pressed],
|
||||
/// [WidgetState.focused] and [WidgetState.hovered].
|
||||
///
|
||||
/// [WidgetStateTextStyle] should only be used with widgets that document
|
||||
/// their support, like [InputDecoration.labelStyle].
|
||||
///
|
||||
/// To use a [WidgetStateTextStyle], you can either:
|
||||
/// 1. Create a subclass of [WidgetStateTextStyle] and implement the abstract `resolve` method.
|
||||
/// 2. Use [WidgetStateTextStyle.resolveWith] and pass in a callback that
|
||||
/// will be used to resolve the color in the given states.
|
||||
///
|
||||
/// If a [WidgetStateTextStyle] is used for a property or a parameter that doesn't
|
||||
/// support resolving [WidgetStateProperty<TextStyle>]s, then its default color
|
||||
/// value will be used for all states.
|
||||
///
|
||||
/// To define a `const` [WidgetStateTextStyle], you'll need to extend
|
||||
/// [WidgetStateTextStyle] and override its [resolve] method. You'll also need
|
||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||
/// at compile-time what its default color is.
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStateTextStyle], the Material specific version of
|
||||
/// `WidgetStateTextStyle`.
|
||||
abstract class WidgetStateTextStyle extends TextStyle implements WidgetStateProperty<TextStyle> {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const WidgetStateTextStyle();
|
||||
|
||||
/// Creates a [WidgetStateTextStyle] from a [WidgetPropertyResolver<TextStyle>]
|
||||
/// callback function.
|
||||
///
|
||||
/// If used as a regular text style, the style resolved in the default state (the
|
||||
/// empty set of states) will be used.
|
||||
///
|
||||
/// The given callback parameter must return a non-null text style in the default
|
||||
/// state.
|
||||
const factory WidgetStateTextStyle.resolveWith(WidgetPropertyResolver<TextStyle> callback) = _WidgetStateTextStyle;
|
||||
|
||||
/// Returns a [TextStyle] that's to be used when a component is in the
|
||||
/// specified state.
|
||||
@override
|
||||
TextStyle resolve(Set<WidgetState> states);
|
||||
}
|
||||
|
||||
class _WidgetStateTextStyle extends WidgetStateTextStyle {
|
||||
const _WidgetStateTextStyle(this._resolve);
|
||||
|
||||
final WidgetPropertyResolver<TextStyle> _resolve;
|
||||
|
||||
@override
|
||||
TextStyle resolve(Set<WidgetState> states) => _resolve(states);
|
||||
}
|
||||
|
||||
/// Interface for classes that [resolve] to a value of type `T` based
|
||||
/// on a widget's interactive "state", which is defined as a set
|
||||
/// of [WidgetState]s.
|
||||
///
|
||||
/// Widget state properties represent values that depend on a widget's "state".
|
||||
/// The state is encoded as a set of [WidgetState] values, like
|
||||
/// [WidgetState.focused], [WidgetState.hovered], [WidgetState.pressed]. For
|
||||
/// example the [InkWell.overlayColor] defines the color that fills the ink well
|
||||
/// when it's pressed (the "splash color"), focused, or hovered. The [InkWell]
|
||||
/// uses the overlay color's [resolve] method to compute the color for the
|
||||
/// ink well's current state.
|
||||
///
|
||||
/// [ButtonStyle], which is used to configure the appearance of
|
||||
/// buttons like [TextButton], [ElevatedButton], and [OutlinedButton],
|
||||
/// has many material state properties. The button widgets keep track
|
||||
/// of their current material state and [resolve] the button style's
|
||||
/// material state properties when their value is needed.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStateProperty], the Material specific version of
|
||||
/// `WidgetStateProperty`.
|
||||
/// {@macro flutter.widgets.WidgetStateProperty.implementations}
|
||||
abstract class WidgetStateProperty<T> {
|
||||
/// Returns a value of type `T` that depends on [states].
|
||||
///
|
||||
/// Widgets like [TextButton] and [ElevatedButton] apply this method to their
|
||||
/// current [WidgetState]s to compute colors and other visual parameters
|
||||
/// at build time.
|
||||
T resolve(Set<WidgetState> states);
|
||||
|
||||
/// Resolves the value for the given set of states if `value` is a
|
||||
/// [WidgetStateProperty], otherwise returns the value itself.
|
||||
///
|
||||
/// This is useful for widgets that have parameters which can optionally be a
|
||||
/// [WidgetStateProperty]. For example, [InkWell.mouseCursor] can be a
|
||||
/// [MouseCursor] or a [WidgetStateProperty<MouseCursor>].
|
||||
static T resolveAs<T>(T value, Set<WidgetState> states) {
|
||||
if (value is WidgetStateProperty<T>) {
|
||||
final WidgetStateProperty<T> property = value;
|
||||
return property.resolve(states);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Convenience method for creating a [WidgetStateProperty] from a
|
||||
/// [WidgetPropertyResolver] function alone.
|
||||
static WidgetStateProperty<T> resolveWith<T>(WidgetPropertyResolver<T> callback) => _WidgetStatePropertyWith<T>(callback);
|
||||
|
||||
/// Convenience method for creating a [WidgetStateProperty] that resolves
|
||||
/// to a single value for all states.
|
||||
///
|
||||
/// If you need a const value, use [WidgetStatePropertyAll] directly.
|
||||
///
|
||||
// TODO(darrenaustin): Deprecate this when we have the ability to create
|
||||
// a dart fix that will replace this with WidgetStatePropertyAll:
|
||||
// https://github.com/dart-lang/sdk/issues/49056.
|
||||
static WidgetStateProperty<T> all<T>(T value) => WidgetStatePropertyAll<T>(value);
|
||||
|
||||
/// Linearly interpolate between two [WidgetStateProperty]s.
|
||||
static WidgetStateProperty<T?>? lerp<T>(
|
||||
WidgetStateProperty<T>? a,
|
||||
WidgetStateProperty<T>? b,
|
||||
double t,
|
||||
T? Function(T?, T?, double) lerpFunction,
|
||||
) {
|
||||
// Avoid creating a _LerpProperties object for a common case.
|
||||
if (a == null && b == null) {
|
||||
return null;
|
||||
}
|
||||
return _LerpProperties<T>(a, b, t, lerpFunction);
|
||||
}
|
||||
}
|
||||
|
||||
class _LerpProperties<T> implements WidgetStateProperty<T?> {
|
||||
const _LerpProperties(this.a, this.b, this.t, this.lerpFunction);
|
||||
|
||||
final WidgetStateProperty<T>? a;
|
||||
final WidgetStateProperty<T>? b;
|
||||
final double t;
|
||||
final T? Function(T?, T?, double) lerpFunction;
|
||||
|
||||
@override
|
||||
T? resolve(Set<WidgetState> states) {
|
||||
final T? resolvedA = a?.resolve(states);
|
||||
final T? resolvedB = b?.resolve(states);
|
||||
return lerpFunction(resolvedA, resolvedB, t);
|
||||
}
|
||||
}
|
||||
|
||||
class _WidgetStatePropertyWith<T> implements WidgetStateProperty<T> {
|
||||
_WidgetStatePropertyWith(this._resolve);
|
||||
|
||||
final WidgetPropertyResolver<T> _resolve;
|
||||
|
||||
@override
|
||||
T resolve(Set<WidgetState> states) => _resolve(states);
|
||||
}
|
||||
|
||||
/// Convenience class for creating a [WidgetStateProperty] that
|
||||
/// resolves to the given value for all states.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStatePropertyAll], the Material specific version of
|
||||
/// `WidgetStatePropertyAll`.
|
||||
class WidgetStatePropertyAll<T> implements WidgetStateProperty<T> {
|
||||
|
||||
/// Constructs a [WidgetStateProperty] that always resolves to the given
|
||||
/// value.
|
||||
const WidgetStatePropertyAll(this.value);
|
||||
|
||||
/// The value of the property that will be used for all states.
|
||||
final T value;
|
||||
|
||||
@override
|
||||
T resolve(Set<WidgetState> states) => value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (value is double) {
|
||||
return 'WidgetStatePropertyAll(${debugFormatDouble(value as double)})';
|
||||
} else {
|
||||
return 'WidgetStatePropertyAll($value)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Manages a set of [WidgetState]s and notifies listeners of changes.
|
||||
///
|
||||
/// Used by widgets that expose their internal state for the sake of
|
||||
/// extensions that add support for additional states. See
|
||||
/// [TextButton] for an example.
|
||||
///
|
||||
/// The controller's [value] is its current set of states. Listeners
|
||||
/// are notified whenever the [value] changes. The [value] should only be
|
||||
/// changed with [update]; it should not be modified directly.
|
||||
///
|
||||
/// The controller's [value] represents the set of states that a
|
||||
/// widget's visual properties, typically [WidgetStateProperty]
|
||||
/// values, are resolved against. It is _not_ the intrinsic state of
|
||||
/// the widget. The widget is responsible for ensuring that the
|
||||
/// controller's [value] tracks its intrinsic state. For example one
|
||||
/// cannot request the keyboard focus for a widget by adding
|
||||
/// [WidgetState.focused] to its controller. When the widget gains the
|
||||
/// or loses the focus it will [update] its controller's [value] and
|
||||
/// notify listeners of the change.
|
||||
///
|
||||
/// When calling `setState` in a [MaterialStatesController] listener, use the
|
||||
/// [SchedulerBinding.addPostFrameCallback] to delay the call to `setState` after
|
||||
/// the frame has been rendered. It's generally prudent to use the
|
||||
/// [SchedulerBinding.addPostFrameCallback] because some of the widgets that
|
||||
/// depend on [MaterialStatesController] may call [update] in their build method.
|
||||
/// In such cases, listener's that call `setState` - during the build phase - will cause
|
||||
/// an error.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialStatesController], the Material specific version of
|
||||
/// `WidgetStatesController`.
|
||||
class WidgetStatesController extends ValueNotifier<Set<WidgetState>> {
|
||||
/// Creates a WidgetStatesController.
|
||||
WidgetStatesController([Set<WidgetState>? value]) : super(<WidgetState>{...?value});
|
||||
|
||||
/// Adds [state] to [value] if [add] is true, and removes it otherwise,
|
||||
/// and notifies listeners if [value] has changed.
|
||||
void update(WidgetState state, bool add) {
|
||||
final bool valueChanged = add ? value.add(state) : value.remove(state);
|
||||
if (valueChanged) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -164,4 +164,5 @@ export 'src/widgets/viewport.dart';
|
|||
export 'src/widgets/visibility.dart';
|
||||
export 'src/widgets/widget_inspector.dart';
|
||||
export 'src/widgets/widget_span.dart';
|
||||
export 'src/widgets/widget_state.dart';
|
||||
export 'src/widgets/will_pop_scope.dart';
|
||||
|
|
|
@ -102,7 +102,7 @@ void main() {
|
|||
expect(description[8], 'showSelectedLabels: true');
|
||||
expect(description[9], 'showUnselectedLabels: true');
|
||||
expect(description[10], 'type: BottomNavigationBarType.fixed');
|
||||
expect(description[11], 'mouseCursor: MaterialStateMouseCursor(clickable)');
|
||||
expect(description[11], 'mouseCursor: WidgetStateMouseCursor(clickable)');
|
||||
});
|
||||
|
||||
testWidgets('BottomNavigationBar is themeable', (WidgetTester tester) async {
|
||||
|
|
|
@ -85,21 +85,21 @@ void main() {
|
|||
.toList();
|
||||
|
||||
expect(description, <String>[
|
||||
'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 10.0))',
|
||||
'backgroundColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
||||
'foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2))',
|
||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff3))',
|
||||
'shadowColor: MaterialStatePropertyAll(Color(0xfffffff4))',
|
||||
'surfaceTintColor: MaterialStatePropertyAll(Color(0xfffffff5))',
|
||||
'elevation: MaterialStatePropertyAll(1.5)',
|
||||
'padding: MaterialStatePropertyAll(EdgeInsets.all(1.0))',
|
||||
'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))',
|
||||
'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))',
|
||||
'iconColor: MaterialStatePropertyAll(Color(0xfffffff6))',
|
||||
'iconSize: MaterialStatePropertyAll(48.1)',
|
||||
'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))',
|
||||
'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))',
|
||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))',
|
||||
'textStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 10.0))',
|
||||
'backgroundColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||
'foregroundColor: WidgetStatePropertyAll(Color(0xfffffff2))',
|
||||
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff3))',
|
||||
'shadowColor: WidgetStatePropertyAll(Color(0xfffffff4))',
|
||||
'surfaceTintColor: WidgetStatePropertyAll(Color(0xfffffff5))',
|
||||
'elevation: WidgetStatePropertyAll(1.5)',
|
||||
'padding: WidgetStatePropertyAll(EdgeInsets.all(1.0))',
|
||||
'minimumSize: WidgetStatePropertyAll(Size(1.0, 2.0))',
|
||||
'maximumSize: WidgetStatePropertyAll(Size(100.0, 200.0))',
|
||||
'iconColor: WidgetStatePropertyAll(Color(0xfffffff6))',
|
||||
'iconSize: WidgetStatePropertyAll(48.1)',
|
||||
'side: WidgetStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))',
|
||||
'shape: WidgetStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))',
|
||||
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(forbidden))',
|
||||
'tapTargetSize: shrinkWrap',
|
||||
'animationDuration: 0:00:01.000000',
|
||||
'enableFeedback: true',
|
||||
|
|
|
@ -71,10 +71,10 @@ void main() {
|
|||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
||||
'checkColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))',
|
||||
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||
'checkColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff2))',
|
||||
'splashRadius: 1.0',
|
||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||
|
|
|
@ -129,7 +129,7 @@ void main() {
|
|||
.toList();
|
||||
|
||||
expect(description, equalsIgnoringHashCodes(<String>[
|
||||
'color: MaterialStatePropertyAll(Color(0xfffffff0))',
|
||||
'color: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||
'backgroundColor: Color(0xfffffff1)',
|
||||
'deleteIconColor: Color(0xfffffff2)',
|
||||
'disabledColor: Color(0xfffffff3)',
|
||||
|
|
|
@ -105,19 +105,19 @@ void main() {
|
|||
.toList();
|
||||
|
||||
expect(description[0], 'decoration: BoxDecoration(color: Color(0xfffffff0))');
|
||||
expect(description[1], "dataRowColor: Instance of '_MaterialStatePropertyWith<Color>'");
|
||||
expect(description[1], "dataRowColor: Instance of '_WidgetStatePropertyWith<Color>'");
|
||||
expect(description[2], 'dataRowMinHeight: 41.0');
|
||||
expect(description[3], 'dataRowMaxHeight: 42.0');
|
||||
expect(description[4], 'dataTextStyle: TextStyle(inherit: true, size: 12.0)');
|
||||
expect(description[5], "headingRowColor: Instance of '_MaterialStatePropertyWith<Color>'");
|
||||
expect(description[5], "headingRowColor: Instance of '_WidgetStatePropertyWith<Color>'");
|
||||
expect(description[6], 'headingRowHeight: 52.0');
|
||||
expect(description[7], 'headingTextStyle: TextStyle(inherit: true, size: 14.0)');
|
||||
expect(description[8], 'horizontalMargin: 3.0');
|
||||
expect(description[9], 'columnSpacing: 4.0');
|
||||
expect(description[10], 'dividerThickness: 5.0');
|
||||
expect(description[11], 'checkboxHorizontalMargin: 6.0');
|
||||
expect(description[12], 'headingCellCursor: MaterialStatePropertyAll(SystemMouseCursor(grab))');
|
||||
expect(description[13], 'dataRowCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))');
|
||||
expect(description[12], 'headingCellCursor: WidgetStatePropertyAll(SystemMouseCursor(grab))');
|
||||
expect(description[13], 'dataRowCursor: WidgetStatePropertyAll(SystemMouseCursor(forbidden))');
|
||||
});
|
||||
|
||||
testWidgets('DataTable is themeable', (WidgetTester tester) async {
|
||||
|
|
|
@ -329,17 +329,17 @@ void main() {
|
|||
'headerHelpStyle: TextStyle(inherit: true, size: 11.0)',
|
||||
'weekDayStyle: TextStyle(inherit: true, size: 12.0)',
|
||||
'dayStyle: TextStyle(inherit: true, size: 13.0)',
|
||||
'dayForegroundColor: MaterialStatePropertyAll(Color(0xfffffff5))',
|
||||
'dayBackgroundColor: MaterialStatePropertyAll(Color(0xfffffff6))',
|
||||
'dayOverlayColor: MaterialStatePropertyAll(Color(0xfffffff7))',
|
||||
'dayShape: MaterialStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
|
||||
'todayForegroundColor: MaterialStatePropertyAll(Color(0xfffffff8))',
|
||||
'todayBackgroundColor: MaterialStatePropertyAll(Color(0xfffffff9))',
|
||||
'dayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff5))',
|
||||
'dayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff6))',
|
||||
'dayOverlayColor: WidgetStatePropertyAll(Color(0xfffffff7))',
|
||||
'dayShape: WidgetStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
|
||||
'todayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff8))',
|
||||
'todayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff9))',
|
||||
'todayBorder: BorderSide(width: 3.0)',
|
||||
'yearStyle: TextStyle(inherit: true, size: 13.0)',
|
||||
'yearForegroundColor: MaterialStatePropertyAll(Color(0xfffffffa))',
|
||||
'yearBackgroundColor: MaterialStatePropertyAll(Color(0xfffffffb))',
|
||||
'yearOverlayColor: MaterialStatePropertyAll(Color(0xfffffffc))',
|
||||
'yearForegroundColor: WidgetStatePropertyAll(Color(0xfffffffa))',
|
||||
'yearBackgroundColor: WidgetStatePropertyAll(Color(0xfffffffb))',
|
||||
'yearOverlayColor: WidgetStatePropertyAll(Color(0xfffffffc))',
|
||||
'rangePickerBackgroundColor: Color(0xfffffffd)',
|
||||
'rangePickerElevation: 7.0',
|
||||
'rangePickerShadowColor: Color(0xfffffffe)',
|
||||
|
@ -350,11 +350,11 @@ void main() {
|
|||
'rangePickerHeaderHeadlineStyle: TextStyle(inherit: true, size: 14.0)',
|
||||
'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)',
|
||||
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
|
||||
'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))',
|
||||
'rangeSelectionOverlayColor: WidgetStatePropertyAll(Color(0xffffff3f))',
|
||||
'dividerColor: Color(0xffffff4f)',
|
||||
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())',
|
||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff6f)))',
|
||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff7f)))'
|
||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff6f)))',
|
||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff7f)))'
|
||||
]));
|
||||
});
|
||||
|
||||
|
|
|
@ -422,7 +422,7 @@ void main() {
|
|||
'extendedIconLabelSpacing: 12.0',
|
||||
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
|
||||
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
|
||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
||||
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ void main() {
|
|||
'minVerticalPadding: 300.0',
|
||||
'minLeadingWidth: 400.0',
|
||||
'enableFeedback: true',
|
||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
||||
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||
'visualDensity: VisualDensity#00000(h: -1.0, v: -1.0)(horizontal: -1.0, vertical: -1.0)',
|
||||
'titleAlignment: ListTileTitleAlignment.top',
|
||||
]),
|
||||
|
|
|
@ -45,10 +45,10 @@ void main() {
|
|||
|
||||
test('toString formats correctly', () {
|
||||
const MaterialStateProperty<Color?> colorProperty = MaterialStatePropertyAll<Color?>(Color(0xFFFFFFFF));
|
||||
expect(colorProperty.toString(), equals('MaterialStatePropertyAll(Color(0xffffffff))'));
|
||||
expect(colorProperty.toString(), equals('WidgetStatePropertyAll(Color(0xffffffff))'));
|
||||
|
||||
const MaterialStateProperty<double?> doubleProperty = MaterialStatePropertyAll<double?>(33 + 1/3);
|
||||
expect(doubleProperty.toString(), equals('MaterialStatePropertyAll(33.3)'));
|
||||
expect(doubleProperty.toString(), equals('WidgetStatePropertyAll(33.3)'));
|
||||
});
|
||||
|
||||
test("Can interpolate between two MaterialStateProperty's", () {
|
||||
|
|
|
@ -1293,7 +1293,7 @@ void main() {
|
|||
expect(
|
||||
description.join('\n'),
|
||||
equalsIgnoringHashCodes(
|
||||
'style: MenuStyle#00000(backgroundColor: MaterialStatePropertyAll(MaterialColor(primary value: Color(0xfff44336))), elevation: MaterialStatePropertyAll(10.0))\n'
|
||||
'style: MenuStyle#00000(backgroundColor: WidgetStatePropertyAll(MaterialColor(primary value: Color(0xfff44336))), elevation: WidgetStatePropertyAll(10.0))\n'
|
||||
'clipBehavior: Clip.none'),
|
||||
);
|
||||
});
|
||||
|
@ -2357,7 +2357,7 @@ void main() {
|
|||
equalsIgnoringHashCodes(
|
||||
<String>[
|
||||
'focusNode: null',
|
||||
'menuStyle: MenuStyle#00000(backgroundColor: MaterialStatePropertyAll(MaterialColor(primary value: Color(0xff4caf50))), elevation: MaterialStatePropertyAll(20.0), shape: MaterialStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)))',
|
||||
'menuStyle: MenuStyle#00000(backgroundColor: WidgetStatePropertyAll(MaterialColor(primary value: Color(0xff4caf50))), elevation: WidgetStatePropertyAll(20.0), shape: WidgetStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)))',
|
||||
'alignmentOffset: null',
|
||||
'clipBehavior: hardEdge',
|
||||
],
|
||||
|
|
|
@ -62,12 +62,12 @@ void main() {
|
|||
expect(description[2], 'elevation: 20.0');
|
||||
expect(description[3], 'indicatorColor: Color(0x00000098)');
|
||||
expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))');
|
||||
expect(description[5], 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))');
|
||||
expect(description[5], 'labelTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 7.0))');
|
||||
// Ignore instance address for IconThemeData.
|
||||
expect(description[6].contains('iconTheme: MaterialStatePropertyAll(IconThemeData'), isTrue);
|
||||
expect(description[6].contains('iconTheme: WidgetStatePropertyAll(IconThemeData'), isTrue);
|
||||
expect(description[6].contains('(color: Color(0x00000097))'), isTrue);
|
||||
expect(description[7], 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide');
|
||||
expect(description[8], 'overlayColor: MaterialStatePropertyAll(Color(0x00000096))');
|
||||
expect(description[8], 'overlayColor: WidgetStatePropertyAll(Color(0x00000096))');
|
||||
});
|
||||
|
||||
testWidgets('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async {
|
||||
|
|
|
@ -60,8 +60,8 @@ void main() {
|
|||
'indicatorColor: Color(0x00000096)',
|
||||
'indicatorShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))',
|
||||
'indicatorSize: Size(10.0, 10.0)',
|
||||
'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))',
|
||||
'iconTheme: MaterialStatePropertyAll(IconThemeData#00000(color: Color(0x00000095)))'
|
||||
'labelTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 7.0))',
|
||||
'iconTheme: WidgetStatePropertyAll(IconThemeData#00000(color: Color(0x00000095)))'
|
||||
],
|
||||
));
|
||||
});
|
||||
|
|
|
@ -117,9 +117,9 @@ void main() {
|
|||
'shadowColor: Color(0xfffffff2)',
|
||||
'surfaceTintColor: Color(0xfffffff3)',
|
||||
'text style: TextStyle(inherit: true, color: Color(0xfffffff4))',
|
||||
"labelTextStyle: Instance of '_MaterialStatePropertyWith<TextStyle?>'",
|
||||
"labelTextStyle: Instance of '_WidgetStatePropertyWith<TextStyle?>'",
|
||||
'enableFeedback: false',
|
||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
||||
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||
'position: over',
|
||||
'iconColor: Color(0xfffffff8)',
|
||||
'iconSize: 31.0'
|
||||
|
|
|
@ -68,9 +68,9 @@ void main() {
|
|||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
||||
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||
'splashRadius: 1.0',
|
||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||
|
|
|
@ -741,12 +741,12 @@ void main() {
|
|||
.toList();
|
||||
|
||||
expect(description, <String>[
|
||||
"thumbVisibility: Instance of '_MaterialStatePropertyWith<bool?>'",
|
||||
"thickness: Instance of '_MaterialStatePropertyWith<double?>'",
|
||||
"thumbVisibility: Instance of '_WidgetStatePropertyWith<bool?>'",
|
||||
"thickness: Instance of '_WidgetStatePropertyWith<double?>'",
|
||||
'radius: Radius.circular(3.0)',
|
||||
"thumbColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
||||
"trackColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
||||
"trackBorderColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
||||
"thumbColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||
"trackColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||
"trackBorderColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||
'crossAxisMargin: 3.0',
|
||||
'mainAxisMargin: 6.0',
|
||||
'minThumbLength: 120.0',
|
||||
|
|
|
@ -85,16 +85,16 @@ void main() {
|
|||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'elevation: MaterialStatePropertyAll(3.0)');
|
||||
expect(description[1], 'backgroundColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[2], 'shadowColor: MaterialStatePropertyAll(Color(0xfffffff2))');
|
||||
expect(description[3], 'surfaceTintColor: MaterialStatePropertyAll(Color(0xfffffff3))');
|
||||
expect(description[4], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff4))');
|
||||
expect(description[5], 'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff5), width: 2.0))');
|
||||
expect(description[6], 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))');
|
||||
expect(description[7], 'padding: MaterialStatePropertyAll(EdgeInsets.all(16.0))');
|
||||
expect(description[8], 'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 24.0))');
|
||||
expect(description[9], 'hintStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 16.0))');
|
||||
expect(description[0], 'elevation: WidgetStatePropertyAll(3.0)');
|
||||
expect(description[1], 'backgroundColor: WidgetStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[2], 'shadowColor: WidgetStatePropertyAll(Color(0xfffffff2))');
|
||||
expect(description[3], 'surfaceTintColor: WidgetStatePropertyAll(Color(0xfffffff3))');
|
||||
expect(description[4], 'overlayColor: WidgetStatePropertyAll(Color(0xfffffff4))');
|
||||
expect(description[5], 'side: WidgetStatePropertyAll(BorderSide(color: Color(0xfffffff5), width: 2.0))');
|
||||
expect(description[6], 'shape: WidgetStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))');
|
||||
expect(description[7], 'padding: WidgetStatePropertyAll(EdgeInsets.all(16.0))');
|
||||
expect(description[8], 'textStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 24.0))');
|
||||
expect(description[9], 'hintStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 16.0))');
|
||||
expect(description[10], 'constraints: BoxConstraints(350.0<=w<=850.0, 0.0<=h<=Infinity)');
|
||||
expect(description[11], 'textCapitalization: TextCapitalization.characters');
|
||||
});
|
||||
|
|
|
@ -99,7 +99,7 @@ void main() {
|
|||
"rangeValueIndicatorShape: Instance of 'PaddleRangeSliderValueIndicatorShape'",
|
||||
'showValueIndicator: always',
|
||||
'valueIndicatorTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
|
||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
||||
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||
'allowedInteraction: tapOnly'
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -73,15 +73,15 @@ void main() {
|
|||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'thumbColor: MaterialStatePropertyAll(Color(0xfffffff0))');
|
||||
expect(description[1], 'trackColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[2], 'trackOutlineColor: MaterialStatePropertyAll(Color(0xfffffff3))');
|
||||
expect(description[3], 'trackOutlineWidth: MaterialStatePropertyAll(6.0)');
|
||||
expect(description[0], 'thumbColor: WidgetStatePropertyAll(Color(0xfffffff0))');
|
||||
expect(description[1], 'trackColor: WidgetStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[2], 'trackOutlineColor: WidgetStatePropertyAll(Color(0xfffffff3))');
|
||||
expect(description[3], 'trackOutlineWidth: WidgetStatePropertyAll(6.0)');
|
||||
expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
|
||||
expect(description[5], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))');
|
||||
expect(description[6], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))');
|
||||
expect(description[5], 'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))');
|
||||
expect(description[6], 'overlayColor: WidgetStatePropertyAll(Color(0xfffffff2))');
|
||||
expect(description[7], 'splashRadius: 1.0');
|
||||
expect(description[8], 'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))');
|
||||
expect(description[8], 'thumbIcon: WidgetStatePropertyAll(Icon(IconData(U+0007B)))');
|
||||
});
|
||||
|
||||
testWidgets('Material2 - Switch is themeable', (WidgetTester tester) async {
|
||||
|
|
|
@ -91,8 +91,8 @@ void main() {
|
|||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: Color(0xfffffff3)),
|
||||
),
|
||||
timeSelectorSeparatorColor: MaterialStatePropertyAll<Color>(Color(0xfffffff4)),
|
||||
timeSelectorSeparatorTextStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(color: Color(0xfffffff5))),
|
||||
timeSelectorSeparatorColor: WidgetStatePropertyAll<Color>(Color(0xfffffff4)),
|
||||
timeSelectorSeparatorTextStyle: WidgetStatePropertyAll<TextStyle>(TextStyle(color: Color(0xfffffff5))),
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
|
@ -102,8 +102,8 @@ void main() {
|
|||
|
||||
expect(description, equalsIgnoringHashCodes(<String>[
|
||||
'backgroundColor: Color(0xfffffff0)',
|
||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff1)))',
|
||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2)))',
|
||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xfffffff1)))',
|
||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xfffffff2)))',
|
||||
'dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3))',
|
||||
'dayPeriodColor: Color(0x00000000)',
|
||||
'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff5)), BorderRadius.zero)',
|
||||
|
@ -123,8 +123,8 @@ void main() {
|
|||
'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))',
|
||||
'padding: EdgeInsets.all(1.0)',
|
||||
'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)',
|
||||
'timeSelectorSeparatorColor: MaterialStatePropertyAll(Color(0xfffffff4))',
|
||||
'timeSelectorSeparatorTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, color: Color(0xfffffff5)))'
|
||||
'timeSelectorSeparatorColor: WidgetStatePropertyAll(Color(0xfffffff4))',
|
||||
'timeSelectorSeparatorTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, color: Color(0xfffffff5)))'
|
||||
]));
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
// 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 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
|
||||
void main() {
|
||||
test('WidgetStateProperty.resolveWith()', () {
|
||||
final WidgetStateProperty<WidgetState> value = WidgetStateProperty.resolveWith<WidgetState>(
|
||||
(Set<WidgetState> states) => states.first,
|
||||
);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.hovered}), WidgetState.hovered);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.focused}), WidgetState.focused);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.pressed}), WidgetState.pressed);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.dragged}), WidgetState.dragged);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.selected}), WidgetState.selected);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.disabled}), WidgetState.disabled);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.error}), WidgetState.error);
|
||||
});
|
||||
|
||||
test('WidgetStateProperty.all()', () {
|
||||
final WidgetStateProperty<int> value = WidgetStateProperty.all<int>(123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.hovered}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.focused}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.pressed}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.dragged}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.selected}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.disabled}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.error}), 123);
|
||||
});
|
||||
|
||||
test('WidgetStatePropertyAll', () {
|
||||
const WidgetStatePropertyAll<int> value = WidgetStatePropertyAll<int>(123);
|
||||
expect(value.resolve(<WidgetState>{}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.hovered}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.focused}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.pressed}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.dragged}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.selected}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.disabled}), 123);
|
||||
expect(value.resolve(<WidgetState>{WidgetState.error}), 123);
|
||||
});
|
||||
|
||||
test('toString formats correctly', () {
|
||||
const WidgetStateProperty<Color?> colorProperty = WidgetStatePropertyAll<Color?>(Color(0xFFFFFFFF));
|
||||
expect(colorProperty.toString(), equals('WidgetStatePropertyAll(Color(0xffffffff))'));
|
||||
|
||||
const WidgetStateProperty<double?> doubleProperty = WidgetStatePropertyAll<double?>(33 + 1/3);
|
||||
expect(doubleProperty.toString(), equals('WidgetStatePropertyAll(33.3)'));
|
||||
});
|
||||
|
||||
test("Can interpolate between two WidgetStateProperty's", () {
|
||||
const WidgetStateProperty<TextStyle?> textStyle1 = WidgetStatePropertyAll<TextStyle?>(
|
||||
TextStyle(fontSize: 14.0),
|
||||
);
|
||||
const WidgetStateProperty<TextStyle?> textStyle2 = WidgetStatePropertyAll<TextStyle?>(
|
||||
TextStyle(fontSize: 20.0),
|
||||
);
|
||||
|
||||
// Using `0.0` interpolation value.
|
||||
TextStyle textStyle = WidgetStateProperty.lerp<TextStyle?>(
|
||||
textStyle1,
|
||||
textStyle2,
|
||||
0.0,
|
||||
TextStyle.lerp,
|
||||
)!.resolve(enabled)!;
|
||||
expect(textStyle.fontSize, 14.0);
|
||||
|
||||
// Using `0.5` interpolation value.
|
||||
textStyle = WidgetStateProperty.lerp<TextStyle?>(
|
||||
textStyle1,
|
||||
textStyle2,
|
||||
0.5,
|
||||
TextStyle.lerp,
|
||||
)!.resolve(enabled)!;
|
||||
expect(textStyle.fontSize, 17.0);
|
||||
|
||||
// Using `1.0` interpolation value.
|
||||
textStyle = WidgetStateProperty.lerp<TextStyle?>(
|
||||
textStyle1,
|
||||
textStyle2,
|
||||
1.0,
|
||||
TextStyle.lerp,
|
||||
)!.resolve(enabled)!;
|
||||
expect(textStyle.fontSize, 20.0);
|
||||
});
|
||||
}
|
||||
|
||||
Set<WidgetState> enabled = <WidgetState>{};
|
|
@ -0,0 +1,93 @@
|
|||
// 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 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
|
||||
|
||||
void main() {
|
||||
test('WidgetStatesController constructor', () {
|
||||
expect(WidgetStatesController().value, <WidgetState>{});
|
||||
expect(WidgetStatesController(<WidgetState>{}).value, <WidgetState>{});
|
||||
expect(WidgetStatesController(<WidgetState>{WidgetState.selected}).value, <WidgetState>{WidgetState.selected});
|
||||
});
|
||||
|
||||
test('WidgetStatesController dispatches memory events', () async {
|
||||
await expectLater(
|
||||
await memoryEvents(() => WidgetStatesController().dispose(), WidgetStatesController),
|
||||
areCreateAndDispose,
|
||||
);
|
||||
});
|
||||
|
||||
test('WidgetStatesController update, listener', () {
|
||||
int count = 0;
|
||||
void valueChanged() {
|
||||
count += 1;
|
||||
}
|
||||
final WidgetStatesController controller = WidgetStatesController();
|
||||
controller.addListener(valueChanged);
|
||||
|
||||
controller.update(WidgetState.selected, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.selected});
|
||||
expect(count, 1);
|
||||
controller.update(WidgetState.selected, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.selected});
|
||||
expect(count, 1);
|
||||
|
||||
controller.update(WidgetState.hovered, false);
|
||||
expect(count, 1);
|
||||
expect(controller.value, <WidgetState>{WidgetState.selected});
|
||||
controller.update(WidgetState.selected, false);
|
||||
expect(count, 2);
|
||||
expect(controller.value, <WidgetState>{});
|
||||
|
||||
controller.update(WidgetState.hovered, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered});
|
||||
expect(count, 3);
|
||||
controller.update(WidgetState.hovered, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered});
|
||||
expect(count, 3);
|
||||
controller.update(WidgetState.pressed, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered, WidgetState.pressed});
|
||||
expect(count, 4);
|
||||
controller.update(WidgetState.selected, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered, WidgetState.pressed, WidgetState.selected});
|
||||
expect(count, 5);
|
||||
controller.update(WidgetState.selected, false);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered, WidgetState.pressed});
|
||||
expect(count, 6);
|
||||
controller.update(WidgetState.selected, false);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered, WidgetState.pressed});
|
||||
expect(count, 6);
|
||||
controller.update(WidgetState.pressed, false);
|
||||
expect(controller.value, <WidgetState>{WidgetState.hovered});
|
||||
expect(count, 7);
|
||||
controller.update(WidgetState.hovered, false);
|
||||
expect(controller.value, <WidgetState>{});
|
||||
expect(count, 8);
|
||||
|
||||
controller.removeListener(valueChanged);
|
||||
controller.update(WidgetState.selected, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.selected});
|
||||
expect(count, 8);
|
||||
});
|
||||
|
||||
|
||||
test('WidgetStatesController const initial value', () {
|
||||
int count = 0;
|
||||
void valueChanged() {
|
||||
count += 1;
|
||||
}
|
||||
final WidgetStatesController controller = WidgetStatesController(const <WidgetState>{WidgetState.selected});
|
||||
controller.addListener(valueChanged);
|
||||
|
||||
controller.update(WidgetState.selected, true);
|
||||
expect(controller.value, <WidgetState>{WidgetState.selected});
|
||||
expect(count, 0);
|
||||
|
||||
controller.update(WidgetState.selected, false);
|
||||
expect(controller.value, <WidgetState>{});
|
||||
expect(count, 1);
|
||||
});
|
||||
}
|
|
@ -137,40 +137,40 @@ void main() {
|
|||
// Changes made in https://github.com/flutter/flutter/pull/97972
|
||||
ThemeData themeData = ThemeData();
|
||||
themeData = ThemeData(checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
@ -178,40 +178,40 @@ void main() {
|
|||
));
|
||||
themeData = ThemeData(
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
@ -219,40 +219,40 @@ void main() {
|
|||
),
|
||||
);
|
||||
themeData = ThemeData.raw(checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
@ -260,40 +260,40 @@ void main() {
|
|||
));
|
||||
themeData = ThemeData.raw(
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
@ -301,40 +301,40 @@ void main() {
|
|||
),
|
||||
);
|
||||
themeData = themeData.copyWith(checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
@ -342,40 +342,40 @@ void main() {
|
|||
));
|
||||
themeData = themeData.copyWith(
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), radioTheme: RadioThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
), switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Colors.black;
|
||||
}
|
||||
return null;
|
||||
|
|
115
packages/flutter/test_fixes/material/widget_state.dart
Normal file
115
packages/flutter/test_fixes/material/widget_state.dart
Normal file
|
@ -0,0 +1,115 @@
|
|||
// 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';
|
||||
|
||||
void main() {
|
||||
// Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
MaterialState selected = MaterialState.selected;
|
||||
MaterialState hovered = MaterialState.hovered;
|
||||
MaterialState focused = MaterialState.focused;
|
||||
MaterialState pressed = MaterialState.pressed;
|
||||
MaterialState dragged = MaterialState.dragged;
|
||||
MaterialState scrolledUnder = MaterialState.scrolledUnder;
|
||||
MaterialState disabled = MaterialState.disabled;
|
||||
MaterialState error = MaterialState.error;
|
||||
|
||||
final MaterialPropertyResolver<MouseCursor?> resolveCallback;
|
||||
|
||||
Color getColor(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return Color(0xFF000002);
|
||||
}
|
||||
return Color(0xFF000004);
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return Color(0xFF000001);
|
||||
}
|
||||
return Color(0xFF000003);
|
||||
}
|
||||
|
||||
final MaterialStateProperty<Color> backgroundColor = MaterialStateColor.resolveWith(getColor);
|
||||
|
||||
class _MouseCursor extends MaterialStateMouseCursor {
|
||||
const _MouseCursor(this.resolveCallback);
|
||||
|
||||
final MaterialPropertyResolver<MouseCursor?> resolveCallback;
|
||||
|
||||
@override
|
||||
MouseCursor resolve(Set<MaterialState> states) => resolveCallback(states) ?? MouseCursor.uncontrolled;
|
||||
}
|
||||
|
||||
MaterialStateBorderSide? get side {
|
||||
return MaterialStateBorderSide.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return const BorderSide(width: 2.0);
|
||||
}
|
||||
return BorderSide(width: 1.0);
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return const BorderSide(width: 1.5);
|
||||
}
|
||||
return BorderSide(width: 0.5);
|
||||
});
|
||||
}
|
||||
|
||||
class SelectedBorder extends RoundedRectangleBorder implements MaterialStateOutlinedBorder {
|
||||
const SelectedBorder();
|
||||
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return const RoundedRectangleBorder();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
TextStyle floatingLabelStyle = MaterialStateTextStyle.resolveWith(
|
||||
(Set<MaterialState> states) {
|
||||
final Color color =
|
||||
states.contains(MaterialState.error) ? Theme.of(context).colorScheme.error : Colors.orange;
|
||||
return TextStyle(color: color, letterSpacing: 1.3);
|
||||
},
|
||||
);
|
||||
|
||||
final MaterialStateProperty<Icon?> thumbIcon =
|
||||
MaterialStateProperty.resolveWith<Icon?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return const Icon(Icons.check);
|
||||
}
|
||||
return const Icon(Icons.close);
|
||||
});
|
||||
|
||||
final Color backgroundColor = MaterialStatePropertyAll<Color>(
|
||||
Colors.blue.withOpacity(0.12),
|
||||
);
|
||||
|
||||
final MaterialStatesController statesController =
|
||||
MaterialStatesController(<MaterialState>{if (widget.selected) MaterialState.selected});
|
||||
|
||||
class _MyWidget extends StatefulWidget {
|
||||
const _MyWidget({
|
||||
required this.controller,
|
||||
required this.evaluator,
|
||||
required this.materialState,
|
||||
});
|
||||
|
||||
final bool Function(_MyWidgetState state) evaluator;
|
||||
|
||||
/// Stream passed down to the child [_InnerWidget] to begin the process.
|
||||
/// This plays the role of an actual user interaction in the wild, but allows
|
||||
/// us to engage the system without mocking pointers/hovers etc.
|
||||
final StreamController<bool> controller;
|
||||
|
||||
/// The value we're watching in the given test.
|
||||
final MaterialState materialState;
|
||||
|
||||
@override
|
||||
State createState() => _MyWidgetState();
|
||||
}
|
||||
|
||||
}
|
115
packages/flutter/test_fixes/material/widget_state.dart.expect
Normal file
115
packages/flutter/test_fixes/material/widget_state.dart.expect
Normal file
|
@ -0,0 +1,115 @@
|
|||
// 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';
|
||||
|
||||
void main() {
|
||||
// Changes made in https://github.com/flutter/flutter/pull/142151
|
||||
WidgetState selected = WidgetState.selected;
|
||||
WidgetState hovered = WidgetState.hovered;
|
||||
WidgetState focused = WidgetState.focused;
|
||||
WidgetState pressed = WidgetState.pressed;
|
||||
WidgetState dragged = WidgetState.dragged;
|
||||
WidgetState scrolledUnder = WidgetState.scrolledUnder;
|
||||
WidgetState disabled = WidgetState.disabled;
|
||||
WidgetState error = WidgetState.error;
|
||||
|
||||
final WidgetPropertyResolver<MouseCursor?> resolveCallback;
|
||||
|
||||
Color getColor(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Color(0xFF000002);
|
||||
}
|
||||
return Color(0xFF000004);
|
||||
}
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return Color(0xFF000001);
|
||||
}
|
||||
return Color(0xFF000003);
|
||||
}
|
||||
|
||||
final WidgetStateProperty<Color> backgroundColor = WidgetStateColor.resolveWith(getColor);
|
||||
|
||||
class _MouseCursor extends WidgetStateMouseCursor {
|
||||
const _MouseCursor(this.resolveCallback);
|
||||
|
||||
final WidgetPropertyResolver<MouseCursor?> resolveCallback;
|
||||
|
||||
@override
|
||||
MouseCursor resolve(Set<WidgetState> states) => resolveCallback(states) ?? MouseCursor.uncontrolled;
|
||||
}
|
||||
|
||||
WidgetStateBorderSide? get side {
|
||||
return WidgetStateBorderSide.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const BorderSide(width: 2.0);
|
||||
}
|
||||
return BorderSide(width: 1.0);
|
||||
}
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const BorderSide(width: 1.5);
|
||||
}
|
||||
return BorderSide(width: 0.5);
|
||||
});
|
||||
}
|
||||
|
||||
class SelectedBorder extends RoundedRectangleBorder implements WidgetStateOutlinedBorder {
|
||||
const SelectedBorder();
|
||||
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const RoundedRectangleBorder();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
TextStyle floatingLabelStyle = WidgetStateTextStyle.resolveWith(
|
||||
(Set<WidgetState> states) {
|
||||
final Color color =
|
||||
states.contains(WidgetState.error) ? Theme.of(context).colorScheme.error : Colors.orange;
|
||||
return TextStyle(color: color, letterSpacing: 1.3);
|
||||
},
|
||||
);
|
||||
|
||||
final WidgetStateProperty<Icon?> thumbIcon =
|
||||
WidgetStateProperty.resolveWith<Icon?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Icon(Icons.check);
|
||||
}
|
||||
return const Icon(Icons.close);
|
||||
});
|
||||
|
||||
final Color backgroundColor = WidgetStatePropertyAll<Color>(
|
||||
Colors.blue.withOpacity(0.12),
|
||||
);
|
||||
|
||||
final WidgetStatesController statesController =
|
||||
WidgetStatesController(<WidgetState>{if (widget.selected) WidgetState.selected});
|
||||
|
||||
class _MyWidget extends StatefulWidget {
|
||||
const _MyWidget({
|
||||
required this.controller,
|
||||
required this.evaluator,
|
||||
required this.materialState,
|
||||
});
|
||||
|
||||
final bool Function(_MyWidgetState state) evaluator;
|
||||
|
||||
/// Stream passed down to the child [_InnerWidget] to begin the process.
|
||||
/// This plays the role of an actual user interaction in the wild, but allows
|
||||
/// us to engage the system without mocking pointers/hovers etc.
|
||||
final StreamController<bool> controller;
|
||||
|
||||
/// The value we're watching in the given test.
|
||||
final WidgetState materialState;
|
||||
|
||||
@override
|
||||
State createState() => _MyWidgetState();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue