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(
|
style: TextButton.styleFrom(
|
||||||
overlayColor: Colors.transparent,
|
overlayColor: Colors.transparent,
|
||||||
foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
|
foregroundBuilder: (BuildContext context, Set<WidgetState> states, Widget? child) {
|
||||||
late final ImageProvider image;
|
late final ImageProvider image;
|
||||||
if (currentAction != null) {
|
if (currentAction != null) {
|
||||||
image = runningImage;
|
image = runningImage;
|
||||||
} else if (states.contains(MaterialState.pressed)) {
|
} else if (states.contains(WidgetState.pressed)) {
|
||||||
image = pressedImage;
|
image = pressedImage;
|
||||||
} else if (states.contains(MaterialState.hovered)) {
|
} else if (states.contains(WidgetState.hovered)) {
|
||||||
image = hoveredImage;
|
image = hoveredImage;
|
||||||
} else {
|
} else {
|
||||||
image = defaultImage;
|
image = defaultImage;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/15303
|
# Changes made in https://github.com/flutter/flutter/pull/15303
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * Material (general): fix_material.yaml
|
# * Material (general): fix_material.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/86198
|
# Changes made in https://github.com/flutter/flutter/pull/86198
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * Material (general): fix_material.yaml
|
# * Material (general): fix_material.yaml
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * ThemeData: fix_theme_data.yaml
|
# * ThemeData: fix_theme_data.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/48547
|
# Changes made in https://github.com/flutter/flutter/pull/48547
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# * Material (general): fix_material.yaml
|
# * Material (general): fix_material.yaml
|
||||||
# * SliverAppBar: fix_sliver_app_bar.yaml
|
# * SliverAppBar: fix_sliver_app_bar.yaml
|
||||||
# * TextTheme: fix_text_theme.yaml
|
# * TextTheme: fix_text_theme.yaml
|
||||||
|
# * WidgetState: fix_widget_state.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/87281
|
# 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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
import 'input_border.dart';
|
import 'input_border.dart';
|
||||||
|
|
||||||
|
@ -20,6 +18,9 @@ import 'input_border.dart';
|
||||||
///
|
///
|
||||||
/// See also:
|
/// 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
|
/// * [MaterialStateProperty], an interface for objects that "resolve" to
|
||||||
/// different values depending on a widget's material state.
|
/// different values depending on a widget's material state.
|
||||||
/// {@template flutter.material.MaterialStateProperty.implementations}
|
/// {@template flutter.material.MaterialStateProperty.implementations}
|
||||||
|
@ -45,62 +46,26 @@ import 'input_border.dart';
|
||||||
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
||||||
/// a [TextStyle] or a [MaterialStateProperty<TextStyle>].
|
/// a [TextStyle] or a [MaterialStateProperty<TextStyle>].
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
enum MaterialState {
|
@Deprecated(
|
||||||
/// The state when the user drags their mouse cursor over the given widget.
|
'Use WidgetState instead. '
|
||||||
///
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
/// See: https://material.io/design/interaction/states.html#hover.
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
hovered,
|
)
|
||||||
|
typedef MaterialState = WidgetState;
|
||||||
/// 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
|
/// Signature for the function that returns a value of type `T` based on a given
|
||||||
/// set of states.
|
/// 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].
|
/// Defines a [Color] that is also a [MaterialStateProperty].
|
||||||
///
|
///
|
||||||
|
@ -149,55 +114,17 @@ typedef MaterialPropertyResolver<T> = T Function(Set<MaterialState> states);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@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.
|
|
||||||
///
|
|
||||||
/// 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
|
/// See also
|
||||||
/// be used.
|
|
||||||
///
|
///
|
||||||
/// Used by [MaterialStateColor.resolveWith].
|
/// * [WidgetStateColor], the non-Material version that can be used
|
||||||
class _MaterialStateColor extends MaterialStateColor {
|
/// interchangably with `MaterialStateColor`.
|
||||||
_MaterialStateColor(this._resolve) : super(_resolve(_defaultStates).value);
|
@Deprecated(
|
||||||
|
'Use WidgetStateColor instead. '
|
||||||
final MaterialPropertyResolver<Color> _resolve;
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
/// The default state for a Material component, the empty set of interaction states.
|
)
|
||||||
static const Set<MaterialState> _defaultStates = <MaterialState>{};
|
typedef MaterialStateColor = WidgetStateColor;
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a [MouseCursor] whose value depends on a set of [MaterialState]s which
|
/// Defines a [MouseCursor] whose value depends on a set of [MaterialState]s which
|
||||||
/// represent the interactive state of a component.
|
/// represent the interactive state of a component.
|
||||||
|
@ -225,76 +152,17 @@ class _MaterialStateColorTransparent extends MaterialStateColor {
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
|
/// * [WidgetStateMouseCursor], the non-Material version that can be used
|
||||||
|
/// interchangeably with `MaterialStateMouseCursor`.
|
||||||
/// * [MouseCursor] for introduction on the mouse cursor system.
|
/// * [MouseCursor] for introduction on the mouse cursor system.
|
||||||
/// * [SystemMouseCursors], which defines cursors that are supported by
|
/// * [SystemMouseCursors], which defines cursors that are supported by
|
||||||
/// native platforms.
|
/// native platforms.
|
||||||
abstract class MaterialStateMouseCursor extends MouseCursor implements MaterialStateProperty<MouseCursor> {
|
@Deprecated(
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
'Use WidgetStateMouseCursor instead. '
|
||||||
/// const constructors so that they can be used in const expressions.
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
const MaterialStateMouseCursor();
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
|
)
|
||||||
@protected
|
typedef MaterialStateMouseCursor = WidgetStateMouseCursor;
|
||||||
@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)';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a [BorderSide] whose value depends on a set of [MaterialState]s
|
/// Defines a [BorderSide] whose value depends on a set of [MaterialState]s
|
||||||
/// which represent the interactive state of a component.
|
/// 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
|
/// This class should only be used for parameters which are documented to take
|
||||||
/// [MaterialStateBorderSide], otherwise only the default state will be used.
|
/// [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.
|
|
||||||
///
|
|
||||||
/// 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
|
/// See also:
|
||||||
/// be used.
|
|
||||||
///
|
///
|
||||||
/// Used by [MaterialStateBorderSide.resolveWith].
|
/// * [WidgetStateBorderSide], the non-Material version that can be used
|
||||||
class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
/// interchangeably with `MaterialStateBorderSide`.
|
||||||
const _MaterialStateBorderSide(this._resolve);
|
@Deprecated(
|
||||||
|
'Use WidgetStateBorderSide instead. '
|
||||||
final MaterialPropertyResolver<BorderSide?> _resolve;
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
@override
|
)
|
||||||
BorderSide? resolve(Set<MaterialState> states) => _resolve(states);
|
typedef MaterialStateBorderSide = WidgetStateBorderSide;
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines an [OutlinedBorder] whose value depends on a set of [MaterialState]s
|
/// Defines an [OutlinedBorder] whose value depends on a set of [MaterialState]s
|
||||||
/// which represent the interactive state of a component.
|
/// which represent the interactive state of a component.
|
||||||
|
@ -403,18 +216,15 @@ class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
|
/// * [WidgetStateOutlinedBorder], the non-Material version that can be used
|
||||||
|
/// interchangeably with `MaterialStateOutlinedBorder`.
|
||||||
/// * [ShapeBorder] the base class for shape outlines.
|
/// * [ShapeBorder] the base class for shape outlines.
|
||||||
abstract class MaterialStateOutlinedBorder extends OutlinedBorder implements MaterialStateProperty<OutlinedBorder?> {
|
@Deprecated(
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
'Use WidgetStateOutlinedBorder instead. '
|
||||||
/// const constructors so that they can be used in const expressions.
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
const MaterialStateOutlinedBorder();
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
|
)
|
||||||
/// Returns an [OutlinedBorder] that's to be used when a Material component is
|
typedef MaterialStateOutlinedBorder = WidgetStateOutlinedBorder;
|
||||||
/// in the specified state. Return null to defer to the default value of the
|
|
||||||
/// widget or theme.
|
|
||||||
@override
|
|
||||||
OutlinedBorder? resolve(Set<MaterialState> states);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a [TextStyle] that is also a [MaterialStateProperty].
|
/// 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
|
/// [MaterialStateTextStyle] and override its [resolve] method. You'll also need
|
||||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||||
/// at compile-time what its default color is.
|
/// 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.
|
|
||||||
///
|
|
||||||
/// 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
|
/// See also:
|
||||||
/// be used.
|
|
||||||
///
|
///
|
||||||
/// Used by [MaterialStateTextStyle.resolveWith].
|
/// * [WidgetStateTextStyle], the non-Material version that can be used
|
||||||
class _MaterialStateTextStyle extends MaterialStateTextStyle {
|
/// interchangeably with `MaterialStateTextStyle`.
|
||||||
const _MaterialStateTextStyle(this._resolve);
|
@Deprecated(
|
||||||
|
'Use WidgetStateTextStyle instead. '
|
||||||
final MaterialPropertyResolver<TextStyle> _resolve;
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
@override
|
)
|
||||||
TextStyle resolve(Set<MaterialState> states) => _resolve(states);
|
typedef MaterialStateTextStyle = WidgetStateTextStyle;
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a [OutlineInputBorder] that is also a [MaterialStateProperty].
|
/// Defines a [OutlineInputBorder] that is also a [MaterialStateProperty].
|
||||||
///
|
///
|
||||||
|
@ -634,106 +419,29 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
|
/// * [WidgetStateProperty], the non-Material version that can be used
|
||||||
|
/// interchangeably with `MaterialStateProperty`.
|
||||||
/// {@macro flutter.material.MaterialStateProperty.implementations}
|
/// {@macro flutter.material.MaterialStateProperty.implementations}
|
||||||
abstract class MaterialStateProperty<T> {
|
@Deprecated(
|
||||||
/// Returns a value of type `T` that depends on [states].
|
'Use WidgetStateProperty instead. '
|
||||||
///
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
/// Widgets like [TextButton] and [ElevatedButton] apply this method to their
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
/// current [MaterialState]s to compute colors and other visual parameters
|
)
|
||||||
/// at build time.
|
typedef MaterialStateProperty<T> = WidgetStateProperty<T>;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience class for creating a [MaterialStateProperty] that
|
/// Convenience class for creating a [MaterialStateProperty] that
|
||||||
/// resolves to the given value for all states.
|
/// resolves to the given value for all states.
|
||||||
class MaterialStatePropertyAll<T> implements MaterialStateProperty<T> {
|
///
|
||||||
|
/// See also:
|
||||||
/// Constructs a [MaterialStateProperty] that always resolves to the given
|
///
|
||||||
/// value.
|
/// * [WidgetStatePropertyAll], the non-Material version that can be used
|
||||||
const MaterialStatePropertyAll(this.value);
|
/// interchangeably with `MaterialStatePropertyAll`.
|
||||||
|
@Deprecated(
|
||||||
/// The value of the property that will be used for all states.
|
'Use WidgetStatePropertyAll instead. '
|
||||||
final T value;
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
@override
|
)
|
||||||
T resolve(Set<MaterialState> states) => value;
|
typedef MaterialStatePropertyAll<T> = WidgetStatePropertyAll<T>;
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
if (value is double) {
|
|
||||||
return 'MaterialStatePropertyAll(${debugFormatDouble(value as double)})';
|
|
||||||
} else {
|
|
||||||
return 'MaterialStatePropertyAll($value)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Manages a set of [MaterialState]s and notifies listeners of changes.
|
/// 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.
|
/// depend on [MaterialStatesController] may call [update] in their build method.
|
||||||
/// In such cases, listener's that call `setState` - during the build phase - will cause
|
/// In such cases, listener's that call `setState` - during the build phase - will cause
|
||||||
/// an error.
|
/// an error.
|
||||||
class MaterialStatesController extends ValueNotifier<Set<MaterialState>> {
|
///
|
||||||
/// Creates a MaterialStatesController.
|
/// See also:
|
||||||
MaterialStatesController([Set<MaterialState>? value]) : super(<MaterialState>{...?value});
|
///
|
||||||
|
/// * [WidgetStatesController], the non-Material version that can be used
|
||||||
/// Adds [state] to [value] if [add] is true, and removes it otherwise,
|
/// interchangeably with `MaterialStatesController`.
|
||||||
/// and notifies listeners if [value] has changed.
|
@Deprecated(
|
||||||
void update(MaterialState state, bool add) {
|
'Use WidgetStatesController instead. '
|
||||||
final bool valueChanged = add ? value.add(state) : value.remove(state);
|
'Moved to the Widgets layer to make code available outside of Material. '
|
||||||
if (valueChanged) {
|
'This feature was deprecated after v3.19.0-0.3.pre.'
|
||||||
notifyListeners();
|
)
|
||||||
}
|
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/visibility.dart';
|
||||||
export 'src/widgets/widget_inspector.dart';
|
export 'src/widgets/widget_inspector.dart';
|
||||||
export 'src/widgets/widget_span.dart';
|
export 'src/widgets/widget_span.dart';
|
||||||
|
export 'src/widgets/widget_state.dart';
|
||||||
export 'src/widgets/will_pop_scope.dart';
|
export 'src/widgets/will_pop_scope.dart';
|
||||||
|
|
|
@ -102,7 +102,7 @@ void main() {
|
||||||
expect(description[8], 'showSelectedLabels: true');
|
expect(description[8], 'showSelectedLabels: true');
|
||||||
expect(description[9], 'showUnselectedLabels: true');
|
expect(description[9], 'showUnselectedLabels: true');
|
||||||
expect(description[10], 'type: BottomNavigationBarType.fixed');
|
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 {
|
testWidgets('BottomNavigationBar is themeable', (WidgetTester tester) async {
|
||||||
|
|
|
@ -85,21 +85,21 @@ void main() {
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description, <String>[
|
expect(description, <String>[
|
||||||
'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 10.0))',
|
'textStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 10.0))',
|
||||||
'backgroundColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
'backgroundColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||||
'foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2))',
|
'foregroundColor: WidgetStatePropertyAll(Color(0xfffffff2))',
|
||||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff3))',
|
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff3))',
|
||||||
'shadowColor: MaterialStatePropertyAll(Color(0xfffffff4))',
|
'shadowColor: WidgetStatePropertyAll(Color(0xfffffff4))',
|
||||||
'surfaceTintColor: MaterialStatePropertyAll(Color(0xfffffff5))',
|
'surfaceTintColor: WidgetStatePropertyAll(Color(0xfffffff5))',
|
||||||
'elevation: MaterialStatePropertyAll(1.5)',
|
'elevation: WidgetStatePropertyAll(1.5)',
|
||||||
'padding: MaterialStatePropertyAll(EdgeInsets.all(1.0))',
|
'padding: WidgetStatePropertyAll(EdgeInsets.all(1.0))',
|
||||||
'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))',
|
'minimumSize: WidgetStatePropertyAll(Size(1.0, 2.0))',
|
||||||
'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))',
|
'maximumSize: WidgetStatePropertyAll(Size(100.0, 200.0))',
|
||||||
'iconColor: MaterialStatePropertyAll(Color(0xfffffff6))',
|
'iconColor: WidgetStatePropertyAll(Color(0xfffffff6))',
|
||||||
'iconSize: MaterialStatePropertyAll(48.1)',
|
'iconSize: WidgetStatePropertyAll(48.1)',
|
||||||
'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))',
|
'side: WidgetStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))',
|
||||||
'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))',
|
'shape: WidgetStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))',
|
||||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))',
|
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(forbidden))',
|
||||||
'tapTargetSize: shrinkWrap',
|
'tapTargetSize: shrinkWrap',
|
||||||
'animationDuration: 0:00:01.000000',
|
'animationDuration: 0:00:01.000000',
|
||||||
'enableFeedback: true',
|
'enableFeedback: true',
|
||||||
|
|
|
@ -71,10 +71,10 @@ void main() {
|
||||||
expect(
|
expect(
|
||||||
description,
|
description,
|
||||||
equalsIgnoringHashCodes(<String>[
|
equalsIgnoringHashCodes(<String>[
|
||||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))',
|
||||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
'fillColor: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||||
'checkColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
'checkColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))',
|
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff2))',
|
||||||
'splashRadius: 1.0',
|
'splashRadius: 1.0',
|
||||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||||
|
|
|
@ -129,7 +129,7 @@ void main() {
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description, equalsIgnoringHashCodes(<String>[
|
expect(description, equalsIgnoringHashCodes(<String>[
|
||||||
'color: MaterialStatePropertyAll(Color(0xfffffff0))',
|
'color: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||||
'backgroundColor: Color(0xfffffff1)',
|
'backgroundColor: Color(0xfffffff1)',
|
||||||
'deleteIconColor: Color(0xfffffff2)',
|
'deleteIconColor: Color(0xfffffff2)',
|
||||||
'disabledColor: Color(0xfffffff3)',
|
'disabledColor: Color(0xfffffff3)',
|
||||||
|
|
|
@ -105,19 +105,19 @@ void main() {
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description[0], 'decoration: BoxDecoration(color: Color(0xfffffff0))');
|
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[2], 'dataRowMinHeight: 41.0');
|
||||||
expect(description[3], 'dataRowMaxHeight: 42.0');
|
expect(description[3], 'dataRowMaxHeight: 42.0');
|
||||||
expect(description[4], 'dataTextStyle: TextStyle(inherit: true, size: 12.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[6], 'headingRowHeight: 52.0');
|
||||||
expect(description[7], 'headingTextStyle: TextStyle(inherit: true, size: 14.0)');
|
expect(description[7], 'headingTextStyle: TextStyle(inherit: true, size: 14.0)');
|
||||||
expect(description[8], 'horizontalMargin: 3.0');
|
expect(description[8], 'horizontalMargin: 3.0');
|
||||||
expect(description[9], 'columnSpacing: 4.0');
|
expect(description[9], 'columnSpacing: 4.0');
|
||||||
expect(description[10], 'dividerThickness: 5.0');
|
expect(description[10], 'dividerThickness: 5.0');
|
||||||
expect(description[11], 'checkboxHorizontalMargin: 6.0');
|
expect(description[11], 'checkboxHorizontalMargin: 6.0');
|
||||||
expect(description[12], 'headingCellCursor: MaterialStatePropertyAll(SystemMouseCursor(grab))');
|
expect(description[12], 'headingCellCursor: WidgetStatePropertyAll(SystemMouseCursor(grab))');
|
||||||
expect(description[13], 'dataRowCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))');
|
expect(description[13], 'dataRowCursor: WidgetStatePropertyAll(SystemMouseCursor(forbidden))');
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DataTable is themeable', (WidgetTester tester) async {
|
testWidgets('DataTable is themeable', (WidgetTester tester) async {
|
||||||
|
|
|
@ -329,17 +329,17 @@ void main() {
|
||||||
'headerHelpStyle: TextStyle(inherit: true, size: 11.0)',
|
'headerHelpStyle: TextStyle(inherit: true, size: 11.0)',
|
||||||
'weekDayStyle: TextStyle(inherit: true, size: 12.0)',
|
'weekDayStyle: TextStyle(inherit: true, size: 12.0)',
|
||||||
'dayStyle: TextStyle(inherit: true, size: 13.0)',
|
'dayStyle: TextStyle(inherit: true, size: 13.0)',
|
||||||
'dayForegroundColor: MaterialStatePropertyAll(Color(0xfffffff5))',
|
'dayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff5))',
|
||||||
'dayBackgroundColor: MaterialStatePropertyAll(Color(0xfffffff6))',
|
'dayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff6))',
|
||||||
'dayOverlayColor: MaterialStatePropertyAll(Color(0xfffffff7))',
|
'dayOverlayColor: WidgetStatePropertyAll(Color(0xfffffff7))',
|
||||||
'dayShape: MaterialStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
|
'dayShape: WidgetStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
|
||||||
'todayForegroundColor: MaterialStatePropertyAll(Color(0xfffffff8))',
|
'todayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff8))',
|
||||||
'todayBackgroundColor: MaterialStatePropertyAll(Color(0xfffffff9))',
|
'todayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff9))',
|
||||||
'todayBorder: BorderSide(width: 3.0)',
|
'todayBorder: BorderSide(width: 3.0)',
|
||||||
'yearStyle: TextStyle(inherit: true, size: 13.0)',
|
'yearStyle: TextStyle(inherit: true, size: 13.0)',
|
||||||
'yearForegroundColor: MaterialStatePropertyAll(Color(0xfffffffa))',
|
'yearForegroundColor: WidgetStatePropertyAll(Color(0xfffffffa))',
|
||||||
'yearBackgroundColor: MaterialStatePropertyAll(Color(0xfffffffb))',
|
'yearBackgroundColor: WidgetStatePropertyAll(Color(0xfffffffb))',
|
||||||
'yearOverlayColor: MaterialStatePropertyAll(Color(0xfffffffc))',
|
'yearOverlayColor: WidgetStatePropertyAll(Color(0xfffffffc))',
|
||||||
'rangePickerBackgroundColor: Color(0xfffffffd)',
|
'rangePickerBackgroundColor: Color(0xfffffffd)',
|
||||||
'rangePickerElevation: 7.0',
|
'rangePickerElevation: 7.0',
|
||||||
'rangePickerShadowColor: Color(0xfffffffe)',
|
'rangePickerShadowColor: Color(0xfffffffe)',
|
||||||
|
@ -350,11 +350,11 @@ void main() {
|
||||||
'rangePickerHeaderHeadlineStyle: TextStyle(inherit: true, size: 14.0)',
|
'rangePickerHeaderHeadlineStyle: TextStyle(inherit: true, size: 14.0)',
|
||||||
'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)',
|
'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)',
|
||||||
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
|
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
|
||||||
'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))',
|
'rangeSelectionOverlayColor: WidgetStatePropertyAll(Color(0xffffff3f))',
|
||||||
'dividerColor: Color(0xffffff4f)',
|
'dividerColor: Color(0xffffff4f)',
|
||||||
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())',
|
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())',
|
||||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff6f)))',
|
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff6f)))',
|
||||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff7f)))'
|
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff7f)))'
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -422,7 +422,7 @@ void main() {
|
||||||
'extendedIconLabelSpacing: 12.0',
|
'extendedIconLabelSpacing: 12.0',
|
||||||
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
|
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
|
||||||
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
|
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
|
||||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ void main() {
|
||||||
'minVerticalPadding: 300.0',
|
'minVerticalPadding: 300.0',
|
||||||
'minLeadingWidth: 400.0',
|
'minLeadingWidth: 400.0',
|
||||||
'enableFeedback: true',
|
'enableFeedback: true',
|
||||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||||
'visualDensity: VisualDensity#00000(h: -1.0, v: -1.0)(horizontal: -1.0, vertical: -1.0)',
|
'visualDensity: VisualDensity#00000(h: -1.0, v: -1.0)(horizontal: -1.0, vertical: -1.0)',
|
||||||
'titleAlignment: ListTileTitleAlignment.top',
|
'titleAlignment: ListTileTitleAlignment.top',
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -45,10 +45,10 @@ void main() {
|
||||||
|
|
||||||
test('toString formats correctly', () {
|
test('toString formats correctly', () {
|
||||||
const MaterialStateProperty<Color?> colorProperty = MaterialStatePropertyAll<Color?>(Color(0xFFFFFFFF));
|
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);
|
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", () {
|
test("Can interpolate between two MaterialStateProperty's", () {
|
||||||
|
|
|
@ -1293,7 +1293,7 @@ void main() {
|
||||||
expect(
|
expect(
|
||||||
description.join('\n'),
|
description.join('\n'),
|
||||||
equalsIgnoringHashCodes(
|
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'),
|
'clipBehavior: Clip.none'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -2357,7 +2357,7 @@ void main() {
|
||||||
equalsIgnoringHashCodes(
|
equalsIgnoringHashCodes(
|
||||||
<String>[
|
<String>[
|
||||||
'focusNode: null',
|
'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',
|
'alignmentOffset: null',
|
||||||
'clipBehavior: hardEdge',
|
'clipBehavior: hardEdge',
|
||||||
],
|
],
|
||||||
|
|
|
@ -62,12 +62,12 @@ void main() {
|
||||||
expect(description[2], 'elevation: 20.0');
|
expect(description[2], 'elevation: 20.0');
|
||||||
expect(description[3], 'indicatorColor: Color(0x00000098)');
|
expect(description[3], 'indicatorColor: Color(0x00000098)');
|
||||||
expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))');
|
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.
|
// 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[6].contains('(color: Color(0x00000097))'), isTrue);
|
||||||
expect(description[7], 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide');
|
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 {
|
testWidgets('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async {
|
||||||
|
|
|
@ -60,8 +60,8 @@ void main() {
|
||||||
'indicatorColor: Color(0x00000096)',
|
'indicatorColor: Color(0x00000096)',
|
||||||
'indicatorShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))',
|
'indicatorShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))',
|
||||||
'indicatorSize: Size(10.0, 10.0)',
|
'indicatorSize: Size(10.0, 10.0)',
|
||||||
'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))',
|
'labelTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 7.0))',
|
||||||
'iconTheme: MaterialStatePropertyAll(IconThemeData#00000(color: Color(0x00000095)))'
|
'iconTheme: WidgetStatePropertyAll(IconThemeData#00000(color: Color(0x00000095)))'
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
|
@ -117,9 +117,9 @@ void main() {
|
||||||
'shadowColor: Color(0xfffffff2)',
|
'shadowColor: Color(0xfffffff2)',
|
||||||
'surfaceTintColor: Color(0xfffffff3)',
|
'surfaceTintColor: Color(0xfffffff3)',
|
||||||
'text style: TextStyle(inherit: true, color: Color(0xfffffff4))',
|
'text style: TextStyle(inherit: true, color: Color(0xfffffff4))',
|
||||||
"labelTextStyle: Instance of '_MaterialStatePropertyWith<TextStyle?>'",
|
"labelTextStyle: Instance of '_WidgetStatePropertyWith<TextStyle?>'",
|
||||||
'enableFeedback: false',
|
'enableFeedback: false',
|
||||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||||
'position: over',
|
'position: over',
|
||||||
'iconColor: Color(0xfffffff8)',
|
'iconColor: Color(0xfffffff8)',
|
||||||
'iconSize: 31.0'
|
'iconSize: 31.0'
|
||||||
|
|
|
@ -68,9 +68,9 @@ void main() {
|
||||||
expect(
|
expect(
|
||||||
description,
|
description,
|
||||||
equalsIgnoringHashCodes(<String>[
|
equalsIgnoringHashCodes(<String>[
|
||||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))',
|
||||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
'fillColor: WidgetStatePropertyAll(Color(0xfffffff0))',
|
||||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
'overlayColor: WidgetStatePropertyAll(Color(0xfffffff1))',
|
||||||
'splashRadius: 1.0',
|
'splashRadius: 1.0',
|
||||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||||
|
|
|
@ -741,12 +741,12 @@ void main() {
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description, <String>[
|
expect(description, <String>[
|
||||||
"thumbVisibility: Instance of '_MaterialStatePropertyWith<bool?>'",
|
"thumbVisibility: Instance of '_WidgetStatePropertyWith<bool?>'",
|
||||||
"thickness: Instance of '_MaterialStatePropertyWith<double?>'",
|
"thickness: Instance of '_WidgetStatePropertyWith<double?>'",
|
||||||
'radius: Radius.circular(3.0)',
|
'radius: Radius.circular(3.0)',
|
||||||
"thumbColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
"thumbColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||||
"trackColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
"trackColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||||
"trackBorderColor: Instance of '_MaterialStatePropertyWith<Color?>'",
|
"trackBorderColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
||||||
'crossAxisMargin: 3.0',
|
'crossAxisMargin: 3.0',
|
||||||
'mainAxisMargin: 6.0',
|
'mainAxisMargin: 6.0',
|
||||||
'minThumbLength: 120.0',
|
'minThumbLength: 120.0',
|
||||||
|
|
|
@ -85,16 +85,16 @@ void main() {
|
||||||
.map((DiagnosticsNode node) => node.toString())
|
.map((DiagnosticsNode node) => node.toString())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description[0], 'elevation: MaterialStatePropertyAll(3.0)');
|
expect(description[0], 'elevation: WidgetStatePropertyAll(3.0)');
|
||||||
expect(description[1], 'backgroundColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
expect(description[1], 'backgroundColor: WidgetStatePropertyAll(Color(0xfffffff1))');
|
||||||
expect(description[2], 'shadowColor: MaterialStatePropertyAll(Color(0xfffffff2))');
|
expect(description[2], 'shadowColor: WidgetStatePropertyAll(Color(0xfffffff2))');
|
||||||
expect(description[3], 'surfaceTintColor: MaterialStatePropertyAll(Color(0xfffffff3))');
|
expect(description[3], 'surfaceTintColor: WidgetStatePropertyAll(Color(0xfffffff3))');
|
||||||
expect(description[4], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff4))');
|
expect(description[4], 'overlayColor: WidgetStatePropertyAll(Color(0xfffffff4))');
|
||||||
expect(description[5], 'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff5), width: 2.0))');
|
expect(description[5], 'side: WidgetStatePropertyAll(BorderSide(color: Color(0xfffffff5), width: 2.0))');
|
||||||
expect(description[6], 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))');
|
expect(description[6], 'shape: WidgetStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))');
|
||||||
expect(description[7], 'padding: MaterialStatePropertyAll(EdgeInsets.all(16.0))');
|
expect(description[7], 'padding: WidgetStatePropertyAll(EdgeInsets.all(16.0))');
|
||||||
expect(description[8], 'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 24.0))');
|
expect(description[8], 'textStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 24.0))');
|
||||||
expect(description[9], 'hintStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 16.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[10], 'constraints: BoxConstraints(350.0<=w<=850.0, 0.0<=h<=Infinity)');
|
||||||
expect(description[11], 'textCapitalization: TextCapitalization.characters');
|
expect(description[11], 'textCapitalization: TextCapitalization.characters');
|
||||||
});
|
});
|
||||||
|
|
|
@ -99,7 +99,7 @@ void main() {
|
||||||
"rangeValueIndicatorShape: Instance of 'PaddleRangeSliderValueIndicatorShape'",
|
"rangeValueIndicatorShape: Instance of 'PaddleRangeSliderValueIndicatorShape'",
|
||||||
'showValueIndicator: always',
|
'showValueIndicator: always',
|
||||||
'valueIndicatorTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
|
'valueIndicatorTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
|
||||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
'mouseCursor: WidgetStateMouseCursor(clickable)',
|
||||||
'allowedInteraction: tapOnly'
|
'allowedInteraction: tapOnly'
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -73,15 +73,15 @@ void main() {
|
||||||
.map((DiagnosticsNode node) => node.toString())
|
.map((DiagnosticsNode node) => node.toString())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(description[0], 'thumbColor: MaterialStatePropertyAll(Color(0xfffffff0))');
|
expect(description[0], 'thumbColor: WidgetStatePropertyAll(Color(0xfffffff0))');
|
||||||
expect(description[1], 'trackColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
expect(description[1], 'trackColor: WidgetStatePropertyAll(Color(0xfffffff1))');
|
||||||
expect(description[2], 'trackOutlineColor: MaterialStatePropertyAll(Color(0xfffffff3))');
|
expect(description[2], 'trackOutlineColor: WidgetStatePropertyAll(Color(0xfffffff3))');
|
||||||
expect(description[3], 'trackOutlineWidth: MaterialStatePropertyAll(6.0)');
|
expect(description[3], 'trackOutlineWidth: WidgetStatePropertyAll(6.0)');
|
||||||
expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
|
expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
|
||||||
expect(description[5], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))');
|
expect(description[5], 'mouseCursor: WidgetStatePropertyAll(SystemMouseCursor(click))');
|
||||||
expect(description[6], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))');
|
expect(description[6], 'overlayColor: WidgetStatePropertyAll(Color(0xfffffff2))');
|
||||||
expect(description[7], 'splashRadius: 1.0');
|
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 {
|
testWidgets('Material2 - Switch is themeable', (WidgetTester tester) async {
|
||||||
|
|
|
@ -91,8 +91,8 @@ void main() {
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: BorderSide(color: Color(0xfffffff3)),
|
side: BorderSide(color: Color(0xfffffff3)),
|
||||||
),
|
),
|
||||||
timeSelectorSeparatorColor: MaterialStatePropertyAll<Color>(Color(0xfffffff4)),
|
timeSelectorSeparatorColor: WidgetStatePropertyAll<Color>(Color(0xfffffff4)),
|
||||||
timeSelectorSeparatorTextStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(color: Color(0xfffffff5))),
|
timeSelectorSeparatorTextStyle: WidgetStatePropertyAll<TextStyle>(TextStyle(color: Color(0xfffffff5))),
|
||||||
).debugFillProperties(builder);
|
).debugFillProperties(builder);
|
||||||
|
|
||||||
final List<String> description = builder.properties
|
final List<String> description = builder.properties
|
||||||
|
@ -102,8 +102,8 @@ void main() {
|
||||||
|
|
||||||
expect(description, equalsIgnoringHashCodes(<String>[
|
expect(description, equalsIgnoringHashCodes(<String>[
|
||||||
'backgroundColor: Color(0xfffffff0)',
|
'backgroundColor: Color(0xfffffff0)',
|
||||||
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff1)))',
|
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xfffffff1)))',
|
||||||
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2)))',
|
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xfffffff2)))',
|
||||||
'dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3))',
|
'dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3))',
|
||||||
'dayPeriodColor: Color(0x00000000)',
|
'dayPeriodColor: Color(0x00000000)',
|
||||||
'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff5)), BorderRadius.zero)',
|
'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff5)), BorderRadius.zero)',
|
||||||
|
@ -123,8 +123,8 @@ void main() {
|
||||||
'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))',
|
'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))',
|
||||||
'padding: EdgeInsets.all(1.0)',
|
'padding: EdgeInsets.all(1.0)',
|
||||||
'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)',
|
'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)',
|
||||||
'timeSelectorSeparatorColor: MaterialStatePropertyAll(Color(0xfffffff4))',
|
'timeSelectorSeparatorColor: WidgetStatePropertyAll(Color(0xfffffff4))',
|
||||||
'timeSelectorSeparatorTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, color: Color(0xfffffff5)))'
|
'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
|
// Changes made in https://github.com/flutter/flutter/pull/97972
|
||||||
ThemeData themeData = ThemeData();
|
ThemeData themeData = ThemeData();
|
||||||
themeData = ThemeData(checkboxTheme: CheckboxThemeData(
|
themeData = ThemeData(checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -178,40 +178,40 @@ void main() {
|
||||||
));
|
));
|
||||||
themeData = ThemeData(
|
themeData = ThemeData(
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -219,40 +219,40 @@ void main() {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
themeData = ThemeData.raw(checkboxTheme: CheckboxThemeData(
|
themeData = ThemeData.raw(checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -260,40 +260,40 @@ void main() {
|
||||||
));
|
));
|
||||||
themeData = ThemeData.raw(
|
themeData = ThemeData.raw(
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -301,40 +301,40 @@ void main() {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
themeData = themeData.copyWith(checkboxTheme: CheckboxThemeData(
|
themeData = themeData.copyWith(checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -342,40 +342,40 @@ void main() {
|
||||||
));
|
));
|
||||||
themeData = themeData.copyWith(
|
themeData = themeData.copyWith(
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), radioTheme: RadioThemeData(
|
), radioTheme: RadioThemeData(
|
||||||
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
fillColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
), switchTheme: SwitchThemeData(
|
), switchTheme: SwitchThemeData(
|
||||||
thumbColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
thumbColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
trackColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
trackColor: WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(WidgetState.disabled)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
return null;
|
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