From d14a301e419af7f3eff7cc3a49bf936c75d2b2f0 Mon Sep 17 00:00:00 2001 From: Jose Alba Date: Tue, 31 Mar 2020 19:14:22 -0400 Subject: [PATCH] Revert "[Slider] Rebase. (#52663)" (#53698) This reverts commit e71cf1cdbeebab9081d09daa73d4d7642f165b9d. --- .../lib/demo/material/slider_demo.dart | 31 +- .../flutter_gallery/lib/gallery/themes.dart | 2 - .../lib/src/material/range_slider.dart | 309 +--- packages/flutter/lib/src/material/slider.dart | 285 +-- .../lib/src/material/slider_theme.dart | 763 ++------ .../test/material/range_slider_test.dart | 1504 +++++----------- .../flutter/test/material/slider_test.dart | 1589 +++++------------ .../test/material/slider_theme_test.dart | 529 +----- .../test/painting/system_fonts_test.dart | 12 +- 9 files changed, 1252 insertions(+), 3772 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart index 4cadff475b4..25ece5b356e 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart @@ -69,7 +69,6 @@ class _CustomRangeThumbShape extends RangeSliderThumbShape { @required SliderThemeData sliderTheme, TextDirection textDirection, Thumb thumb, - bool isPressed, }) { final Canvas canvas = context.canvas; final ColorTween colorTween = ColorTween( @@ -131,8 +130,6 @@ class _CustomThumbShape extends SliderComponentShape { SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { final Canvas canvas = context.canvas; final ColorTween colorTween = ColorTween( @@ -172,8 +169,6 @@ class _CustomValueIndicatorShape extends SliderComponentShape { SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { final Canvas canvas = context.canvas; final ColorTween enableColor = ColorTween( @@ -273,21 +268,15 @@ class _SlidersState extends State<_Sliders> { ), ), ), - SliderTheme( - data: const SliderThemeData( - showValueIndicator: ShowValueIndicator.always, - ), - child: Slider.adaptive( - label: _continuousValue.toStringAsFixed(6).toString(), - value: _continuousValue, - min: 0.0, - max: 100.0, - onChanged: (double value) { - setState(() { - _continuousValue = value; - }); - }, - ), + Slider.adaptive( + value: _continuousValue, + min: 0.0, + max: 100.0, + onChanged: (double value) { + setState(() { + _continuousValue = value; + }); + }, ), const Text('Continuous with Editable Numerical Value'), ], @@ -325,7 +314,7 @@ class _SlidersState extends State<_Sliders> { activeTrackColor: Colors.deepPurple, inactiveTrackColor: theme.colorScheme.onSurface.withOpacity(0.5), activeTickMarkColor: theme.colorScheme.onSurface.withOpacity(0.7), - inactiveTickMarkColor: theme.colorScheme.surface.withOpacity(0.7), + inactiveTickMarkColor: theme.colorScheme.surface.withOpacity(0.7), overlayColor: theme.colorScheme.onSurface.withOpacity(0.12), thumbColor: Colors.deepPurple, valueIndicatorColor: Colors.deepPurpleAccent, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart b/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart index 4099bfc09a2..2f271c7c73b 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart @@ -21,12 +21,10 @@ ThemeData _buildDarkTheme() { final ColorScheme colorScheme = const ColorScheme.dark().copyWith( primary: primaryColor, secondary: secondaryColor, - onPrimary: secondaryColor, ); final ThemeData base = ThemeData( brightness: Brightness.dark, accentColorBrightness: Brightness.dark, - colorScheme: colorScheme, primaryColor: primaryColor, primaryColorDark: const Color(0xFF0050a0), primaryColorLight: secondaryColor, diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index fbe1e5a9f1a..d33b4e52ffa 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -22,11 +22,6 @@ import 'theme.dart'; // RangeValues _dollarsRange = RangeValues(50, 100); // void setState(VoidCallback fn) { } -/// [RangeSlider] uses this callback to paint the value indicator on the overlay. -/// Since the value indicator is painted on the Overlay; this method paints the -/// value indicator in a [RenderBox] that appears in the [Overlay]. -typedef PaintRangeValueIndicator = void Function(PaintingContext context, Offset offset); - /// A Material Design range slider. /// /// Used to select a range from a range of values. @@ -132,7 +127,6 @@ class RangeSlider extends StatefulWidget { this.activeColor, this.inactiveColor, this.semanticFormatterCallback, - this.useV2Slider = false, }) : assert(values != null), assert(min != null), assert(max != null), @@ -141,7 +135,6 @@ class RangeSlider extends StatefulWidget { assert(values.start >= min && values.start <= max), assert(values.end >= min && values.end <= max), assert(divisions == null || divisions > 0), - assert(useV2Slider != null), super(key: key); /// The currently selected values for this range slider. @@ -340,19 +333,6 @@ class RangeSlider extends StatefulWidget { /// {@end-tool} final RangeSemanticFormatterCallback semanticFormatterCallback; - /// Whether to use the updated Material spec version of the [RangeSlider]. - /// * The v2 [RangeSlider] has an updated value indicator that matches the latest specs. - /// * The value indicator is painted on the Overlay. - /// * The active track is bigger than the inactive track. - /// * The thumb that is activated has elevation. - /// * Updated value indicators in case they overlap with each other. - /// * - /// - /// This is a temporary flag for migrating the slider from v1 to v2. Currently - /// this defaults to false, because the changes may break existing tests. This - /// value will be defaulted to true in the future. - final bool useV2Slider; - // Touch width for the tap boundary of the slider thumbs. static const double _minTouchTargetWidth = kMinInteractiveDimension; @@ -374,7 +354,6 @@ class RangeSlider extends StatefulWidget { properties.add(StringProperty('labelEnd', labels?.end)); properties.add(ColorProperty('activeColor', activeColor)); properties.add(ColorProperty('inactiveColor', inactiveColor)); - properties.add(FlagProperty('useV2Slider', value: useV2Slider, ifFalse: 'useV1Slider')); properties.add(ObjectFlagProperty>.has('semanticFormatterCallback', semanticFormatterCallback)); } } @@ -398,10 +377,6 @@ class _RangeSliderState extends State with TickerProviderStateMixin AnimationController startPositionController; AnimationController endPositionController; Timer interactionTimer; - // Value Indicator paint Animation that appears on the Overlay. - PaintRangeValueIndicator paintTopValueIndicator; - PaintRangeValueIndicator paintBottomValueIndicator; - @override void initState() { @@ -545,7 +520,14 @@ class _RangeSliderState extends State with TickerProviderStateMixin return null; }; - + static const double _defaultTrackHeight = 2; + static const RangeSliderTrackShape _defaultTrackShape = RoundedRectRangeSliderTrackShape(); + static const RangeSliderTickMarkShape _defaultTickMarkShape = RoundRangeSliderTickMarkShape(); + static const SliderComponentShape _defaultOverlayShape = RoundSliderOverlayShape(); + static const RangeSliderThumbShape _defaultThumbShape = RoundRangeSliderThumbShape(); + static const RangeSliderValueIndicatorShape _defaultValueIndicatorShape = PaddleRangeSliderValueIndicatorShape(); + static const ShowValueIndicator _defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete; + static const double _defaultMinThumbSeparation = 8; @override Widget build(BuildContext context) { @@ -561,29 +543,6 @@ class _RangeSliderState extends State with TickerProviderStateMixin // colors come from the ThemeData.colorScheme. These colors, along with // the default shapes and text styles are aligned to the Material // Guidelines. - - final bool useV2Slider = widget.useV2Slider; - final double _defaultTrackHeight = useV2Slider ? 4 : 2; - final RangeSliderTrackShape _defaultTrackShape = RoundedRectRangeSliderTrackShape(useV2Slider: useV2Slider); - final RangeSliderTickMarkShape _defaultTickMarkShape = RoundRangeSliderTickMarkShape(useV2Slider: useV2Slider); - const SliderComponentShape _defaultOverlayShape = RoundSliderOverlayShape(); - final RangeSliderThumbShape _defaultThumbShape = RoundRangeSliderThumbShape(useV2Slider: useV2Slider); - final RangeSliderValueIndicatorShape _defaultValueIndicatorShape = useV2Slider ? const RectangularRangeSliderValueIndicatorShape() : const PaddleRangeSliderValueIndicatorShape(); - const ShowValueIndicator _defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete; - const double _defaultMinThumbSeparation = 8; - - // The value indicator's color is not the same as the thumb and active track - // (which can be defined by activeColor) if the - // RectangularSliderValueIndicatorShape is used. In all other cases, the - // value indicator is assumed to be the same as the active color. - final RangeSliderValueIndicatorShape valueIndicatorShape = sliderTheme.rangeValueIndicatorShape ?? _defaultValueIndicatorShape; - Color valueIndicatorColor; - if (valueIndicatorShape is RectangularRangeSliderValueIndicatorShape) { - valueIndicatorColor = sliderTheme.valueIndicatorColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(0.60), theme.colorScheme.surface.withOpacity(0.90)); - } else { - valueIndicatorColor = widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary; - } - sliderTheme = sliderTheme.copyWith( trackHeight: sliderTheme.trackHeight ?? _defaultTrackHeight, activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary, @@ -596,14 +555,14 @@ class _RangeSliderState extends State with TickerProviderStateMixin disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? theme.colorScheme.onSurface.withOpacity(0.12), thumbColor: widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary, overlappingShapeStrokeColor: sliderTheme.overlappingShapeStrokeColor ?? theme.colorScheme.surface, - disabledThumbColor: sliderTheme.disabledThumbColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(.38), const Color(0xFFFFFFFF)), + disabledThumbColor: sliderTheme.disabledThumbColor ?? theme.colorScheme.onSurface.withOpacity(0.38), overlayColor: widget.activeColor?.withOpacity(0.12) ?? sliderTheme.overlayColor ?? theme.colorScheme.primary.withOpacity(0.12), - valueIndicatorColor: valueIndicatorColor, + valueIndicatorColor: widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary, rangeTrackShape: sliderTheme.rangeTrackShape ?? _defaultTrackShape, rangeTickMarkShape: sliderTheme.rangeTickMarkShape ?? _defaultTickMarkShape, rangeThumbShape: sliderTheme.rangeThumbShape ?? _defaultThumbShape, overlayShape: sliderTheme.overlayShape ?? _defaultOverlayShape, - rangeValueIndicatorShape: valueIndicatorShape, + rangeValueIndicatorShape: sliderTheme.rangeValueIndicatorShape ?? _defaultValueIndicatorShape, showValueIndicator: sliderTheme.showValueIndicator ?? _defaultShowValueIndicator, valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyText1.copyWith( color: theme.colorScheme.onPrimary, @@ -612,49 +571,19 @@ class _RangeSliderState extends State with TickerProviderStateMixin thumbSelector: sliderTheme.thumbSelector ?? _defaultRangeThumbSelector, ); - // This size is used as the max bounds for the painting of the value - // indicators. It must be kept in sync with the function with the same name - // in slider.dart. - Size _screenSize() => MediaQuery.of(context).size; - - return CompositedTransformTarget( - link: _layerLink, - child: _RangeSliderRenderObjectWidget( - values: _unlerpRangeValues(widget.values), - divisions: widget.divisions, - labels: widget.labels, - sliderTheme: sliderTheme, - textScaleFactor: MediaQuery.of(context).textScaleFactor, - screenSize: _screenSize(), - onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, - onChangeStart: widget.onChangeStart != null ? _handleDragStart : null, - onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null, - state: this, - semanticFormatterCallback: widget.semanticFormatterCallback, - useV2Slider: widget.useV2Slider, - ), + return _RangeSliderRenderObjectWidget( + values: _unlerpRangeValues(widget.values), + divisions: widget.divisions, + labels: widget.labels, + sliderTheme: sliderTheme, + textScaleFactor: MediaQuery.of(context).textScaleFactor, + onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, + onChangeStart: widget.onChangeStart != null ? _handleDragStart : null, + onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null, + state: this, + semanticFormatterCallback: widget.semanticFormatterCallback, ); } - - final LayerLink _layerLink = LayerLink(); - - OverlayEntry overlayEntry; - - void showValueIndicator() { - if (overlayEntry == null) { - overlayEntry = OverlayEntry( - builder: (BuildContext context) { - return CompositedTransformFollower( - link: _layerLink, - child: _ValueIndicatorRenderObjectWidget( - state: this, - ), - ); - }, - ); - Overlay.of(context).insert(overlayEntry); - } - } } class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { @@ -665,13 +594,11 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { this.labels, this.sliderTheme, this.textScaleFactor, - this.screenSize, this.onChanged, this.onChangeStart, this.onChangeEnd, this.state, this.semanticFormatterCallback, - this.useV2Slider, }) : super(key: key); final RangeValues values; @@ -679,13 +606,11 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { final RangeLabels labels; final SliderThemeData sliderTheme; final double textScaleFactor; - final Size screenSize; final ValueChanged onChanged; final ValueChanged onChangeStart; final ValueChanged onChangeEnd; final RangeSemanticFormatterCallback semanticFormatterCallback; final _RangeSliderState state; - final bool useV2Slider; @override _RenderRangeSlider createRenderObject(BuildContext context) { @@ -696,7 +621,6 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { sliderTheme: sliderTheme, theme: Theme.of(context), textScaleFactor: textScaleFactor, - screenSize: screenSize, onChanged: onChanged, onChangeStart: onChangeStart, onChangeEnd: onChangeEnd, @@ -704,7 +628,6 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { textDirection: Directionality.of(context), semanticFormatterCallback: semanticFormatterCallback, platform: Theme.of(context).platform, - useV2Slider: useV2Slider, ); } @@ -717,7 +640,6 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { ..sliderTheme = sliderTheme ..theme = Theme.of(context) ..textScaleFactor = textScaleFactor - ..screenSize = screenSize ..onChanged = onChanged ..onChangeStart = onChangeStart ..onChangeEnd = onChangeEnd @@ -735,7 +657,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix SliderThemeData sliderTheme, ThemeData theme, double textScaleFactor, - Size screenSize, TargetPlatform platform, ValueChanged onChanged, RangeSemanticFormatterCallback semanticFormatterCallback, @@ -743,7 +664,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix this.onChangeEnd, @required _RangeSliderState state, @required TextDirection textDirection, - bool useV2Slider, }) : assert(values != null), assert(values.start >= 0.0 && values.start <= 1.0), assert(values.end >= 0.0 && values.end <= 1.0), @@ -757,11 +677,9 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix _sliderTheme = sliderTheme, _theme = theme, _textScaleFactor = textScaleFactor, - _screenSize = screenSize, _onChanged = onChanged, _state = state, - _textDirection = textDirection, - _useV2Slider = useV2Slider { + _textDirection = textDirection { _updateLabelPainters(); final GestureArenaTeam team = GestureArenaTeam(); _drag = HorizontalDragGestureRecognizer() @@ -782,12 +700,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix _valueIndicatorAnimation = CurvedAnimation( parent: _state.valueIndicatorController, curve: Curves.fastOutSlowIn, - )..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.dismissed && _state.overlayEntry != null) { - _state.overlayEntry.remove(); - _state.overlayEntry = null; - } - }); + ); _enableAnimation = CurvedAnimation( parent: _state.enableController, curve: Curves.easeInOut, @@ -936,15 +849,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix _updateLabelPainters(); } - Size get screenSize => _screenSize; - Size _screenSize; - set screenSize(Size value) { - if (value == screenSize) - return; - _screenSize = value; - markNeedsPaint(); - } - ValueChanged get onChanged => _onChanged; ValueChanged _onChanged; set onChanged(ValueChanged value) { @@ -1009,8 +913,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix return 0.05; } - final bool _useV2Slider; - void _updateLabelPainters() { _updateLabelPainter(Thumb.start); _updateLabelPainter(Thumb.end); @@ -1107,7 +1009,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix } void _startInteraction(Offset globalPosition) { - _state.showValueIndicator(); final double tapValue = _getValueFromGlobalPosition(globalPosition).clamp(0.0, 1.0) as double; _lastThumbSelection = sliderTheme.thumbSelector(textDirection, values, tapValue, _thumbSize, size, 0); @@ -1299,11 +1200,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix isEnabled: isEnabled, ); - final bool startThumbSelected = _lastThumbSelection == Thumb.start; - final bool endThumbSelected = _lastThumbSelection == Thumb.end; - if (!_overlayAnimation.isDismissed) { - if (startThumbSelected) { + if (_lastThumbSelection == Thumb.start) { _sliderTheme.overlayShape.paint( context, startThumbCenter, @@ -1317,7 +1215,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix value: startValue, ); } - if (endThumbSelected) { + if (_lastThumbSelection == Thumb.end) { _sliderTheme.overlayShape.paint( context, endThumbCenter, @@ -1338,8 +1236,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix isEnabled: isEnabled, sliderTheme: _sliderTheme, ).width; - final double padding = _useV2Slider ? trackRect.height : tickMarkWidth; - final double adjustedTrackWidth = trackRect.width - padding; + final double adjustedTrackWidth = trackRect.width - tickMarkWidth; // If the tick marks would be too dense, don't bother painting them. if (adjustedTrackWidth / divisions >= 3.0 * tickMarkWidth) { final double dy = trackRect.center.dy; @@ -1347,7 +1244,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix final double value = i / divisions; // The ticks are mapped to be within the track, so the tick mark width // must be subtracted from the track width. - final double dx = trackRect.left + value * adjustedTrackWidth + padding / 2; + final double dx = trackRect.left + value * adjustedTrackWidth + tickMarkWidth / 2; final Offset tickMarkOffset = Offset(dx, dy); _sliderTheme.rangeTickMarkShape.paint( context, @@ -1376,27 +1273,22 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix final double bottomValue = isLastThumbStart ? endValue : startValue; final double topValue = isLastThumbStart ? startValue : endValue; final bool shouldPaintValueIndicators = isEnabled && labels != null && !_valueIndicatorAnimation.isDismissed && showValueIndicator; - final Size resolvedscreenSize = screenSize.isEmpty ? size : screenSize; if (shouldPaintValueIndicators) { - _state.paintBottomValueIndicator = (PaintingContext context, Offset offset) { - _sliderTheme.rangeValueIndicatorShape.paint( - context, - bottomThumbCenter, - activationAnimation: _valueIndicatorAnimation, - enableAnimation: _enableAnimation, - isDiscrete: isDiscrete, - isOnTop: false, - labelPainter: bottomLabelPainter, - parentBox: this, - sliderTheme: _sliderTheme, - textDirection: _textDirection, - thumb: bottomThumb, - value: bottomValue, - textScaleFactor: textScaleFactor, - sizeWithOverflow: resolvedscreenSize, - ); - }; + _sliderTheme.rangeValueIndicatorShape.paint( + context, + bottomThumbCenter, + activationAnimation: _valueIndicatorAnimation, + enableAnimation: _enableAnimation, + isDiscrete: isDiscrete, + isOnTop: false, + labelPainter: bottomLabelPainter, + parentBox: this, + sliderTheme: _sliderTheme, + textDirection: _textDirection, + thumb: bottomThumb, + value: bottomValue, + ); } _sliderTheme.rangeThumbShape.paint( @@ -1409,7 +1301,6 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix textDirection: textDirection, sliderTheme: _sliderTheme, thumb: bottomThumb, - isPressed: bottomThumb == Thumb.start ? startThumbSelected : endThumbSelected, ); if (shouldPaintValueIndicators) { @@ -1418,29 +1309,15 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix center: startThumbCenter, labelPainter: _startLabelPainter, activationAnimation: _valueIndicatorAnimation, - textScaleFactor: textScaleFactor, - sizeWithOverflow: resolvedscreenSize, ); final double endOffset = sliderTheme.rangeValueIndicatorShape.getHorizontalShift( parentBox: this, center: endThumbCenter, labelPainter: _endLabelPainter, activationAnimation: _valueIndicatorAnimation, - textScaleFactor: textScaleFactor, - sizeWithOverflow: resolvedscreenSize, ); - final double startHalfWidth = sliderTheme.rangeValueIndicatorShape.getPreferredSize( - isEnabled, - isDiscrete, - labelPainter: _startLabelPainter, - textScaleFactor: textScaleFactor, - ).width / 2; - final double endHalfWidth = sliderTheme.rangeValueIndicatorShape.getPreferredSize( - isEnabled, - isDiscrete, - labelPainter: _endLabelPainter, - textScaleFactor: textScaleFactor, - ).width / 2; + final double startHalfWidth = sliderTheme.rangeValueIndicatorShape.getPreferredSize(isEnabled, isDiscrete, labelPainter: _startLabelPainter).width / 2; + final double endHalfWidth = sliderTheme.rangeValueIndicatorShape.getPreferredSize(isEnabled, isDiscrete, labelPainter: _endLabelPainter).width / 2; double innerOverflow = startHalfWidth + endHalfWidth; switch (textDirection) { case TextDirection.ltr: @@ -1453,37 +1330,32 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix break; } - _state.paintTopValueIndicator = (PaintingContext context, Offset offset) { - _sliderTheme.rangeValueIndicatorShape.paint( - context, - topThumbCenter, - activationAnimation: _valueIndicatorAnimation, - enableAnimation: _enableAnimation, - isDiscrete: isDiscrete, - isOnTop: thumbDelta < innerOverflow, - labelPainter: topLabelPainter, - parentBox: this, - sliderTheme: _sliderTheme, - textDirection: _textDirection, - thumb: topThumb, - value: topValue, - textScaleFactor: textScaleFactor, - sizeWithOverflow: resolvedscreenSize, - ); - }; + _sliderTheme.rangeValueIndicatorShape.paint( + context, + topThumbCenter, + activationAnimation: _valueIndicatorAnimation, + enableAnimation: _enableAnimation, + isDiscrete: isDiscrete, + isOnTop: thumbDelta < innerOverflow, + labelPainter: topLabelPainter, + parentBox: this, + sliderTheme: _sliderTheme, + textDirection: _textDirection, + thumb: topThumb, + value: topValue, + ); } _sliderTheme.rangeThumbShape.paint( context, topThumbCenter, - activationAnimation: _overlayAnimation, + activationAnimation: _valueIndicatorAnimation, enableAnimation: _enableAnimation, isDiscrete: isDiscrete, isOnTop: thumbDelta < sliderTheme.rangeThumbShape.getPreferredSize(isEnabled, isDiscrete).width, textDirection: textDirection, sliderTheme: _sliderTheme, thumb: topThumb, - isPressed: topThumb == Thumb.start ? startThumbSelected : endThumbSelected, ); } @@ -1547,66 +1419,3 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix return (value - _semanticActionUnit).clamp(0.0, 1.0) as double; } } - - -class _ValueIndicatorRenderObjectWidget extends LeafRenderObjectWidget { - const _ValueIndicatorRenderObjectWidget({ - this.state, - }); - - final _RangeSliderState state; - - @override - _RenderValueIndicator createRenderObject(BuildContext context) { - return _RenderValueIndicator( - state: state, - ); - } - @override - void updateRenderObject(BuildContext context, _RenderValueIndicator renderObject) { - renderObject._state = state; - } -} - -class _RenderValueIndicator extends RenderBox with RelayoutWhenSystemFontsChangeMixin { - _RenderValueIndicator({ - _RangeSliderState state, - }) :_state = state { - _valueIndicatorAnimation = CurvedAnimation( - parent: _state.valueIndicatorController, - curve: Curves.fastOutSlowIn, - ); - } - - Animation _valueIndicatorAnimation; - _RangeSliderState _state; - - @override - bool get sizedByParent => true; - - @override - void attach(PipelineOwner owner) { - super.attach(owner); - _valueIndicatorAnimation.addListener(markNeedsPaint); - _state.startPositionController.addListener(markNeedsPaint); - _state.endPositionController.addListener(markNeedsPaint); - } - - @override - void detach() { - _valueIndicatorAnimation.removeListener(markNeedsPaint); - _state.startPositionController.removeListener(markNeedsPaint); - _state.endPositionController.removeListener(markNeedsPaint); - super.detach(); - } - - @override - void paint(PaintingContext context, Offset offset) { - if (_state.paintBottomValueIndicator != null) { - _state.paintBottomValueIndicator(context, offset); - } - if (_state.paintTopValueIndicator != null) { - _state.paintTopValueIndicator(context, offset); - } - } -} diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index f920b4d579a..6a473b10f2c 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -31,11 +31,6 @@ import 'theme.dart'; /// * [Slider.semanticFormatterCallback], which shows an example use case. typedef SemanticFormatterCallback = String Function(double value); -/// [Slider] uses this callback to paint the value indicator on the overlay. -/// Since the value indicator is painted on the Overlay; this method paints the -/// value indicator in a [RenderBox] that appears in the [Overlay]. -typedef PaintValueIndicator = void Function(PaintingContext context, Offset offset); - enum _SliderType { material, adaptive } /// A Material Design slider. @@ -129,7 +124,6 @@ class Slider extends StatefulWidget { this.activeColor, this.inactiveColor, this.semanticFormatterCallback, - this.useV2Slider = false, }) : _sliderType = _SliderType.material, assert(value != null), assert(min != null), @@ -137,7 +131,6 @@ class Slider extends StatefulWidget { assert(min <= max), assert(value >= min && value <= max), assert(divisions == null || divisions > 0), - assert(useV2Slider != null), super(key: key); /// Creates a [CupertinoSlider] if the target platform is iOS, creates a @@ -160,7 +153,6 @@ class Slider extends StatefulWidget { this.activeColor, this.inactiveColor, this.semanticFormatterCallback, - this.useV2Slider = false, }) : _sliderType = _SliderType.adaptive, assert(value != null), assert(min != null), @@ -168,7 +160,6 @@ class Slider extends StatefulWidget { assert(min <= max), assert(value >= min && value <= max), assert(divisions == null || divisions > 0), - assert(useV2Slider != null), super(key: key); /// The currently selected value for this slider. @@ -383,19 +374,6 @@ class Slider extends StatefulWidget { /// Ignored if this slider is created with [Slider.adaptive] final SemanticFormatterCallback semanticFormatterCallback; - /// Whether to use the updated Material spec version of the [Slider]. - /// * The v2 Slider has an updated value indicator that matches the latest specs. - /// * The value indicator is painted on the Overlay. - /// * The active track is bigger than the inactive track. - /// * The thumb that is activated has elevation. - /// * Updated value indicators in case they overlap with each other. - /// * - /// - /// This is a temporary flag for migrating the slider from v1 to v2. To avoid - /// unexpected breaking changes, this value should be set to true. Setting - /// this to false is considered deprecated. - final bool useV2Slider; - final _SliderType _sliderType ; @override @@ -414,7 +392,6 @@ class Slider extends StatefulWidget { properties.add(StringProperty('label', label)); properties.add(ColorProperty('activeColor', activeColor)); properties.add(ColorProperty('inactiveColor', inactiveColor)); - properties.add(FlagProperty('useV2Slider', value: useV2Slider, ifFalse: 'useV1Slider')); properties.add(ObjectFlagProperty>.has('semanticFormatterCallback', semanticFormatterCallback)); } } @@ -435,8 +412,6 @@ class _SliderState extends State with TickerProviderStateMixin { // and the next on a discrete slider. AnimationController positionController; Timer interactionTimer; - // Value Indicator Animation that appears on the Overlay. - PaintValueIndicator paintValueIndicator; @override void initState() { @@ -504,6 +479,14 @@ class _SliderState extends State with TickerProviderStateMixin { return widget.max > widget.min ? (value - widget.min) / (widget.max - widget.min) : 0.0; } + static const double _defaultTrackHeight = 2; + static const SliderTrackShape _defaultTrackShape = RoundedRectSliderTrackShape(); + static const SliderTickMarkShape _defaultTickMarkShape = RoundSliderTickMarkShape(); + static const SliderComponentShape _defaultOverlayShape = RoundSliderOverlayShape(); + static const SliderComponentShape _defaultThumbShape = RoundSliderThumbShape(); + static const SliderComponentShape _defaultValueIndicatorShape = PaddleSliderValueIndicatorShape(); + static const ShowValueIndicator _defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete; + @override Widget build(BuildContext context) { assert(debugCheckHasMaterial(context)); @@ -542,28 +525,6 @@ class _SliderState extends State with TickerProviderStateMixin { // colors come from the ThemeData.colorScheme. These colors, along with // the default shapes and text styles are aligned to the Material // Guidelines. - - final bool useV2Slider = widget.useV2Slider; - final double _defaultTrackHeight = useV2Slider ? 4 : 2; - final SliderTrackShape _defaultTrackShape = RoundedRectSliderTrackShape(useV2Slider: useV2Slider); - final SliderTickMarkShape _defaultTickMarkShape = RoundSliderTickMarkShape(useV2Slider: useV2Slider); - const SliderComponentShape _defaultOverlayShape = RoundSliderOverlayShape(); - final SliderComponentShape _defaultThumbShape = RoundSliderThumbShape(useV2Slider: useV2Slider); - final SliderComponentShape _defaultValueIndicatorShape = useV2Slider ? const RectangularSliderValueIndicatorShape() : const PaddleSliderValueIndicatorShape(); - const ShowValueIndicator _defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete; - - // The value indicator's color is not the same as the thumb and active track - // (which can be defined by activeColor) if the - // RectangularSliderValueIndicatorShape is used. In all other cases, the - // value indicator is assumed to be the same as the active color. - final SliderComponentShape valueIndicatorShape = sliderTheme.valueIndicatorShape ?? _defaultValueIndicatorShape; - Color valueIndicatorColor; - if (valueIndicatorShape is RectangularSliderValueIndicatorShape) { - valueIndicatorColor = sliderTheme.valueIndicatorColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(0.60), theme.colorScheme.surface.withOpacity(0.90)); - } else { - valueIndicatorColor = widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary; - } - sliderTheme = sliderTheme.copyWith( trackHeight: sliderTheme.trackHeight ?? _defaultTrackHeight, activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary, @@ -575,41 +536,31 @@ class _SliderState extends State with TickerProviderStateMixin { disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.12), disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? theme.colorScheme.onSurface.withOpacity(0.12), thumbColor: widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary, - disabledThumbColor: sliderTheme.disabledThumbColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(.38), const Color(0xFFFFFFFF)), + disabledThumbColor: sliderTheme.disabledThumbColor ?? theme.colorScheme.onSurface.withOpacity(0.38), overlayColor: widget.activeColor?.withOpacity(0.12) ?? sliderTheme.overlayColor ?? theme.colorScheme.primary.withOpacity(0.12), - valueIndicatorColor: valueIndicatorColor, + valueIndicatorColor: widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary, trackShape: sliderTheme.trackShape ?? _defaultTrackShape, tickMarkShape: sliderTheme.tickMarkShape ?? _defaultTickMarkShape, thumbShape: sliderTheme.thumbShape ?? _defaultThumbShape, overlayShape: sliderTheme.overlayShape ?? _defaultOverlayShape, - valueIndicatorShape: valueIndicatorShape, + valueIndicatorShape: sliderTheme.valueIndicatorShape ?? _defaultValueIndicatorShape, showValueIndicator: sliderTheme.showValueIndicator ?? _defaultShowValueIndicator, valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyText1.copyWith( color: theme.colorScheme.onPrimary, ), ); - // This size is used as the max bounds for the painting of the value - // indicators It must be kept in sync with the function with the same name - // in range_slider.dart. - Size _screenSize() => MediaQuery.of(context).size; - - return CompositedTransformTarget( - link: _layerLink, - child: _SliderRenderObjectWidget( - value: _unlerp(widget.value), - divisions: widget.divisions, - label: widget.label, - sliderTheme: sliderTheme, - textScaleFactor: MediaQuery.of(context).textScaleFactor, - screenSize: _screenSize(), - onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, - onChangeStart: widget.onChangeStart != null ? _handleDragStart : null, - onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null, - state: this, - semanticFormatterCallback: widget.semanticFormatterCallback, - useV2Slider: widget.useV2Slider, - ), + return _SliderRenderObjectWidget( + value: _unlerp(widget.value), + divisions: widget.divisions, + label: widget.label, + sliderTheme: sliderTheme, + mediaQueryData: MediaQuery.of(context), + onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, + onChangeStart: widget.onChangeStart != null ? _handleDragStart : null, + onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null, + state: this, + semanticFormatterCallback: widget.semanticFormatterCallback, ); } @@ -631,28 +582,8 @@ class _SliderState extends State with TickerProviderStateMixin { ), ); } - final LayerLink _layerLink = LayerLink(); - - OverlayEntry overlayEntry; - - void showValueIndicator() { - if (overlayEntry == null) { - overlayEntry = OverlayEntry( - builder: (BuildContext context) { - return CompositedTransformFollower( - link: _layerLink, - child: _ValueIndicatorRenderObjectWidget( - state: this, - ), - ); - }, - ); - Overlay.of(context).insert(overlayEntry); - } - } } - class _SliderRenderObjectWidget extends LeafRenderObjectWidget { const _SliderRenderObjectWidget({ Key key, @@ -660,28 +591,24 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { this.divisions, this.label, this.sliderTheme, - this.textScaleFactor, - this.screenSize, + this.mediaQueryData, this.onChanged, this.onChangeStart, this.onChangeEnd, this.state, this.semanticFormatterCallback, - this.useV2Slider, }) : super(key: key); final double value; final int divisions; final String label; final SliderThemeData sliderTheme; - final double textScaleFactor; - final Size screenSize; + final MediaQueryData mediaQueryData; final ValueChanged onChanged; final ValueChanged onChangeStart; final ValueChanged onChangeEnd; final SemanticFormatterCallback semanticFormatterCallback; final _SliderState state; - final bool useV2Slider; @override _RenderSlider createRenderObject(BuildContext context) { @@ -690,8 +617,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { divisions: divisions, label: label, sliderTheme: sliderTheme, - textScaleFactor: textScaleFactor, - screenSize: screenSize, + mediaQueryData: mediaQueryData, onChanged: onChanged, onChangeStart: onChangeStart, onChangeEnd: onChangeEnd, @@ -699,7 +625,6 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { textDirection: Directionality.of(context), semanticFormatterCallback: semanticFormatterCallback, platform: Theme.of(context).platform, - useV2Slider: useV2Slider, ); } @@ -711,8 +636,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ..label = label ..sliderTheme = sliderTheme ..theme = Theme.of(context) - ..textScaleFactor = textScaleFactor - ..screenSize = screenSize + ..mediaQueryData = mediaQueryData ..onChanged = onChanged ..onChangeStart = onChangeStart ..onChangeEnd = onChangeEnd @@ -730,8 +654,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { int divisions, String label, SliderThemeData sliderTheme, - double textScaleFactor, - Size screenSize, + MediaQueryData mediaQueryData, TargetPlatform platform, ValueChanged onChanged, SemanticFormatterCallback semanticFormatterCallback, @@ -739,22 +662,19 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { this.onChangeEnd, @required _SliderState state, @required TextDirection textDirection, - bool useV2Slider, }) : assert(value != null && value >= 0.0 && value <= 1.0), - assert(state != null), - assert(textDirection != null), - _platform = platform, - _semanticFormatterCallback = semanticFormatterCallback, - _label = label, - _value = value, - _divisions = divisions, - _sliderTheme = sliderTheme, - _textScaleFactor = textScaleFactor, - _screenSize = screenSize, - _onChanged = onChanged, - _state = state, - _textDirection = textDirection, - _useV2Slider = useV2Slider { + assert(state != null), + assert(textDirection != null), + _platform = platform, + _semanticFormatterCallback = semanticFormatterCallback, + _label = label, + _value = value, + _divisions = divisions, + _sliderTheme = sliderTheme, + _mediaQueryData = mediaQueryData, + _onChanged = onChanged, + _state = state, + _textDirection = textDirection { _updateLabelPainter(); final GestureArenaTeam team = GestureArenaTeam(); _drag = HorizontalDragGestureRecognizer() @@ -775,12 +695,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _valueIndicatorAnimation = CurvedAnimation( parent: _state.valueIndicatorController, curve: Curves.fastOutSlowIn, - )..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.dismissed && _state.overlayEntry != null) { - _state.overlayEntry.remove(); - _state.overlayEntry = null; - } - }); + ); _enableAnimation = CurvedAnimation( parent: _state.enableController, curve: Curves.easeInOut, @@ -911,26 +826,18 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { markNeedsPaint(); } - double get textScaleFactor => _textScaleFactor; - double _textScaleFactor; - set textScaleFactor(double value) { - if (value == _textScaleFactor) { + MediaQueryData get mediaQueryData => _mediaQueryData; + MediaQueryData _mediaQueryData; + set mediaQueryData(MediaQueryData value) { + if (value == _mediaQueryData) { return; } - _textScaleFactor = value; + _mediaQueryData = value; + // Media query data includes the textScaleFactor, so we need to update the + // label painter. _updateLabelPainter(); } - Size get screenSize => _screenSize; - Size _screenSize; - set screenSize(Size value) { - if (value == _screenSize) { - return; - } - _screenSize = value; - markNeedsPaint(); - } - ValueChanged get onChanged => _onChanged; ValueChanged _onChanged; set onChanged(ValueChanged value) { @@ -964,8 +871,6 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _updateLabelPainter(); } - final bool _useV2Slider; - bool get showValueIndicator { bool showValueIndicator; switch (_sliderTheme.showValueIndicator) { @@ -1010,7 +915,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { text: label, ) ..textDirection = textDirection - ..textScaleFactor = textScaleFactor + ..textScaleFactor = _mediaQueryData.textScaleFactor ..layout(); } else { _labelPainter.text = null; @@ -1070,7 +975,6 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { } void _startInteraction(Offset globalPosition) { - _state.showValueIndicator(); if (isInteractive) { _active = true; // We supply the *current* value as the start location, so that if we have @@ -1104,7 +1008,6 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _active = false; _currentDragValue = 0.0; _state.overlayController.reverse(); - if (showValueIndicator && _state.interactionTimer == null) { _state.valueIndicatorController.reverse(); } @@ -1227,8 +1130,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { isEnabled: isInteractive, sliderTheme: _sliderTheme, ).width; - final double padding = _useV2Slider ? trackRect.height : tickMarkWidth; - final double adjustedTrackWidth = trackRect.width - padding; + final double adjustedTrackWidth = trackRect.width - tickMarkWidth; // If the tick marks would be too dense, don't bother painting them. if (adjustedTrackWidth / divisions >= 3.0 * tickMarkWidth) { final double dy = trackRect.center.dy; @@ -1236,7 +1138,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { final double value = i / divisions; // The ticks are mapped to be within the track, so the tick mark width // must be subtracted from the track width. - final double dx = trackRect.left + value * adjustedTrackWidth + padding / 2; + final double dx = trackRect.left + value * adjustedTrackWidth + tickMarkWidth / 2; final Offset tickMarkOffset = Offset(dx, dy); _sliderTheme.tickMarkShape.paint( context, @@ -1254,36 +1156,31 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { if (isInteractive && label != null && !_valueIndicatorAnimation.isDismissed) { if (showValueIndicator) { - _state.paintValueIndicator = (PaintingContext context, Offset offset) { - _sliderTheme.valueIndicatorShape.paint( - context, - offset + thumbCenter, - activationAnimation: _valueIndicatorAnimation, - enableAnimation: _enableAnimation, - isDiscrete: isDiscrete, - labelPainter: _labelPainter, - parentBox: this, - sliderTheme: _sliderTheme, - textDirection: _textDirection, - value: _value, - textScaleFactor: textScaleFactor, - sizeWithOverflow: screenSize.isEmpty ? size : screenSize, - ); - }; + _sliderTheme.valueIndicatorShape.paint( + context, + thumbCenter, + activationAnimation: _valueIndicatorAnimation, + enableAnimation: _enableAnimation, + isDiscrete: isDiscrete, + labelPainter: _labelPainter, + parentBox: this, + sliderTheme: _sliderTheme, + textDirection: _textDirection, + value: _value, + ); } } _sliderTheme.thumbShape.paint( context, thumbCenter, - activationAnimation: _overlayAnimation, + activationAnimation: _valueIndicatorAnimation, enableAnimation: _enableAnimation, isDiscrete: isDiscrete, labelPainter: _labelPainter, parentBox: this, sliderTheme: _sliderTheme, textDirection: _textDirection, - sizeWithOverflow: screenSize.isEmpty ? size : screenSize, value: _value, ); } @@ -1323,59 +1220,3 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { } } } - -class _ValueIndicatorRenderObjectWidget extends LeafRenderObjectWidget { - const _ValueIndicatorRenderObjectWidget({ - this.state, - }); - - final _SliderState state; - - @override - _RenderValueIndicator createRenderObject(BuildContext context) { - return _RenderValueIndicator( - state: state, - ); - } - @override - void updateRenderObject(BuildContext context, _RenderValueIndicator renderObject) { - renderObject._state = state; - } -} - -class _RenderValueIndicator extends RenderBox with RelayoutWhenSystemFontsChangeMixin { - _RenderValueIndicator({ - _SliderState state, - }) : _state = state { - _valueIndicatorAnimation = CurvedAnimation( - parent: _state.valueIndicatorController, - curve: Curves.fastOutSlowIn, - ); - } - Animation _valueIndicatorAnimation; - _SliderState _state; - - @override - bool get sizedByParent => true; - - @override - void attach(PipelineOwner owner) { - super.attach(owner); - _valueIndicatorAnimation.addListener(markNeedsPaint); - _state.positionController.addListener(markNeedsPaint); - } - - @override - void detach() { - _valueIndicatorAnimation.removeListener(markNeedsPaint); - _state.positionController.removeListener(markNeedsPaint); - super.detach(); - } - - @override - void paint(PaintingContext context, Offset offset) { - if (_state.paintValueIndicator != null) { - _state.paintValueIndicator(context, offset); - } - } -} diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index 8cfe6d4541d..c9579d81f12 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -108,28 +108,6 @@ import 'theme_data.dart'; /// track segments. In [TextDirection.ltr], the start of the slider is on the /// left, and in [TextDirection.rtl], the start of the slider is on the right. /// {@endtemplate} -/// -/// {@template flutter.material.slider.useV2Slider} -/// Whether to use the updated Material spec version of the slider shape. -/// -/// This is a temporary flag for migrating the slider from v1 to v2. To avoid -/// unexpected breaking changes, this value should be set to true. Setting -/// this to false is considered deprecated. -/// {@endtemplate} -/// -/// {@template flutter.material.slider.shape.textScaleFactor} -/// Can be used to determine whether the component should -/// paint larger or smaller, depending on whether [textScaleFactor] is greater -/// than 1 for larger, and between 0 and 1 for smaller. It usually comes from -/// [MediaQueryData.textScaleFactor]. -/// {@endtemplate} -/// -/// {@template flutter.material.rangeSlider.shape.sizeWithOverflow} -/// Can be used to determine the bounds the drawing of the -/// components that are outside of the regular slider bounds. It's the size of -/// the box, whose center is aligned with the slider's bounds, that the value -/// indicators must be drawn within. Typically, it is bigger than the slider. -/// {@endtemplate} /// Applies a slider theme to descendant [Slider] widgets. /// @@ -300,7 +278,7 @@ enum Thumb { /// by creating subclasses of [SliderTrackShape], /// [SliderComponentShape], and/or [SliderTickMarkShape]. See /// [RoundSliderThumbShape], [RectangularSliderTrackShape], -/// [RoundSliderTickMarkShape], [RectangularSliderValueIndicatorShape], and +/// [RoundSliderTickMarkShape], [PaddleSliderValueIndicatorShape], and /// [RoundSliderOverlayShape] for examples. /// /// The track painting can be skipped by specifying 0 for [trackHeight]. @@ -512,7 +490,6 @@ class SliderThemeData with Diagnosticable { /// The color given to the [valueIndicatorShape] to draw itself with. final Color valueIndicatorColor; - /// The shape that will be used to draw the [Slider]'s overlay. /// /// Both the [overlayColor] and a non default [overlayShape] may be specified. @@ -999,10 +976,6 @@ abstract class SliderComponentShape { /// [labelPainter] already has the [textDirection] set. /// /// [value] is the current parametric value (from 0.0 to 1.0) of the slider. - /// - /// {@macro flutter.material.slider.shape.textScaleFactor} - /// - /// {@macro flutter.material.slider.shape.sizeWithOverflow} void paint( PaintingContext context, Offset center, { @@ -1014,8 +987,6 @@ abstract class SliderComponentShape { SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }); /// Special instance of [SliderComponentShape] to skip the thumb drawing. @@ -1231,9 +1202,6 @@ abstract class RangeSliderThumbShape { /// left and right thumb. /// /// {@macro flutter.material.rangeSlider.shape.thumb} - /// - /// [isPressed] can be used to give the selected thumb additional selected - /// or pressed state visual feedback, such as a larger shadow. void paint( PaintingContext context, Offset center, { @@ -1245,7 +1213,6 @@ abstract class RangeSliderThumbShape { TextDirection textDirection, SliderThemeData sliderTheme, Thumb thumb, - bool isPressed, }); } @@ -1271,14 +1238,7 @@ abstract class RangeSliderValueIndicatorShape { /// /// [labelPainter] helps determine the width of the shape. It is variable /// width because it is derived from a formatted string. - /// - /// {@macro flutter.material.slider.shape.textScaleFactor} - Size getPreferredSize( - bool isEnabled, - bool isDiscrete, { - TextPainter labelPainter, - double textScaleFactor, - }); + Size getPreferredSize(bool isEnabled, bool isDiscrete, { TextPainter labelPainter }); /// Determines the best offset to keep this shape on the screen. /// @@ -1289,8 +1249,6 @@ abstract class RangeSliderValueIndicatorShape { Offset center, TextPainter labelPainter, Animation activationAnimation, - double textScaleFactor, - Size sizeWithOverflow, }) { return 0; } @@ -1312,12 +1270,6 @@ abstract class RangeSliderValueIndicatorShape { /// the default case, this is used to paint a stroke around the top indicator /// for better visibility between the two indicators. /// - /// {@macro flutter.material.slider.shape.textScaleFactor} - /// - /// {@macro flutter.material.slider.shape.sizeWithOverflow} - /// - /// {@macro flutter.material.rangeSlider.shape.parentBox} - /// /// {@macro flutter.material.rangeSlider.shape.sliderTheme} /// /// [textDirection] can be used to determine how any extra text or graphics, @@ -1335,8 +1287,6 @@ abstract class RangeSliderValueIndicatorShape { bool isDiscrete, bool isOnTop, TextPainter labelPainter, - double textScaleFactor, - Size sizeWithOverflow, RenderBox parentBox, SliderThemeData sliderTheme, TextDirection textDirection, @@ -1602,17 +1552,17 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS assert(thumbCenter != null); assert(isEnabled != null); assert(isDiscrete != null); - // If the slider [SliderThemeData.trackHeight] is less than or equal to 0, - // then it makes no difference whether the track is painted or not, - // therefore the painting can be a no-op. + // If the slider track height is less than or equal to 0, then it makes no + // difference whether the track is painted or not, therefore the painting + // can be a no-op. if (sliderTheme.trackHeight <= 0) { return; } // Assign the track segment paints, which are left: active, right: inactive, // but reversed for right to left text. - final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor, end: sliderTheme.activeTrackColor); - final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor, end: sliderTheme.inactiveTrackColor); + final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor , end: sliderTheme.activeTrackColor); + final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor , end: sliderTheme.inactiveTrackColor); final Paint activePaint = Paint()..color = activeTrackColorTween.evaluate(enableAnimation); final Paint inactivePaint = Paint()..color = inactiveTrackColorTween.evaluate(enableAnimation); Paint leftTrackPaint; @@ -1636,10 +1586,11 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS isDiscrete: isDiscrete, ); - final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx, trackRect.bottom); + final Size thumbSize = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete); + final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx - thumbSize.width / 2, trackRect.bottom); if (!leftTrackSegment.isEmpty) context.canvas.drawRect(leftTrackSegment, leftTrackPaint); - final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx, trackRect.top, trackRect.right, trackRect.bottom); + final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + thumbSize.width / 2, trackRect.top, trackRect.right, trackRect.bottom); if (!rightTrackSegment.isEmpty) context.canvas.drawRect(rightTrackSegment, rightTrackPaint); } @@ -1669,10 +1620,7 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS /// * [RectangularSliderTrackShape], for a similar track with sharp edges. class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackShape { /// Create a slider track that draws two rectangles with rounded outer edges. - const RoundedRectSliderTrackShape({ this.useV2Slider = false }); - - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; + const RoundedRectSliderTrackShape(); @override void paint( @@ -1685,7 +1633,6 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS @required Offset thumbCenter, bool isDiscrete = false, bool isEnabled = false, - double additionalActiveTrackHeight = 2, }) { assert(context != null); assert(offset != null); @@ -1699,9 +1646,9 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS assert(enableAnimation != null); assert(textDirection != null); assert(thumbCenter != null); - // If the slider [SliderThemeData.trackHeight] is less than or equal to 0, - // then it makes no difference whether the track is painted or not, - // therefore the painting can be a no-op. + // If the slider track height is less than or equal to 0, then it makes no + // difference whether the track is painted or not, therefore the painting + // can be a no-op. if (sliderTheme.trackHeight <= 0) { return; } @@ -1732,49 +1679,22 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS isEnabled: isEnabled, isDiscrete: isDiscrete, ); - final Radius trackRadius = Radius.circular(trackRect.height / 2); - final Radius activeTrackRadius = Radius.circular(trackRect.height / 2 + 1); - if (useV2Slider) { - context.canvas.drawRRect( - RRect.fromLTRBAndCorners( - trackRect.left, - (textDirection == TextDirection.ltr) ? trackRect.top - (additionalActiveTrackHeight / 2): trackRect.top, - thumbCenter.dx, - (textDirection == TextDirection.ltr) ? trackRect.bottom + (additionalActiveTrackHeight / 2) : trackRect.bottom, - topLeft: (textDirection == TextDirection.ltr) ? activeTrackRadius : trackRadius, - bottomLeft: (textDirection == TextDirection.ltr) ? activeTrackRadius: trackRadius, - ), - leftTrackPaint, - ); - context.canvas.drawRRect( - RRect.fromLTRBAndCorners( - thumbCenter.dx, - (textDirection == TextDirection.rtl) ? trackRect.top - (additionalActiveTrackHeight / 2) : trackRect.top, - trackRect.right, - (textDirection == TextDirection.rtl) ? trackRect.bottom + (additionalActiveTrackHeight / 2) : trackRect.bottom, - topRight: (textDirection == TextDirection.rtl) ? activeTrackRadius : trackRadius, - bottomRight: (textDirection == TextDirection.rtl) ? activeTrackRadius : trackRadius, - ), - rightTrackPaint, - ); - } else { - // The arc rects create a semi-circle with radius equal to track height. - final Rect leftTrackArcRect = Rect.fromLTWH(trackRect.left, trackRect.top, trackRect.height, trackRect.height); - if (!leftTrackArcRect.isEmpty) - context.canvas.drawArc(leftTrackArcRect, math.pi / 2, math.pi, false, leftTrackPaint); - final Rect rightTrackArcRect = Rect.fromLTWH(trackRect.right - trackRect.height / 2, trackRect.top, trackRect.height, trackRect.height); - if (!rightTrackArcRect.isEmpty) - context.canvas.drawArc(rightTrackArcRect, -math.pi / 2, math.pi, false, rightTrackPaint); + // The arc rects create a semi-circle with radius equal to track height. + final Rect leftTrackArcRect = Rect.fromLTWH(trackRect.left, trackRect.top, trackRect.height, trackRect.height); + if (!leftTrackArcRect.isEmpty) + context.canvas.drawArc(leftTrackArcRect, math.pi / 2, math.pi, false, leftTrackPaint); + final Rect rightTrackArcRect = Rect.fromLTWH(trackRect.right - trackRect.height / 2, trackRect.top, trackRect.height, trackRect.height); + if (!rightTrackArcRect.isEmpty) + context.canvas.drawArc(rightTrackArcRect, -math.pi / 2, math.pi, false, rightTrackPaint); - final Size thumbSize = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete); - final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx - thumbSize.width / 2, trackRect.bottom); - if (!leftTrackSegment.isEmpty) - context.canvas.drawRect(leftTrackSegment, leftTrackPaint); - final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + thumbSize.width / 2, trackRect.top, trackRect.right, trackRect.bottom); - if (!rightTrackSegment.isEmpty) - context.canvas.drawRect(rightTrackSegment, rightTrackPaint); - } + final Size thumbSize = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete); + final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx - thumbSize.width / 2, trackRect.bottom); + if (!leftTrackSegment.isEmpty) + context.canvas.drawRect(leftTrackSegment, leftTrackPaint); + final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + thumbSize.width / 2, trackRect.top, trackRect.right, trackRect.bottom); + if (!rightTrackSegment.isEmpty) + context.canvas.drawRect(rightTrackSegment, rightTrackPaint); } } @@ -1806,10 +1726,7 @@ class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { /// /// The middle track segment is the selected range and is active, and the two /// outer track segments are inactive. - const RectangularRangeSliderTrackShape({this.useV2Slider}); - - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; + const RectangularRangeSliderTrackShape(); @override Rect getPreferredRect({ @@ -1868,8 +1785,8 @@ class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { assert(textDirection != null); // Assign the track segment paints, which are left: active, right: inactive, // but reversed for right to left text. - final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor, end: sliderTheme.activeTrackColor); - final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor, end: sliderTheme.inactiveTrackColor); + final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor , end: sliderTheme.activeTrackColor); + final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor , end: sliderTheme.inactiveTrackColor); final Paint activePaint = Paint()..color = activeTrackColorTween.evaluate(enableAnimation); final Paint inactivePaint = Paint()..color = inactiveTrackColorTween.evaluate(enableAnimation); @@ -1935,10 +1852,7 @@ class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { /// /// The middle track segment is the selected range and is active, and the two /// outer track segments are inactive. - const RoundedRectRangeSliderTrackShape({ this.useV2Slider }); - - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; + const RoundedRectRangeSliderTrackShape(); @override Rect getPreferredRect({ @@ -1980,7 +1894,6 @@ class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { bool isEnabled = false, bool isDiscrete = false, @required TextDirection textDirection, - double additionalActiveTrackHeight = 2, }) { assert(context != null); assert(offset != null); @@ -1997,23 +1910,12 @@ class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { assert(isEnabled != null); assert(isDiscrete != null); assert(textDirection != null); - - if (sliderTheme.trackHeight <= 0) { - return; - } - // Assign the track segment paints, which are left: active, right: inactive, // but reversed for right to left text. - final ColorTween activeTrackColorTween = ColorTween( - begin: sliderTheme.disabledActiveTrackColor, - end: sliderTheme.activeTrackColor); - final ColorTween inactiveTrackColorTween = ColorTween( - begin: sliderTheme.disabledInactiveTrackColor, - end: sliderTheme.inactiveTrackColor); - final Paint activePaint = Paint() - ..color = activeTrackColorTween.evaluate(enableAnimation); - final Paint inactivePaint = Paint() - ..color = inactiveTrackColorTween.evaluate(enableAnimation); + final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor , end: sliderTheme.activeTrackColor); + final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor , end: sliderTheme.inactiveTrackColor); + final Paint activePaint = Paint()..color = activeTrackColorTween.evaluate(enableAnimation); + final Paint inactivePaint = Paint()..color = inactiveTrackColorTween.evaluate(enableAnimation); Offset leftThumbOffset; Offset rightThumbOffset; @@ -2038,62 +1940,25 @@ class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { isEnabled: isEnabled, isDiscrete: isDiscrete, ); + final double trackRadius = trackRect.height / 2; - if (useV2Slider) { - final Radius trackRadius = Radius.circular(trackRect.height / 2); + final Rect leftTrackArcRect = Rect.fromLTWH(trackRect.left, trackRect.top, trackRect.height, trackRect.height); + if (!leftTrackArcRect.isEmpty) + context.canvas.drawArc(leftTrackArcRect, math.pi / 2, math.pi, false, inactivePaint); - context.canvas.drawRRect( - RRect.fromLTRBAndCorners( - trackRect.left, - trackRect.top, - leftThumbOffset.dx, - trackRect.bottom, - topLeft: trackRadius, - bottomLeft: trackRadius, - ), - inactivePaint, - ); - context.canvas.drawRect( - Rect.fromLTRB( - leftThumbOffset.dx, - trackRect.top - (additionalActiveTrackHeight / 2), - rightThumbOffset.dx, - trackRect.bottom + (additionalActiveTrackHeight / 2), - ), - activePaint, - ); - context.canvas.drawRRect( - RRect.fromLTRBAndCorners( - rightThumbOffset.dx, - trackRect.top, - trackRect.right, - trackRect.bottom, - topRight: trackRadius, - bottomRight: trackRadius, - ), - inactivePaint, - ); - } else { - final double trackRadius = trackRect.height / 2; + final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRadius, trackRect.top, leftThumbOffset.dx - thumbRadius, trackRect.bottom); + if (!leftTrackSegment.isEmpty) + context.canvas.drawRect(leftTrackSegment, inactivePaint); + final Rect middleTrackSegment = Rect.fromLTRB(leftThumbOffset.dx + thumbRadius, trackRect.top, rightThumbOffset.dx - thumbRadius, trackRect.bottom); + if (!middleTrackSegment.isEmpty) + context.canvas.drawRect(middleTrackSegment, activePaint); + final Rect rightTrackSegment = Rect.fromLTRB(rightThumbOffset.dx + thumbRadius, trackRect.top, trackRect.right - trackRadius, trackRect.bottom); + if (!rightTrackSegment.isEmpty) + context.canvas.drawRect(rightTrackSegment, inactivePaint); - final Rect leftTrackArcRect = Rect.fromLTWH(trackRect.left, trackRect.top, trackRect.height, trackRect.height); - if (!leftTrackArcRect.isEmpty) - context.canvas.drawArc(leftTrackArcRect, math.pi / 2, math.pi, false, inactivePaint); - - final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRadius, trackRect.top, leftThumbOffset.dx - thumbRadius, trackRect.bottom); - if (!leftTrackSegment.isEmpty) - context.canvas.drawRect(leftTrackSegment, inactivePaint); - final Rect middleTrackSegment = Rect.fromLTRB(leftThumbOffset.dx + thumbRadius, trackRect.top, rightThumbOffset.dx - thumbRadius, trackRect.bottom); - if (!middleTrackSegment.isEmpty) - context.canvas.drawRect(middleTrackSegment, activePaint); - final Rect rightTrackSegment = Rect.fromLTRB(rightThumbOffset.dx + thumbRadius, trackRect.top, trackRect.right - trackRadius, trackRect.bottom); - if (!rightTrackSegment.isEmpty) - context.canvas.drawRect(rightTrackSegment, inactivePaint); - - final Rect rightTrackArcRect = Rect.fromLTWH(trackRect.right - trackRect.height, trackRect.top, trackRect.height, trackRect.height); - if (!rightTrackArcRect.isEmpty) - context.canvas.drawArc(rightTrackArcRect, -math.pi / 2, math.pi, false, inactivePaint); - } + final Rect rightTrackArcRect = Rect.fromLTWH(trackRect.right - trackRect.height, trackRect.top, trackRect.height, trackRect.height); + if (!rightTrackArcRect.isEmpty) + context.canvas.drawArc(rightTrackArcRect, -math.pi / 2, math.pi, false, inactivePaint); } } @@ -2117,21 +1982,13 @@ class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { /// sliders in a widget subtree. class RoundSliderTickMarkShape extends SliderTickMarkShape { /// Create a slider tick mark that draws a circle. - const RoundSliderTickMarkShape({ - this.tickMarkRadius, - this.useV2Slider = false, - }); + const RoundSliderTickMarkShape({ this.tickMarkRadius }); /// The preferred radius of the round tick mark. /// - /// If it is not provided, and [useV2Slider] is true, then 1/4 of the - /// [SliderThemeData.trackHeight] is used. If it is not provided, and - /// [useV2Slider] is false, then half of the track height is used. + /// If it is not provided, then half of the track height is used. final double tickMarkRadius; - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; - @override Size getPreferredSize({ @required SliderThemeData sliderTheme, @@ -2140,11 +1997,9 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape { assert(sliderTheme != null); assert(sliderTheme.trackHeight != null); assert(isEnabled != null); - // The tick marks are tiny circles. If no radius is provided, then the - // radius is defaulted to be a fraction of the - // [SliderThemeData.trackHeight]. The fraction is 1/4 when [useV2Slider] is - // true, and 1/2 when it is false. - return Size.fromRadius(tickMarkRadius ?? sliderTheme.trackHeight / (useV2Slider ? 4 : 2)); + // The tick marks are tiny circles. If no radius is provided, then they are + // defaulted to be the same height as the track. + return Size.fromRadius(tickMarkRadius ?? sliderTheme.trackHeight / 2); } @override @@ -2190,9 +2045,9 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape { // The tick marks are tiny circles that are the same height as the track. final double tickMarkRadius = getPreferredSize( - isEnabled: isEnabled, - sliderTheme: sliderTheme, - ).width / 2; + isEnabled: isEnabled, + sliderTheme: sliderTheme, + ).width / 2; if (tickMarkRadius > 0) { context.canvas.drawCircle(center, tickMarkRadius, paint); } @@ -2219,21 +2074,13 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape { /// sliders in a widget subtree. class RoundRangeSliderTickMarkShape extends RangeSliderTickMarkShape { /// Create a range slider tick mark that draws a circle. - const RoundRangeSliderTickMarkShape({ - this.tickMarkRadius, - this.useV2Slider = false, - }); + const RoundRangeSliderTickMarkShape({ this.tickMarkRadius }); /// The preferred radius of the round tick mark. /// - /// If it is not provided, and [useV2Slider] is true, then 1/4 of the - /// [SliderThemeData.trackHeight] is used. If it is not provided, and - /// [useV2Slider] is false, then half of the track height is used. + /// If it is not provided, then half of the track height is used. final double tickMarkRadius; - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; - @override Size getPreferredSize({ @required SliderThemeData sliderTheme, @@ -2242,7 +2089,7 @@ class RoundRangeSliderTickMarkShape extends RangeSliderTickMarkShape { assert(sliderTheme != null); assert(sliderTheme.trackHeight != null); assert(isEnabled != null); - return Size.fromRadius(tickMarkRadius ?? sliderTheme.trackHeight / (useV2Slider ? 4 : 2)); + return Size.fromRadius(tickMarkRadius ?? sliderTheme.trackHeight / 2); } @override @@ -2351,8 +2198,6 @@ class _EmptySliderComponentShape extends SliderComponentShape { SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { // no-op. } @@ -2360,9 +2205,6 @@ class _EmptySliderComponentShape extends SliderComponentShape { /// The default shape of a [Slider]'s thumb. /// -/// If [useV2Slider] is true, then there is a shadow for the resting and -/// pressed state. -/// /// See also: /// /// * [Slider], which includes a thumb defined by this shape. @@ -2373,9 +2215,6 @@ class RoundSliderThumbShape extends SliderComponentShape { const RoundSliderThumbShape({ this.enabledThumbRadius = 10.0, this.disabledThumbRadius, - this.elevation = 1.0, - this.pressedElevation = 6.0, - this.useV2Slider = false, }); /// The preferred radius of the round thumb shape when the slider is enabled. @@ -2388,31 +2227,7 @@ class RoundSliderThumbShape extends SliderComponentShape { /// If no disabledRadius is provided, then it is equal to the /// [enabledThumbRadius] final double disabledThumbRadius; - double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius; - - /// The resting elevation adds shadow to the unpressed thumb. - /// - /// This value is only used when [useV2Slider] is true. - /// - /// The default is 1. - /// - /// Use 0 for no shadow. The higher the value, the larger the shadow. For - /// example, a value of 12 will create a very large shadow. - /// - final double elevation; - - /// The pressed elevation adds shadow to the pressed thumb. - /// - /// This value is only used when [useV2Slider] is true. - /// - /// The default is 6. - /// - /// Use 0 for no shadow. The higher the value, the larger the shadow. For - /// example, a value of 12 will create a very large shadow. - final double pressedElevation; - - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; + double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius; @override Size getPreferredSize(bool isEnabled, bool isDiscrete) { @@ -2431,8 +2246,6 @@ class RoundSliderThumbShape extends SliderComponentShape { @required SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { assert(context != null); assert(center != null); @@ -2440,7 +2253,6 @@ class RoundSliderThumbShape extends SliderComponentShape { assert(sliderTheme != null); assert(sliderTheme.disabledThumbColor != null); assert(sliderTheme.thumbColor != null); - assert(!sizeWithOverflow.isEmpty); final Canvas canvas = context.canvas; final Tween radiusTween = Tween( @@ -2451,35 +2263,16 @@ class RoundSliderThumbShape extends SliderComponentShape { begin: sliderTheme.disabledThumbColor, end: sliderTheme.thumbColor, ); - - final Color color = colorTween.evaluate(enableAnimation); - final double radius = radiusTween.evaluate(enableAnimation); - - if (useV2Slider) { - final Tween elevationTween = Tween( - begin: elevation, - end: pressedElevation, - ); - - final double evaluatedElevation = elevationTween.evaluate(activationAnimation); - final Path path = Path() - ..addArc(Rect.fromCenter(center: center, width: 2 * radius, height: 2 * radius), 0, math.pi * 2); - canvas.drawShadow(path, Colors.black, evaluatedElevation, true); - } - canvas.drawCircle( center, - radius, - Paint()..color = color, + radiusTween.evaluate(enableAnimation), + Paint()..color = colorTween.evaluate(enableAnimation), ); } } /// The default shape of a [RangeSlider]'s thumbs. /// -/// If [useV2Slider] is true, then there is a shadow for the resting and -/// pressed state. -/// /// See also: /// /// * [RangeSlider], which includes thumbs defined by this shape. @@ -2490,14 +2283,8 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { const RoundRangeSliderThumbShape({ this.enabledThumbRadius = 10.0, this.disabledThumbRadius, - this.elevation = 1.0, - this.pressedElevation = 6.0, - this.useV2Slider = false, }) : assert(enabledThumbRadius != null); - /// {@macro flutter.material.slider.useV2Slider} - final bool useV2Slider; - /// The preferred radius of the round thumb shape when the slider is enabled. /// /// If it is not provided, then the material default of 10 is used. @@ -2508,17 +2295,7 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { /// If no disabledRadius is provided, then it is equal to the /// [enabledThumbRadius]. final double disabledThumbRadius; - double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius; - - /// The resting elevation adds shadow to the unpressed thumb. - /// - /// The default is 1. - final double elevation; - - /// The pressed elevation adds shadow to the pressed thumb. - /// - /// The default is 6. - final double pressedElevation; + double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius; @override Size getPreferredSize(bool isEnabled, bool isDiscrete) { @@ -2537,7 +2314,6 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { @required SliderThemeData sliderTheme, TextDirection textDirection, Thumb thumb, - bool isPressed, }) { assert(context != null); assert(center != null); @@ -2556,10 +2332,6 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { end: sliderTheme.thumbColor, ); final double radius = radiusTween.evaluate(enableAnimation); - final Tween elevationTween = Tween( - begin: elevation, - end: pressedElevation, - ); // Add a stroke of 1dp around the circle if this thumb would overlap // the other thumb. @@ -2589,19 +2361,10 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { } } - final Color color = colorTween.evaluate(enableAnimation); - - if (useV2Slider) { - final double evaluatedElevation = isPressed ? elevationTween.evaluate(activationAnimation) : elevation; - final Path shadowPath = Path() - ..addArc(Rect.fromCenter(center: center, width: 2 * radius, height: 2 * radius), 0, math.pi * 2); - canvas.drawShadow(shadowPath, Colors.black, evaluatedElevation, true); - } - canvas.drawCircle( center, radius, - Paint()..color = color, + Paint()..color = colorTween.evaluate(enableAnimation), ); } } @@ -2627,8 +2390,7 @@ class RoundSliderOverlayShape extends SliderComponentShape { /// The preferred radius of the round thumb shape when enabled. /// - /// If it is not provided, then half of the [SliderThemeData.trackHeight] is - /// used. + /// If it is not provided, then half of the track height is used. final double overlayRadius; @override @@ -2648,8 +2410,6 @@ class RoundSliderOverlayShape extends SliderComponentShape { @required SliderThemeData sliderTheme, @required TextDirection textDirection, @required double value, - double textScaleFactor, - Size sizeWithOverflow, }) { assert(context != null); assert(center != null); @@ -2682,22 +2442,16 @@ class RoundSliderOverlayShape extends SliderComponentShape { /// * [Slider], which includes a value indicator defined by this shape. /// * [SliderTheme], which can be used to configure the slider value indicator /// of all sliders in a widget subtree. -class RectangularSliderValueIndicatorShape extends SliderComponentShape { - /// Create a slider value indicator that resembles a rectangular tooltip. - const RectangularSliderValueIndicatorShape(); +class PaddleSliderValueIndicatorShape extends SliderComponentShape { + /// Create a slider value indicator in the shape of an upside-down pear. + const PaddleSliderValueIndicatorShape(); - static const _RectangularSliderValueIndicatorPathPainter _pathPainter = _RectangularSliderValueIndicatorPathPainter(); + static const _PaddleSliderTrackShapePathPainter _pathPainter = _PaddleSliderTrackShapePathPainter(); @override - Size getPreferredSize( - bool isEnabled, - bool isDiscrete, { - @required TextPainter labelPainter, - @required double textScaleFactor, - }) { - assert(labelPainter != null); - assert(textScaleFactor != null && textScaleFactor >= 0); - return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter, textScaleFactor); + Size getPreferredSize(bool isEnabled, bool isDiscrete, { @required TextPainter labelPainter }) { + assert(labelPainter != null); + return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter); } @override @@ -2712,20 +2466,27 @@ class RectangularSliderValueIndicatorShape extends SliderComponentShape { @required SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { - final Canvas canvas = context.canvas; - final double scale = activationAnimation.value; - _pathPainter.paint( - parentBox: parentBox, - canvas: canvas, - center: center, - scale: scale, - labelPainter: labelPainter, - textScaleFactor: textScaleFactor, - sizeWithOverflow: sizeWithOverflow, - backgroundPaintColor: sliderTheme.valueIndicatorColor); + assert(context != null); + assert(center != null); + assert(activationAnimation != null); + assert(enableAnimation != null); + assert(labelPainter != null); + assert(parentBox != null); + assert(sliderTheme != null); + final ColorTween enableColor = ColorTween( + begin: sliderTheme.disabledThumbColor, + end: sliderTheme.valueIndicatorColor, + ); + _pathPainter.drawValueIndicator( + parentBox, + context.canvas, + center, + Paint()..color = enableColor.evaluate(enableAnimation), + activationAnimation.value, + labelPainter, + null, + ); } } @@ -2736,288 +2497,16 @@ class RectangularSliderValueIndicatorShape extends SliderComponentShape { /// * [RangeSlider], which includes value indicators defined by this shape. /// * [SliderTheme], which can be used to configure the range slider value /// indicator of all sliders in a widget subtree. -class RectangularRangeSliderValueIndicatorShape - extends RangeSliderValueIndicatorShape { - /// Create a range slider value indicator that resembles a rectangular tooltip. - const RectangularRangeSliderValueIndicatorShape(); - - static const _RectangularSliderValueIndicatorPathPainter _pathPainter = _RectangularSliderValueIndicatorPathPainter(); - - @override - Size getPreferredSize( - bool isEnabled, - bool isDiscrete, { - @required TextPainter labelPainter, - @required double textScaleFactor, - }) { - assert(labelPainter != null); - assert(textScaleFactor != null && textScaleFactor >= 0); - return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter, textScaleFactor); - } - - @override - double getHorizontalShift({ - RenderBox parentBox, - Offset center, - TextPainter labelPainter, - Animation activationAnimation, - double textScaleFactor, - Size sizeWithOverflow, - }) { - return _pathPainter.getHorizontalShift( - parentBox: parentBox, - center: center, - labelPainter: labelPainter, - textScaleFactor: textScaleFactor, - sizeWithOverflow: sizeWithOverflow, - scale: activationAnimation.value, - ); - } - - @override - void paint( - PaintingContext context, - Offset center, { - Animation activationAnimation, - Animation enableAnimation, - bool isDiscrete, - bool isOnTop, - TextPainter labelPainter, - double textScaleFactor, - Size sizeWithOverflow, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, - Thumb thumb, - }) { - final Canvas canvas = context.canvas; - final double scale = activationAnimation.value; - _pathPainter.paint( - parentBox: parentBox, - canvas: canvas, - center: center, - scale: scale, - labelPainter: labelPainter, - textScaleFactor: textScaleFactor, - sizeWithOverflow: sizeWithOverflow, - backgroundPaintColor: sliderTheme.valueIndicatorColor, - strokePaintColor: isOnTop ? sliderTheme.overlappingShapeStrokeColor : null, - ); - } -} - -class _RectangularSliderValueIndicatorPathPainter { - const _RectangularSliderValueIndicatorPathPainter(); - - static const double _triangleHeight = 8.0; - static const double _labelPadding = 16.0; - static const double _preferredHeight = 32.0; - static const double _minLabelWidth = 16.0; - static const double _bottomTipYOffset = 14.0; - static const double _preferredHalfHeight = _preferredHeight / 2; - static const double _upperRectRadius = 4; - - Size getPreferredSize( - bool isEnabled, - bool isDiscrete, - TextPainter labelPainter, - double textScaleFactor, - ) { - assert(labelPainter != null); - return Size( - _upperRectangleWidth(labelPainter, 1, textScaleFactor), - labelPainter.height + _labelPadding, - ); - } - - double getHorizontalShift({ - RenderBox parentBox, - Offset center, - TextPainter labelPainter, - double textScaleFactor, - Size sizeWithOverflow, - double scale, - }) { - assert(!sizeWithOverflow.isEmpty); - const double edgePadding = 8.0; - final double rectangleWidth = _upperRectangleWidth(labelPainter, scale, textScaleFactor); - - // The rectangle must be shifted towards the center so that it minimizes the - // chance of it rendering outside the bounds of the render box. If the shift - // is negative, then the lobe is shifted from right to left, and if it is - // positive, then the lobe is shifted from left to right. - final double overflowLeft = math.max(0, rectangleWidth / 2 - center.dx + edgePadding); - final double overflowRight = math.max(0, rectangleWidth / 2 - (sizeWithOverflow.width - center.dx - edgePadding)); - - if (rectangleWidth < sizeWithOverflow.width) { - return overflowLeft - overflowRight; - } else if (overflowLeft - overflowRight > 0) { - return overflowLeft - (edgePadding * textScaleFactor); - } else { - return -overflowRight + (edgePadding * textScaleFactor); - } - } - - double _upperRectangleWidth(TextPainter labelPainter, double scale, double textScaleFactor) { - final double unscaledWidth = math.max(_minLabelWidth * textScaleFactor, labelPainter.width) + _labelPadding * 2; - return unscaledWidth * scale; - } - - void paint({ - RenderBox parentBox, - Canvas canvas, - Offset center, - double scale, - TextPainter labelPainter, - double textScaleFactor, - Size sizeWithOverflow, - Color backgroundPaintColor, - Color strokePaintColor, - }) { - if (scale == 0.0) { - // Zero scale essentially means "do not draw anything", so it's safe to just return. - return; - } - assert(!sizeWithOverflow.isEmpty); - - final double rectangleWidth = _upperRectangleWidth(labelPainter, scale, textScaleFactor); - final double horizontalShift = getHorizontalShift( - parentBox: parentBox, - center: center, - labelPainter: labelPainter, - textScaleFactor: textScaleFactor, - sizeWithOverflow: sizeWithOverflow, - scale: scale, - ); - - final double rectHeight = labelPainter.height + _labelPadding; - final Rect upperRect = Rect.fromLTWH( - -rectangleWidth / 2 + horizontalShift, - -_triangleHeight - rectHeight, - rectangleWidth, - rectHeight, - ); - - final Path trianglePath = Path() - ..lineTo(-_triangleHeight, -_triangleHeight) - ..lineTo(_triangleHeight, -_triangleHeight) - ..close(); - final Paint fillPaint = Paint()..color = backgroundPaintColor; - final RRect upperRRect = RRect.fromRectAndRadius(upperRect, const Radius.circular(_upperRectRadius)); - trianglePath.addRRect(upperRRect); - - canvas.save(); - // Prepare the canvas for the base of the tooltip, which is relative to the - // center of the thumb. - canvas.translate(center.dx, center.dy - _bottomTipYOffset); - canvas.scale(scale, scale); - if (strokePaintColor != null) { - final Paint strokePaint = Paint() - ..color = strokePaintColor - ..strokeWidth = 1.0 - ..style = PaintingStyle.stroke; - canvas.drawPath(trianglePath, strokePaint); - } - canvas.drawPath(trianglePath, fillPaint); - - // The label text is centered within the value indicator. - final double bottomTipToUpperRectTranslateY = -_preferredHalfHeight / 2 - upperRect.height; - canvas.translate(0, bottomTipToUpperRectTranslateY); - final Offset boxCenter = Offset(horizontalShift, upperRect.height / 2); - final Offset halfLabelPainterOffset = Offset(labelPainter.width / 2, labelPainter.height / 2); - final Offset labelOffset = boxCenter - halfLabelPainterOffset; - labelPainter.paint(canvas, labelOffset); - canvas.restore(); - } -} - -/// A variant shape of a [Slider]'s value indicator . The value indicator is in -/// the shape of an upside-down pear. -/// -/// See also: -/// -/// * [Slider], which includes a value indicator defined by this shape. -/// * [SliderTheme], which can be used to configure the slider value indicator -/// of all sliders in a widget subtree. -class PaddleSliderValueIndicatorShape extends SliderComponentShape { - /// Create a slider value indicator in the shape of an upside-down pear. - const PaddleSliderValueIndicatorShape(); - - static const _PaddleSliderValueIndicatorPathPainter _pathPainter = _PaddleSliderValueIndicatorPathPainter(); - - @override - Size getPreferredSize(bool isEnabled, bool isDiscrete, {@required TextPainter labelPainter, @required double textScaleFactor,}) { - assert(labelPainter != null); - assert(textScaleFactor != null && textScaleFactor >= 0); - return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter, textScaleFactor); - } - - @override - void paint( - PaintingContext context, - Offset center, { - @required Animation activationAnimation, - @required Animation enableAnimation, - bool isDiscrete, - @required TextPainter labelPainter, - @required RenderBox parentBox, - @required SliderThemeData sliderTheme, - TextDirection textDirection, - double value, - double textScaleFactor, - Size sizeWithOverflow, - }) { - assert(context != null); - assert(center != null); - assert(activationAnimation != null); - assert(enableAnimation != null); - assert(labelPainter != null); - assert(parentBox != null); - assert(sliderTheme != null); - assert(!sizeWithOverflow.isEmpty); - final ColorTween enableColor = ColorTween( - begin: sliderTheme.disabledThumbColor, - end: sliderTheme.valueIndicatorColor, - ); - _pathPainter.paint( - parentBox, - context.canvas, - center, - Paint()..color = enableColor.evaluate(enableAnimation), - activationAnimation.value, - labelPainter, - textScaleFactor, - sizeWithOverflow, - null, - ); - } -} - -/// A variant shape of a [RangeSlider]'s value indicators. The value indicator -/// is in the shape of an upside-down pear. -/// -/// See also: -/// -/// * [RangeSlider], which includes value indicators defined by this shape. -/// * [SliderTheme], which can be used to configure the range slider value -/// indicator of all sliders in a widget subtree. class PaddleRangeSliderValueIndicatorShape extends RangeSliderValueIndicatorShape { /// Create a slider value indicator in the shape of an upside-down pear. const PaddleRangeSliderValueIndicatorShape(); - static const _PaddleSliderValueIndicatorPathPainter _pathPainter = _PaddleSliderValueIndicatorPathPainter(); + static const _PaddleSliderTrackShapePathPainter _pathPainter = _PaddleSliderTrackShapePathPainter(); @override - Size getPreferredSize( - bool isEnabled, - bool isDiscrete, { - @required TextPainter labelPainter, - @required double textScaleFactor, - }) { + Size getPreferredSize(bool isEnabled, bool isDiscrete, { @required TextPainter labelPainter }) { assert(labelPainter != null); - assert(textScaleFactor != null && textScaleFactor >= 0); - return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter, textScaleFactor); + return _pathPainter.getPreferredSize(isEnabled, isDiscrete, labelPainter); } @override @@ -3026,16 +2515,12 @@ class PaddleRangeSliderValueIndicatorShape extends RangeSliderValueIndicatorShap Offset center, TextPainter labelPainter, Animation activationAnimation, - double textScaleFactor, - Size sizeWithOverflow, }) { return _pathPainter.getHorizontalShift( parentBox: parentBox, center: center, labelPainter: labelPainter, scale: activationAnimation.value, - textScaleFactor: textScaleFactor, - sizeWithOverflow: sizeWithOverflow, ); } @@ -3053,8 +2538,6 @@ class PaddleRangeSliderValueIndicatorShape extends RangeSliderValueIndicatorShap TextDirection textDirection, Thumb thumb, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { assert(context != null); assert(center != null); @@ -3063,28 +2546,25 @@ class PaddleRangeSliderValueIndicatorShape extends RangeSliderValueIndicatorShap assert(labelPainter != null); assert(parentBox != null); assert(sliderTheme != null); - assert(!sizeWithOverflow.isEmpty); final ColorTween enableColor = ColorTween( begin: sliderTheme.disabledThumbColor, end: sliderTheme.valueIndicatorColor, ); // Add a stroke of 1dp around the top paddle. - _pathPainter.paint( + _pathPainter.drawValueIndicator( parentBox, context.canvas, center, Paint()..color = enableColor.evaluate(enableAnimation), activationAnimation.value, labelPainter, - textScaleFactor, - sizeWithOverflow, isOnTop ? sliderTheme.overlappingShapeStrokeColor : null, ); } } -class _PaddleSliderValueIndicatorPathPainter { - const _PaddleSliderValueIndicatorPathPainter(); +class _PaddleSliderTrackShapePathPainter { + const _PaddleSliderTrackShapePathPainter(); // These constants define the shape of the default value indicator. // The value indicator changes shape based on the size of @@ -3094,12 +2574,14 @@ class _PaddleSliderValueIndicatorPathPainter { // Radius of the top lobe of the value indicator. static const double _topLobeRadius = 16.0; - static const double _minLabelWidth = 16.0; + // Designed size of the label text. This is the size that the value indicator + // was designed to contain. We scale it from here to fit other sizes. + static const double _labelTextDesignSize = 14.0; // Radius of the bottom lobe of the value indicator. static const double _bottomLobeRadius = 10.0; static const double _labelPadding = 8.0; static const double _distanceBetweenTopBottomCenters = 40.0; - static const double _middleNeckWidth = 3.0; + static const double _middleNeckWidth = 2.0; static const double _bottomNeckRadius = 4.5; // The base of the triangle between the top lobe center and the centers of // the two top neck arcs. @@ -3127,12 +2609,10 @@ class _PaddleSliderValueIndicatorPathPainter { bool isEnabled, bool isDiscrete, TextPainter labelPainter, - double textScaleFactor, ) { assert(labelPainter != null); - assert(textScaleFactor != null && textScaleFactor >= 0); - final double width = math.max(_minLabelWidth * textScaleFactor, labelPainter.width) + _labelPadding * 2 * textScaleFactor; - return Size(width, _preferredHeight * textScaleFactor); + final double textScaleFactor = labelPainter.height / _labelTextDesignSize; + return Size(labelPainter.width + 2 * _labelPadding * textScaleFactor, _preferredHeight * textScaleFactor); } // Adds an arc to the path that has the attributes passed in. This is @@ -3148,17 +2628,15 @@ class _PaddleSliderValueIndicatorPathPainter { Offset center, TextPainter labelPainter, double scale, - double textScaleFactor, - Size sizeWithOverflow, }) { - assert(!sizeWithOverflow.isEmpty); + final double textScaleFactor = labelPainter.height / _labelTextDesignSize; final double inverseTextScale = textScaleFactor != 0 ? 1.0 / textScaleFactor : 0.0; final double labelHalfWidth = labelPainter.width / 2.0; final double halfWidthNeeded = math.max( 0.0, inverseTextScale * labelHalfWidth - (_topLobeRadius - _labelPadding), ); - final double shift = _getIdealOffset(parentBox, halfWidthNeeded, textScaleFactor * scale, center, sizeWithOverflow.width); + final double shift = _getIdealOffset(parentBox, halfWidthNeeded, textScaleFactor * scale, center); return shift * textScaleFactor; } @@ -3169,9 +2647,8 @@ class _PaddleSliderValueIndicatorPathPainter { double halfWidthNeeded, double scale, Offset center, - double widthWithOverflow, ) { - const double edgeMargin = 8.0; + const double edgeMargin = 4.0; final Rect topLobeRect = Rect.fromLTWH( -_topLobeRadius - halfWidthNeeded, -_topLobeRadius - _distanceBetweenTopBottomCenters, @@ -3184,11 +2661,12 @@ class _PaddleSliderValueIndicatorPathPainter { final Offset bottomRight = (topLobeRect.bottomRight * scale) + center; double shift = 0.0; - if (topLeft.dx < edgeMargin) { - shift = edgeMargin - topLeft.dx; + final double startGlobal = parentBox.localToGlobal(Offset.zero).dx; + if (topLeft.dx < startGlobal + edgeMargin) { + shift = startGlobal + edgeMargin - topLeft.dx; } - final double endGlobal = widthWithOverflow; + final double endGlobal = parentBox.localToGlobal(Offset(parentBox.size.width, parentBox.size.height)).dx; if (bottomRight.dx > endGlobal - edgeMargin) { shift = endGlobal - edgeMargin - bottomRight.dx; } @@ -3204,15 +2682,13 @@ class _PaddleSliderValueIndicatorPathPainter { return shift; } - void paint( + void drawValueIndicator( RenderBox parentBox, Canvas canvas, Offset center, Paint paint, double scale, TextPainter labelPainter, - double textScaleFactor, - Size sizeWithOverflow, Color strokePaintColor, ) { if (scale == 0.0) { @@ -3220,10 +2696,10 @@ class _PaddleSliderValueIndicatorPathPainter { // our math below will attempt to divide by zero and send needless NaNs to the engine. return; } - assert(!sizeWithOverflow.isEmpty); // The entire value indicator should scale with the size of the label, // to keep it large enough to encompass the label text. + final double textScaleFactor = labelPainter.height / _labelTextDesignSize; final double overallScale = scale * textScaleFactor; final double inverseTextScale = textScaleFactor != 0 ? 1.0 / textScaleFactor : 0.0; final double labelHalfWidth = labelPainter.width / 2.0; @@ -3265,7 +2741,7 @@ class _PaddleSliderValueIndicatorPathPainter { inverseTextScale * labelHalfWidth - (_topLobeRadius - _labelPadding), ); - final double shift = _getIdealOffset(parentBox, halfWidthNeeded, overallScale, center, sizeWithOverflow.width); + final double shift = _getIdealOffset(parentBox, halfWidthNeeded, overallScale, center); final double leftWidthNeeded = halfWidthNeeded - shift; final double rightWidthNeeded = halfWidthNeeded + shift; @@ -3274,8 +2750,7 @@ class _PaddleSliderValueIndicatorPathPainter { final double leftAmount = math.max(0.0, math.min(1.0, leftWidthNeeded / _neckTriangleBase)); final double rightAmount = math.max(0.0, math.min(1.0, rightWidthNeeded / _neckTriangleBase)); // The angle between the top neck arc's center and the top lobe's center - // and vertical. The base amount is chosen so that the neck is smooth, - // even when the lobe is shifted due to its size. + // and vertical. final double leftTheta = (1.0 - leftAmount) * _thirtyDegrees; final double rightTheta = (1.0 - rightAmount) * _thirtyDegrees; // The center of the top left neck arc. diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 2d579a50cab..22ebb25132d 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -17,28 +17,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -46,7 +44,7 @@ void main() { // No thumbs get select when tapping between the thumbs outside the touch // boundaries expect(values, equals(const RangeValues(0.3, 0.7))); - // taps at 0.5 + // taps at 0.5 await tester.tap(find.byType(RangeSlider)); await tester.pump(); expect(values, equals(const RangeValues(0.3, 0.7))); @@ -74,28 +72,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -131,31 +127,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0.0, - max: 100.0, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0.0, + max: 100.0, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -193,31 +187,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -255,28 +247,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -302,28 +292,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -349,31 +337,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -399,31 +385,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -449,28 +433,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -502,28 +484,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -555,31 +535,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -611,31 +589,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -667,28 +643,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -720,28 +694,26 @@ void main() { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -773,31 +745,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -829,31 +799,29 @@ void main() { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - divisions: 10, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + divisions: 10, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -887,36 +855,34 @@ void main() { RangeValues endValues; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - onChangeStart: (RangeValues newValues) { - startValues = newValues; - }, - onChangeEnd: (RangeValues newValues) { - endValues = newValues; - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, + onChangeStart: (RangeValues newValues) { + startValues = newValues; + }, + onChangeEnd: (RangeValues newValues) { + endValues = newValues; + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -945,36 +911,34 @@ void main() { RangeValues endValues; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: RangeSlider( - values: values, - min: 0, - max: 100, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - onChangeStart: (RangeValues newValues) { - startValues = newValues; - }, - onChangeEnd: (RangeValues newValues) { - endValues = newValues; - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: RangeSlider( + values: values, + min: 0, + max: 100, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, + onChangeStart: (RangeValues newValues) { + startValues = newValues; + }, + onChangeEnd: (RangeValues newValues) { + endValues = newValues; + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -1031,30 +995,26 @@ void main() { Color inactiveColor, int divisions, bool enabled = true, - bool useV2Slider = false, }) { RangeValues values = const RangeValues(0.5, 0.75); final ValueChanged onChanged = !enabled ? null : (RangeValues newValues) { values = newValues; }; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, - useV2Slider: useV2Slider, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: theme, + child: RangeSlider( + values: values, + labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), + divisions: divisions, + activeColor: activeColor, + inactiveColor: inactiveColor, + onChanged: onChanged, ), ), ), @@ -1063,31 +1023,6 @@ void main() { ); } - testWidgets('Range Slider V2 uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp(theme: theme, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - // Check default theme for enabled widget. - expect(sliderBox, paints - ..rrect(color: sliderTheme.inactiveTrackColor) - ..rect(color: sliderTheme.activeTrackColor) - ..rrect(color: sliderTheme.inactiveTrackColor)); - expect(sliderBox, paints - ..circle(color: sliderTheme.thumbColor) - ..circle(color: sliderTheme.thumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = _buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1111,34 +1046,6 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { - const Color activeColor = Color(0xcafefeed); - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp(theme: theme, activeColor: activeColor, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.inactiveTrackColor) - ..rect(color: activeColor) - ..rrect(color: sliderTheme.inactiveTrackColor)); - expect( - sliderBox, - paints - ..circle(color: activeColor) - ..circle(color: activeColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = _buildTheme(); @@ -1165,33 +1072,6 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { - const Color inactiveColor = Color(0xdeadbeef); - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp(theme: theme, inactiveColor: inactiveColor, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: inactiveColor) - ..rect(color: sliderTheme.activeTrackColor) - ..rrect(color: inactiveColor)); - expect( - sliderBox, - paints - ..circle(color: sliderTheme.thumbColor) - ..circle(color: sliderTheme.thumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = _buildTheme(); @@ -1217,38 +1097,6 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { - const Color activeColor = Color(0xcafefeed); - const Color inactiveColor = Color(0xdeadbeef); - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp( - theme: theme, - activeColor: activeColor, - inactiveColor: inactiveColor, - useV2Slider: true, - )); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: inactiveColor) - ..rect(color: activeColor) - ..rrect(color: inactiveColor)); - expect( - sliderBox, - paints - ..circle(color: activeColor) - ..circle(color: activeColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); @@ -1280,36 +1128,6 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp(theme: theme, divisions: 3, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.inactiveTrackColor) - ..rect(color: sliderTheme.activeTrackColor) - ..rrect(color: sliderTheme.inactiveTrackColor)); - expect( - sliderBox, - paints - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.activeTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.thumbColor) - ..circle(color: sliderTheme.thumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = _buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1338,48 +1156,6 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { - const Color activeColor = Color(0xcafefeed); - const Color inactiveColor = Color(0xdeadbeef); - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - - await tester.pumpWidget(_buildThemedApp( - theme: theme, - activeColor: activeColor, - inactiveColor: inactiveColor, - divisions: 3, - useV2Slider: true, - )); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: inactiveColor) - ..rect(color: activeColor) - ..rrect(color: inactiveColor)); - expect( - sliderBox, - paints - ..circle(color: activeColor) - ..circle(color: activeColor) - ..circle(color: inactiveColor) - ..circle(color: activeColor) - ..circle(color: activeColor) - ..circle(color: activeColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); @@ -1419,27 +1195,6 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp(theme: theme, enabled: false, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.disabledInactiveTrackColor) - ..rect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = _buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1460,35 +1215,6 @@ void main() { }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { - const Color activeColor = Color(0xcafefeed); - const Color inactiveColor = Color(0xdeadbeef); - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildThemedApp( - theme: theme, - activeColor: activeColor, - inactiveColor: inactiveColor, - enabled: false, - useV2Slider: true, - )); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.disabledInactiveTrackColor) - ..rect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); @@ -1515,66 +1241,6 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgets('Range Slider V2 uses the right theme colors for the right shapes when the value indicators are showing', (WidgetTester tester) async { - final ThemeData theme = _buildTheme(); - final SliderThemeData sliderTheme = theme.sliderTheme; - RangeValues values = const RangeValues(0.5, 0.75); - - Widget buildApp({ - Color activeColor, - Color inactiveColor, - int divisions, - bool enabled = true, - }) { - final ValueChanged onChanged = !enabled ? null : (RangeValues newValues) { - values = newValues; - }; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, - useV2Slider: true, - ), - ), - ), - ), - ), - ), - ); - } - - await tester.pumpWidget(buildApp(divisions: 3)); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - final Offset topRight = tester.getTopRight(find.byType(RangeSlider)).translate(-24, 0); - final TestGesture gesture = await tester.startGesture(topRight); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect(values.end, equals(1)); - expect( - valueIndicatorBox, - paints - ..path(color: sliderTheme.valueIndicatorColor) - ..path(color: sliderTheme.valueIndicatorColor), - ); - await gesture.up(); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - }); - testWidgets('Range Slider uses the right theme colors for the right shapes when the value indicators are showing', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); @@ -1591,23 +1257,21 @@ void main() { final ValueChanged onChanged = !enabled ? null : (RangeValues newValues) { values = newValues; }; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: theme, + child: RangeSlider( + values: values, + labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), + divisions: divisions, + activeColor: activeColor, + inactiveColor: inactiveColor, + onChanged: onChanged, ), ), ), @@ -1618,7 +1282,7 @@ void main() { await tester.pumpWidget(buildApp(divisions: 3)); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); final Offset topRight = tester.getTopRight(find.byType(RangeSlider)).translate(-24, 0); TestGesture gesture = await tester.startGesture(topRight); @@ -1626,7 +1290,7 @@ void main() { await tester.pumpAndSettle(); expect(values.end, equals(1)); expect( - valueIndicatorBox, + sliderBox, paints ..path(color: sliderTheme.valueIndicatorColor) ..path(color: sliderTheme.valueIndicatorColor), @@ -1646,7 +1310,7 @@ void main() { await tester.pumpAndSettle(); expect(values.end, equals(1)); expect( - valueIndicatorBox, + sliderBox, paints ..path(color: customColor1) ..path(color: customColor1), @@ -1654,7 +1318,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider V2 top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1668,102 +1332,29 @@ void main() { final SliderThemeData sliderTheme = theme.sliderTheme; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - useV2Slider: true, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: theme, + child: RangeSlider( + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), ), - ); - }, - ), - ), - ), - ); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Get the bounds of the track by finding the slider edges and translating - // inwards by the overlay radius. - final Offset topLeft = tester.getTopLeft(find.byType(RangeSlider)).translate(24, 0); - final Offset bottomRight = tester.getBottomRight(find.byType(RangeSlider)).translate(-24, 0); - final Offset middle = topLeft + bottomRight / 2; - - // Drag the thumbs towards the center. - final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.3; - await tester.dragFrom(leftTarget, middle - leftTarget); - await tester.pumpAndSettle(); - final Offset rightTarget = topLeft + (bottomRight - topLeft) * 0.7; - await tester.dragFrom(rightTarget, middle - rightTarget); - expect(values.start, closeTo(0.5, 0.03)); - expect(values.end, closeTo(0.5, 0.03)); - await tester.pumpAndSettle(); - - expect( - valueIndicatorBox, - paints - ..circle(color: sliderTheme.thumbColor) - ..circle(color: sliderTheme.overlappingShapeStrokeColor) - ..circle(color: sliderTheme.thumbColor), - ); - }); - - testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { - RangeValues values = const RangeValues(0.3, 0.7); - - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - sliderTheme: const SliderThemeData( - thumbColor: Color(0xff000001), - overlappingShapeStrokeColor: Color(0xff000002), - ), - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), - ), - ), - ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -1795,7 +1386,7 @@ void main() { ); }); - testWidgets('Range Slider V2 top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1810,38 +1401,35 @@ void main() { final SliderThemeData sliderTheme = theme.sliderTheme; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - useV2Slider: true, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: theme, + child: RangeSlider( + values: values, + labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); // Get the bounds of the track by finding the slider edges and translating // inwards by the overlay radius. @@ -1862,7 +1450,7 @@ void main() { await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path(color: sliderTheme.valueIndicatorColor) ..path(color: sliderTheme.overlappingShapeStrokeColor) @@ -1872,83 +1460,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { - RangeValues values = const RangeValues(0.3, 0.7); - - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - sliderTheme: const SliderThemeData( - valueIndicatorColor: Color(0xff000001), - overlappingShapeStrokeColor: Color(0xff000002), - showValueIndicator: ShowValueIndicator.always, - ), - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), - ), - ), - ), - ); - }, - ), - ), - ), - ); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Get the bounds of the track by finding the slider edges and translating - // inwards by the overlay radius. - final Offset topLeft = tester.getTopLeft(find.byType(RangeSlider)).translate(24, 0); - final Offset bottomRight = tester.getBottomRight(find.byType(RangeSlider)).translate(-24, 0); - final Offset middle = topLeft + bottomRight / 2; - - // Drag the thumbs towards the center. - final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.3; - await tester.dragFrom(leftTarget, middle - leftTarget); - await tester.pumpAndSettle(); - final Offset rightTarget = topLeft + (bottomRight - topLeft) * 0.7; - await tester.dragFrom(rightTarget, middle - rightTarget); - await tester.pumpAndSettle(); - expect(values.start, closeTo(0.5, 0.03)); - expect(values.end, closeTo(0.5, 0.03)); - final TestGesture gesture = await tester.startGesture(middle); - await tester.pumpAndSettle(); - - expect( - valueIndicatorBox, - paints - ..path(color: sliderTheme.valueIndicatorColor) - ..path(color: sliderTheme.overlappingShapeStrokeColor) - ..path(color: sliderTheme.valueIndicatorColor), - ); - - await gesture.up(); - }); - - testWidgets('Range Slider V2 top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1963,38 +1475,35 @@ void main() { final SliderThemeData sliderTheme = theme.sliderTheme; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: 2.0), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - useV2Slider: true, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: 2.0), + child: Material( + child: Center( + child: Theme( + data: theme, + child: RangeSlider( + values: values, + labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); // Get the bounds of the track by finding the slider edges and translating // inwards by the overlay radius. @@ -2015,83 +1524,7 @@ void main() { await tester.pumpAndSettle(); expect( - valueIndicatorBox, - paints - ..path(color: sliderTheme.valueIndicatorColor) - ..path(color: sliderTheme.overlappingShapeStrokeColor) - ..path(color: sliderTheme.valueIndicatorColor), - ); - - await gesture.up(); - }); - - testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { - RangeValues values = const RangeValues(0.3, 0.7); - - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - sliderTheme: const SliderThemeData( - valueIndicatorColor: Color(0xff000001), - overlappingShapeStrokeColor: Color(0xff000002), - showValueIndicator: ShowValueIndicator.always, - ), - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: 2.0), - child: Material( - child: Center( - child: Theme( - data: theme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toStringAsFixed(2), values.end.toStringAsFixed(2)), - onChanged: (RangeValues newValues) { - setState(() { - values = newValues; - }); - }, - ), - ), - ), - ), - ); - }, - ), - ), - ), - ); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Get the bounds of the track by finding the slider edges and translating - // inwards by the overlay radius. - final Offset topLeft = tester.getTopLeft(find.byType(RangeSlider)).translate(24, 0); - final Offset bottomRight = tester.getBottomRight(find.byType(RangeSlider)).translate(-24, 0); - final Offset middle = topLeft + bottomRight / 2; - - // Drag the thumbs towards the center. - final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.3; - await tester.dragFrom(leftTarget, middle - leftTarget); - await tester.pumpAndSettle(); - final Offset rightTarget = topLeft + (bottomRight - topLeft) * 0.7; - await tester.dragFrom(rightTarget, middle - rightTarget); - await tester.pumpAndSettle(); - expect(values.start, closeTo(0.5, 0.03)); - expect(values.end, closeTo(0.5, 0.03)); - final TestGesture gesture = await tester.startGesture(middle); - await tester.pumpAndSettle(); - - expect( - valueIndicatorBox, + sliderBox, paints ..path(color: sliderTheme.valueIndicatorColor) ..path(color: sliderTheme.overlappingShapeStrokeColor) @@ -2132,8 +1565,7 @@ void main() { 'labelStart: "lowerValue"', 'labelEnd: "upperValue"', 'activeColor: MaterialColor(primary value: Color(0xff2196f3))', - 'inactiveColor: MaterialColor(primary value: Color(0xff9e9e9e))', - 'useV1Slider', + 'inactiveColor: MaterialColor(primary value: Color(0xff9e9e9e))' ]); }); } diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 3a81021bb33..3dd11ff2911 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -39,8 +39,6 @@ class LoggingThumbShape extends SliderComponentShape { SliderThemeData sliderTheme, TextDirection textDirection, double value, - double textScaleFactor, - Size sizeWithOverflow, }) { log.add(thumbCenter); final Paint thumbPaint = Paint()..color = Colors.red; @@ -78,35 +76,33 @@ void main() { double endValue; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - onChangeStart: (double value) { - startValue = value; - }, - onChangeEnd: (double value) { - endValue = value; - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, + onChangeStart: (double value) { + startValue = value; + }, + onChangeEnd: (double value) { + endValue = value; + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -138,29 +134,27 @@ void main() { double value = 0.0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -190,40 +184,37 @@ void main() { int startValueUpdates = 0; int endValueUpdates = 0; - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - onChanged: (double newValue) { - setState(() { - updates++; - value = newValue; - }); - }, - onChangeStart: (double value) { - startValueUpdates++; - startValue = value; - }, - onChangeEnd: (double value) { - endValueUpdates++; - endValue = value; - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + onChanged: (double newValue) { + setState(() { + updates++; + value = newValue; + }); + }, + onChangeStart: (double value) { + startValueUpdates++; + startValue = value; + }, + onChangeEnd: (double value) { + endValueUpdates++; + endValue = value; + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -247,30 +238,28 @@ void main() { double value = 0.0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + divisions: 4, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -301,34 +290,32 @@ void main() { final List log = []; final LoggingThumbShape loggingThumb = LoggingThumbShape(log); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(thumbShape: loggingThumb); - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: SliderTheme( - data: sliderTheme, - child: Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(thumbShape: loggingThumb); + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: SliderTheme( + data: sliderTheme, + child: Slider( + key: sliderKey, + value: value, + divisions: 4, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -372,30 +359,28 @@ void main() { int updates = 0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - onChanged: (double newValue) { - setState(() { - updates++; - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + onChanged: (double newValue) { + setState(() { + updates++; + value = newValue; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -416,34 +401,32 @@ void main() { final List log = []; final LoggingThumbShape loggingThumb = LoggingThumbShape(log); await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(thumbShape: loggingThumb); - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: SliderTheme( - data: sliderTheme, - child: Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(thumbShape: loggingThumb); + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: SliderTheme( + data: sliderTheme, + child: Slider( + key: sliderKey, + value: value, + divisions: 4, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -486,35 +469,33 @@ void main() { double value = 0.0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: SizedBox( - width: 144.0 + 2 * 16.0, // _kPreferredTotalWidth - child: Slider( - key: sliderKey, - min: 0.0, - max: 100.0, - divisions: 10, - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: SizedBox( + width: 144.0 + 2 * 16.0, // _kPreferredTotalWidth + child: Slider( + key: sliderKey, + min: 0.0, + max: 100.0, + divisions: 10, + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -539,58 +520,50 @@ void main() { testWidgets('Slider can be given zero values', (WidgetTester tester) async { final List log = []; - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Slider( - value: 0.0, - min: 0.0, - max: 1.0, - onChanged: (double newValue) { - log.add(newValue); - }, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Slider( + value: 0.0, + min: 0.0, + max: 1.0, + onChanged: (double newValue) { + log.add(newValue); + }, ), ), ), - ); + )); await tester.tap(find.byType(Slider)); expect(log, [0.5]); log.clear(); - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Slider( - value: 0.0, - min: 0.0, - max: 0.0, - onChanged: (double newValue) { - log.add(newValue); - }, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Slider( + value: 0.0, + min: 0.0, + max: 0.0, + onChanged: (double newValue) { + log.add(newValue); + }, ), ), ), - ); + )); await tester.tap(find.byType(Slider)); expect(log, []); log.clear(); }); - testWidgets('Slider V2 uses the right theme colors for the right components', (WidgetTester tester) async { + testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); final ThemeData theme = ThemeData( @@ -624,24 +597,21 @@ void main() { : (double d) { value = d; }; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: Slider( - value: value, - label: '$value', - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, - useV2Slider: true, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: theme, + child: Slider( + value: value, + label: '$value', + divisions: divisions, + activeColor: activeColor, + inactiveColor: inactiveColor, + onChanged: onChanged, ), ), ), @@ -653,228 +623,6 @@ void main() { await tester.pumpWidget(buildApp()); final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Check default theme for enabled widget. - expect(sliderBox, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); - expect(sliderBox, paints..shadow(color: const Color(0xff000000))); - expect(sliderBox, paints..circle(color: sliderTheme.thumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - - // Test setting only the activeColor. - await tester.pumpWidget(buildApp(activeColor: customColor1)); - expect(sliderBox, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)); - expect(sliderBox, paints..shadow(color: Colors.black)); - expect(sliderBox, paints..circle(color: customColor1)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test setting only the inactiveColor. - await tester.pumpWidget(buildApp(inactiveColor: customColor1)); - expect(sliderBox, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)); - expect(sliderBox, paints..shadow(color: Colors.black)); - expect(sliderBox, paints..circle(color: sliderTheme.thumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test setting both activeColor and inactiveColor. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2)); - expect(sliderBox, paints..rrect(color: customColor1)..rrect(color: customColor2)); - expect(sliderBox, paints..shadow(color: Colors.black)); - expect(sliderBox, paints..circle(color: customColor1)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test colors for discrete slider. - await tester.pumpWidget(buildApp(divisions: 3)); - expect(sliderBox, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); - expect( - sliderBox, - paints - ..circle(color: sliderTheme.activeTickMarkColor) - ..circle(color: sliderTheme.activeTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..shadow(color: Colors.black) - ..circle(color: sliderTheme.thumbColor) - ); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test colors for discrete slider with inactiveColor and activeColor set. - await tester.pumpWidget(buildApp( - activeColor: customColor1, - inactiveColor: customColor2, - divisions: 3, - )); - expect(sliderBox, paints..rrect(color: customColor1)..rrect(color: customColor2)); - expect( - sliderBox, - paints - ..circle(color: customColor2) - ..circle(color: customColor2) - ..circle(color: customColor1) - ..circle(color: customColor1) - ..shadow(color: Colors.black) - ..circle(color: customColor1)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - - // Test default theme for disabled widget. - await tester.pumpWidget(buildApp(enabled: false)); - await tester.pumpAndSettle(); - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor)); - expect(sliderBox, paints..shadow(color: Colors.black)..circle(color: sliderTheme.disabledThumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); - - // Test setting the activeColor and inactiveColor for disabled widget. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, enabled: false)); - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor)); - expect(sliderBox, paints..circle(color: sliderTheme.disabledThumbColor)); - expect(sliderBox, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(sliderBox, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); - - // Test that the default value indicator has the right colors. - await tester.pumpWidget(buildApp(divisions: 3)); - Offset center = tester.getCenter(find.byType(Slider)); - TestGesture gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect(value, equals(2.0 / 3.0)); - expect( - valueIndicatorBox, - paints - ..rrect(color: sliderTheme.activeTrackColor) - ..rrect(color: sliderTheme.inactiveTrackColor) - ..circle(color: sliderTheme.overlayColor) - ..circle(color: sliderTheme.activeTickMarkColor) - ..circle(color: sliderTheme.activeTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.inactiveTickMarkColor) - ..shadow(color: Colors.black) - ..circle(color: sliderTheme.thumbColor) - ..path(color: sliderTheme.valueIndicatorColor), - ); - await gesture.up(); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - - // Testing the custom colors are used for the indicator. - await tester.pumpWidget(buildApp( - divisions: 3, - activeColor: customColor1, - inactiveColor: customColor2, - )); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect(value, equals(2.0 / 3.0)); - expect( - valueIndicatorBox, - paints - ..rrect(color: customColor1) // active track - ..rrect(color: customColor2) // inactive track - ..circle(color: customColor1.withOpacity(0.12)) // overlay - ..circle(color: customColor2) // 1st tick mark - ..circle(color: customColor2) // 2nd tick mark - ..circle(color: customColor2) // 3rd tick mark - ..circle(color: customColor1) // 4th tick mark - ..shadow(color: Colors.black) - ..circle(color: customColor1) // thumb - ..path(color: sliderTheme.valueIndicatorColor), // indicator - ); - await gesture.up(); - }); - - testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async { - const Color customColor1 = Color(0xcafefeed); - const Color customColor2 = Color(0xdeadbeef); - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - sliderTheme: const SliderThemeData( - disabledThumbColor: Color(0xff000001), - disabledActiveTickMarkColor: Color(0xff000002), - disabledActiveTrackColor: Color(0xff000003), - disabledInactiveTickMarkColor: Color(0xff000004), - disabledInactiveTrackColor: Color(0xff000005), - activeTrackColor: Color(0xff000006), - activeTickMarkColor: Color(0xff000007), - inactiveTrackColor: Color(0xff000008), - inactiveTickMarkColor: Color(0xff000009), - overlayColor: Color(0xff000010), - thumbColor: Color(0xff000011), - valueIndicatorColor: Color(0xff000012), - ), - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - double value = 0.45; - Widget buildApp({ - Color activeColor, - Color inactiveColor, - int divisions, - bool enabled = true, - }) { - final ValueChanged onChanged = !enabled - ? null - : (double d) { - value = d; - }; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: theme, - child: Slider( - value: value, - label: '$value', - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, - ), - ), - ), - ), - ), - ), - ); - } - - await tester.pumpWidget(buildApp()); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); // Check default theme for enabled widget. expect(sliderBox, paints..rect(color: sliderTheme.activeTrackColor)..rect(color: sliderTheme.inactiveTrackColor)); @@ -981,7 +729,7 @@ void main() { await tester.pumpAndSettle(); expect(value, equals(2.0 / 3.0)); expect( - valueIndicatorBox, + sliderBox, paints ..rect(color: sliderTheme.activeTrackColor) ..rect(color: sliderTheme.inactiveTrackColor) @@ -990,8 +738,8 @@ void main() { ..circle(color: sliderTheme.activeTickMarkColor) ..circle(color: sliderTheme.inactiveTickMarkColor) ..circle(color: sliderTheme.inactiveTickMarkColor) - ..circle(color: sliderTheme.thumbColor) - ..path(color: sliderTheme.valueIndicatorColor), + ..path(color: sliderTheme.valueIndicatorColor) + ..circle(color: sliderTheme.thumbColor), ); await gesture.up(); // Wait for value indicator animation to finish. @@ -1009,7 +757,7 @@ void main() { await tester.pumpAndSettle(); expect(value, equals(2.0 / 3.0)); expect( - valueIndicatorBox, + sliderBox, paints ..rect(color: customColor1) // active track ..rect(color: customColor2) // inactive track @@ -1018,39 +766,35 @@ void main() { ..circle(color: customColor2) // 2nd tick mark ..circle(color: customColor2) // 3rd tick mark ..circle(color: customColor1) // 4th tick mark - ..circle(color: customColor1) // thumb - ..path(color: customColor1), // indicator + ..path(color: customColor1) // indicator + ..circle(color: customColor1), // thumb ); await gesture.up(); }); testWidgets('Slider can tap in vertical scroller', (WidgetTester tester) async { double value = 0.0; - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: ListView( - children: [ - Slider( - value: value, - onChanged: (double newValue) { - value = newValue; - }, - ), - Container( - height: 2000.0, - ), - ], + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: ListView( + children: [ + Slider( + value: value, + onChanged: (double newValue) { + value = newValue; + }, ), - ), + Container( + height: 2000.0, + ), + ], ), ), ), - ); + )); await tester.tap(find.byType(Slider)); expect(value, equals(0.5)); @@ -1058,26 +802,22 @@ void main() { testWidgets('Slider drags immediately (LTR)', (WidgetTester tester) async { double value = 0.0; - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - value: value, - onChanged: (double newValue) { - value = newValue; - }, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + value: value, + onChanged: (double newValue) { + value = newValue; + }, ), ), ), ), - ); + )); final Offset center = tester.getCenter(find.byType(Slider)); final TestGesture gesture = await tester.startGesture(center); @@ -1093,26 +833,22 @@ void main() { testWidgets('Slider drags immediately (RTL)', (WidgetTester tester) async { double value = 0.0; - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - value: value, - onChanged: (double newValue) { - value = newValue; - }, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.rtl, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + value: value, + onChanged: (double newValue) { + value = newValue; + }, ), ), ), ), - ); + )); final Offset center = tester.getCenter(find.byType(Slider)); final TestGesture gesture = await tester.startGesture(center); @@ -1127,220 +863,61 @@ void main() { }); testWidgets('Slider sizing', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: const Material( - child: Center( - child: Slider( - value: 0.5, - onChanged: null, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: const Material( + child: Center( + child: Slider( + value: 0.5, + onChanged: null, ), ), ), ), - ); + )); expect(tester.renderObject(find.byType(Slider)).size, const Size(800.0, 600.0)); - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: const Material( - child: Center( - child: IntrinsicWidth( - child: Slider( - value: 0.5, - onChanged: null, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: const Material( + child: Center( + child: IntrinsicWidth( + child: Slider( + value: 0.5, + onChanged: null, ), ), ), ), ), - ); + )); expect(tester.renderObject(find.byType(Slider)).size, const Size(144.0 + 2.0 * 24.0, 600.0)); - await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: const Material( - child: Center( - child: OverflowBox( - maxWidth: double.infinity, - maxHeight: double.infinity, - child: Slider( - value: 0.5, - onChanged: null, - ), - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: const Material( + child: Center( + child: OverflowBox( + maxWidth: double.infinity, + maxHeight: double.infinity, + child: Slider( + value: 0.5, + onChanged: null, ), ), ), ), ), - ); + )); expect(tester.renderObject(find.byType(Slider)).size, const Size(144.0 + 2.0 * 24.0, 48.0)); }); - testWidgets('Slider V2 respects textScaleFactor', (WidgetTester tester) async { - final Key sliderKey = UniqueKey(); - double value = 0.0; - - Widget buildSlider({ - double textScaleFactor, - bool isDiscrete = true, - ShowValueIndicator show = ShowValueIndicator.onlyForDiscrete, - }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), - child: Material( - child: Theme( - data: Theme.of(context).copyWith( - sliderTheme: Theme.of(context).sliderTheme.copyWith(showValueIndicator: show), - ), - child: Center( - child: OverflowBox( - maxWidth: double.infinity, - maxHeight: double.infinity, - child: Slider( - key: sliderKey, - min: 0.0, - max: 100.0, - divisions: isDiscrete ? 10 : null, - label: '${value.round()}', - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - useV2Slider: true, - ), - ), - ), - ), - ), - ); - }, - ), - ), - ); - } - - await tester.pumpWidget(buildSlider(textScaleFactor: 1.0)); - Offset center = tester.getCenter(find.byType(Slider)); - TestGesture gesture = await tester.startGesture(center); - await tester.pumpAndSettle(); - - expect( - tester.firstRenderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(0.0, -38.0), - Offset(-30.0, -16.0), - Offset(30.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - - await gesture.up(); - await tester.pumpAndSettle(); - - await tester.pumpWidget(buildSlider(textScaleFactor: 2.0)); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - await tester.pumpAndSettle(); - - expect( - tester.firstRenderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(0.0, -52.0), - Offset(-44.0, -16.0), - Offset(44.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - - await gesture.up(); - await tester.pumpAndSettle(); - - // Check continuous - await tester.pumpWidget(buildSlider( - textScaleFactor: 1.0, - isDiscrete: false, - show: ShowValueIndicator.onlyForContinuous, - )); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - await tester.pumpAndSettle(); - - expect(tester.firstRenderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(0.0, -38.0), - Offset(-30.0, -16.0), - Offset(30.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - - await gesture.up(); - await tester.pumpAndSettle(); - - await tester.pumpWidget(buildSlider( - textScaleFactor: 2.0, - isDiscrete: false, - show: ShowValueIndicator.onlyForContinuous, - )); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - await tester.pumpAndSettle(); - - expect( - tester.firstRenderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(0.0, -52.0), - Offset(-44.0, -16.0), - Offset(44.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - - await gesture.up(); - await tester.pumpAndSettle(); - }, skip: isBrowser); - testWidgets('Slider respects textScaleFactor', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -1350,42 +927,40 @@ void main() { bool isDiscrete = true, ShowValueIndicator show = ShowValueIndicator.onlyForDiscrete, }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), - child: Material( - child: Theme( - data: Theme.of(context).copyWith( - sliderTheme: Theme.of(context).sliderTheme.copyWith(showValueIndicator: show), - ), - child: Center( - child: OverflowBox( - maxWidth: double.infinity, - maxHeight: double.infinity, - child: Slider( - key: sliderKey, - min: 0.0, - max: 100.0, - divisions: isDiscrete ? 10 : null, - label: '${value.round()}', - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData(textScaleFactor: textScaleFactor), + child: Material( + child: Theme( + data: Theme.of(context).copyWith( + sliderTheme: Theme.of(context).sliderTheme.copyWith(showValueIndicator: show), + ), + child: Center( + child: OverflowBox( + maxWidth: double.infinity, + maxHeight: double.infinity, + child: Slider( + key: sliderKey, + min: 0.0, + max: 100.0, + divisions: isDiscrete ? 10 : null, + label: '${value.round()}', + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), ), ), - ); - }, - ), + ), + ); + }, ), ); } @@ -1395,7 +970,7 @@ void main() { TestGesture gesture = await tester.startGesture(center); await tester.pumpAndSettle(); - expect(tester.firstRenderObject(find.byType(Overlay)), paints..scale(x: 1.0, y: 1.0)); + expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0)); await gesture.up(); await tester.pumpAndSettle(); @@ -1405,7 +980,7 @@ void main() { gesture = await tester.startGesture(center); await tester.pumpAndSettle(); - expect(tester.firstRenderObject(find.byType(Overlay)), paints..scale(x: 2.0, y: 2.0)); + expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0)); await gesture.up(); await tester.pumpAndSettle(); @@ -1420,7 +995,7 @@ void main() { gesture = await tester.startGesture(center); await tester.pumpAndSettle(); - expect(tester.firstRenderObject(find.byType(Overlay)), paints..scale(x: 1.0, y: 1.0)); + expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0)); await gesture.up(); await tester.pumpAndSettle(); @@ -1434,7 +1009,7 @@ void main() { gesture = await tester.startGesture(center); await tester.pumpAndSettle(); - expect(tester.firstRenderObject(find.byType(Overlay)), paints..scale(x: 2.0, y: 2.0)); + expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0)); await gesture.up(); await tester.pumpAndSettle(); @@ -1444,20 +1019,18 @@ void main() { Widget buildSlider({ int divisions, }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - min: 0.0, - max: 100.0, - divisions: divisions, - value: 0.25, - onChanged: (double newValue) { }, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + min: 0.0, + max: 100.0, + divisions: divisions, + value: 0.25, + onChanged: (double newValue) { }, ), ), ), @@ -1491,139 +1064,6 @@ void main() { expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 1)); }); - testWidgets('Slider V2 has correct animations when reparented', (WidgetTester tester) async { - final Key sliderKey = GlobalKey(debugLabel: 'A'); - double value = 0.0; - - Widget buildSlider(int parents) { - Widget createParents(int parents, StateSetter setState) { - Widget slider = Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - useV2Slider: true, - ); - - for (int i = 0; i < parents; ++i) { - slider = Column(children: [slider]); - } - return slider; - } - - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: createParents(parents, setState), - ), - ); - }, - ), - ), - ); - } - - Future testReparenting(bool reparent) async { - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - final Offset center = tester.getCenter(find.byType(Slider)); - // Move to 0.0. - TestGesture gesture = await tester.startGesture(Offset.zero); - await tester.pump(); - await gesture.up(); - await tester.pumpAndSettle(); - expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); - expect( - sliderBox, - paints - ..circle(x: 26.0, y: 24.0, radius: 1.0) - ..circle(x: 213.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 1.0) - ..circle(x: 587.0, y: 24.0, radius: 1.0) - ..circle(x: 774.0, y: 24.0, radius: 1.0) - ..circle(x: 24.0, y: 24.0, radius: 10.0), - ); - - gesture = await tester.startGesture(center); - await tester.pump(); - // Wait for animations to start. - await tester.pump(const Duration(milliseconds: 25)); - expect(SchedulerBinding.instance.transientCallbackCount, equals(2)); - expect( - sliderBox, - paints - ..circle(x: 111.20703125, y: 24.0, radius: 5.687664985656738) - ..circle(x: 26.0, y: 24.0, radius: 1.0) - ..circle(x: 213.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 1.0) - ..circle(x: 587.0, y: 24.0, radius: 1.0) - ..circle(x: 774.0, y: 24.0, radius: 1.0) - ..circle(x: 111.20703125, y: 24.0, radius: 10.0), - ); - - // Reparenting in the middle of an animation should do nothing. - if (reparent) { - await tester.pumpWidget(buildSlider(2)); - } - - // Move a little further in the animations. - await tester.pump(const Duration(milliseconds: 10)); - expect(SchedulerBinding.instance.transientCallbackCount, equals(2)); - expect( - sliderBox, - paints - ..circle(x: 190.0135726928711, y: 24.0, radius: 12.0) - ..circle(x: 26.0, y: 24.0, radius: 1.0) - ..circle(x: 213.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 1.0) - ..circle(x: 587.0, y: 24.0, radius: 1.0) - ..circle(x: 774.0, y: 24.0, radius: 1.0) - ..circle(x: 190.0135726928711, y: 24.0, radius: 10.0), - ); - // Wait for animations to finish. - await tester.pumpAndSettle(); - expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); - expect( - sliderBox, - paints - ..circle(x: 400.0, y: 24.0, radius: 24.0) - ..circle(x: 26.0, y: 24.0, radius: 1.0) - ..circle(x: 213.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 1.0) - ..circle(x: 587.0, y: 24.0, radius: 1.0) - ..circle(x: 774.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 10.0), - ); - await gesture.up(); - await tester.pumpAndSettle(); - expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); - expect( - sliderBox, - paints - ..circle(x: 26.0, y: 24.0, radius: 1.0) - ..circle(x: 213.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 1.0) - ..circle(x: 587.0, y: 24.0, radius: 1.0) - ..circle(x: 774.0, y: 24.0, radius: 1.0) - ..circle(x: 400.0, y: 24.0, radius: 10.0), - ); - } - - await tester.pumpWidget(buildSlider(1)); - // Do it once without reparenting in the middle of an animation - await testReparenting(false); - // Now do it again with reparenting in the middle of an animation. - await testReparenting(true); - }); - testWidgets('Slider has correct animations when reparented', (WidgetTester tester) async { final Key sliderKey = GlobalKey(debugLabel: 'A'); double value = 0.0; @@ -1647,19 +1087,17 @@ void main() { return slider; } - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: createParents(parents, setState), - ), - ); - }, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: createParents(parents, setState), + ), + ); + }, ), ); } @@ -1756,20 +1194,17 @@ void main() { await testReparenting(true); }); - testWidgets('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Slider( - value: 0.5, - onChanged: (double v) { }, - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Slider( + value: 0.5, + onChanged: (double v) { }, ), ), ), @@ -1781,23 +1216,11 @@ void main() { TestSemantics.root(children: [ TestSemantics.rootChild( id: 1, + value: '50%', + increasedValue: '55%', + decreasedValue: '45%', textDirection: TextDirection.ltr, - - children: [ - TestSemantics( - id: 2, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 3, - actions: SemanticsAction.decrease.index | SemanticsAction.increase.index, - value: '50%', - increasedValue: '55%', - decreasedValue: '45%', - ), - ], - ), - ], + actions: SemanticsAction.decrease.index | SemanticsAction.increase.index, ), ]), ignoreRect: true, @@ -1805,16 +1228,14 @@ void main() { )); // Disable slider - await tester.pumpWidget(MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: const Material( - child: Slider( - value: 0.5, - onChanged: null, - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: const Material( + child: Slider( + value: 0.5, + onChanged: null, ), ), ), @@ -1823,18 +1244,7 @@ void main() { expect( semantics, hasSemantics( - TestSemantics.root(children: [ - TestSemantics.rootChild( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - flags: [SemanticsFlag.scopesRoute], - ), - ], - ), - ]), + TestSemantics.root(), ignoreRect: true, ignoreTransform: true, )); @@ -1842,12 +1252,11 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); -testWidgets('Slider Semantics', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); + testWidgets('Slider Semantics', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - MaterialApp( - home: Theme( + await tester.pumpWidget( + Theme( data: ThemeData.light(), child: Directionality( textDirection: TextDirection.ltr, @@ -1864,56 +1273,42 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { ), ), ), - ), - ); + ); - expect( - semantics, - hasSemantics( - TestSemantics.root(children: [ - TestSemantics.rootChild( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 3, - actions: SemanticsAction.decrease.index | SemanticsAction.increase.index, - value: '50%', - increasedValue: '60%', - decreasedValue: '40%', - ), - ], - ), - ], - ), - ]), - ignoreRect: true, - ignoreTransform: true, - )); - semantics.dispose(); -}, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + expect( + semantics, + hasSemantics( + TestSemantics.root(children: [ + TestSemantics.rootChild( + id: 1, + value: '50%', + increasedValue: '60%', + decreasedValue: '40%', + textDirection: TextDirection.ltr, + actions: SemanticsAction.decrease.index | SemanticsAction.increase.index, + ), + ]), + ignoreRect: true, + ignoreTransform: true, + )); + semantics.dispose(); + }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets('Slider semantics with custom formatter', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Slider( - value: 40.0, - min: 0.0, - max: 200.0, - divisions: 10, - semanticFormatterCallback: (double value) => value.round().toString(), - onChanged: (double v) { }, - ), + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Slider( + value: 40.0, + min: 0.0, + max: 200.0, + divisions: 10, + semanticFormatterCallback: (double value) => value.round().toString(), + onChanged: (double v) { }, ), ), ), @@ -1925,22 +1320,11 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { TestSemantics.root(children: [ TestSemantics.rootChild( id: 1, + value: '40', + increasedValue: '60', + decreasedValue: '20', textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 3, - actions: SemanticsAction.increase.index | SemanticsAction.decrease.index, - value: '40', - increasedValue: '60', - decreasedValue: '20', - ), - ], - ), - ], + actions: SemanticsAction.decrease.index | SemanticsAction.increase.index, ), ]), ignoreRect: true, @@ -1958,23 +1342,21 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { double value = 0.45; Widget buildApp({ SliderThemeData sliderTheme, int divisions, bool enabled = true }) { final ValueChanged onChanged = enabled ? (double d) => value = d : null; - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Theme( - data: baseTheme, - child: SliderTheme( - data: sliderTheme, - child: Slider( - value: value, - label: '$value', - divisions: divisions, - onChanged: onChanged, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Theme( + data: baseTheme, + child: SliderTheme( + data: sliderTheme, + child: Slider( + value: value, + label: '$value', + divisions: divisions, + onChanged: onChanged, ), ), ), @@ -1997,9 +1379,9 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); expect( - valueIndicatorBox, + sliderBox, isVisible ? (paints..path(color: theme.valueIndicatorColor)) : isNot(paints..path(color: theme.valueIndicatorColor)), @@ -2039,30 +1421,28 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + key: sliderKey, + value: value, + divisions: 4, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -2137,36 +1517,34 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; await tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(tickMarkShape: TallSliderTickMarkShape()); - return MediaQuery( - data: MediaQueryData.fromWindow(window), - child: Material( - child: Center( - child: IntrinsicHeight( - child: SliderTheme( - data: sliderTheme, - child: Slider( - key: sliderKey, - value: value, - divisions: 4, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ), + Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(tickMarkShape: TallSliderTickMarkShape()); + return MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: IntrinsicHeight( + child: SliderTheme( + data: sliderTheme, + child: Slider( + key: sliderKey, + value: value, + divisions: 4, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, ), ), ), ), - ); - }, - ), + ), + ); + }, ), ), ); @@ -2205,7 +1583,6 @@ testWidgets('Slider Semantics', (WidgetTester tester) async { 'label: "Set a value"', 'activeColor: MaterialColor(primary value: Color(0xff2196f3))', 'inactiveColor: MaterialColor(primary value: Color(0xff9e9e9e))', - 'useV1Slider', ]); }); } diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index a99270a7859..8ddf4730cec 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -94,24 +94,6 @@ void main() { ]); }); - testWidgets('Slider V2 uses ThemeData slider theme if present', (WidgetTester tester) async { - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.red, - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false, useV2Slider: true)); - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - - expect( - sliderBox, - paints - ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor), - ); - }); - testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -130,28 +112,6 @@ void main() { ); }); - testWidgets('Slider V2 overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.red, - ); - final SliderThemeData sliderTheme = theme.sliderTheme; - final SliderThemeData customTheme = sliderTheme.copyWith( - activeTrackColor: Colors.purple, - inactiveTrackColor: Colors.purple.withAlpha(0x3d), - ); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false, useV2Slider: true)); - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - - expect( - sliderBox, - paints - ..rrect(color: customTheme.disabledActiveTrackColor) - ..rrect(color: customTheme.disabledInactiveTrackColor), - ); - }); - testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -258,40 +218,6 @@ void main() { expect(lerp.valueIndicatorTextStyle.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgets('Slider V2 track draws correctly', (WidgetTester tester) async { - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - ); - final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, useV2Slider: true)); - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - - const Radius radius = Radius.circular(2); - const Radius activatedRadius = Radius.circular(3); - - // The enabled slider thumb has track segments that extend to and from - // the center of the thumb. - expect( - sliderBox, - paints - ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.activeTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor), - ); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false, useV2Slider: true)); - await tester.pumpAndSettle(); // wait for disable animation - - // The disabled slider thumb is the same size as the enabled thumb. - expect( - sliderBox, - paints - ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.disabledActiveTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor), - ); - }); - testWidgets('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -314,7 +240,12 @@ void main() { await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false)); await tester.pumpAndSettle(); // wait for disable animation - // The disabled slider thumb is the same size as the enabled thumb. + // The disabled slider thumb has a horizontal gap between itself and the + // track segments. Therefore, the track segments are shorter since they do + // not extend to the center of the thumb, but rather the outer edge of th + // gap. As a result, the `right` value of the first segment is less than it + // is above, and the `left` value of the second segment is more than it is + // above. expect( sliderBox, paints @@ -428,38 +359,32 @@ void main() { ); }); - testWidgets('Slider V2 value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default slider value indicator shape draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, ); - final SliderThemeData sliderTheme = theme.sliderTheme.copyWith( - thumbColor: Colors.red.shade500, - showValueIndicator: ShowValueIndicator.always, - ); + final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500, showValueIndicator: ShowValueIndicator.always); Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: textScale), - child: Material( - child: Row( - children: [ - Expanded( - child: SliderTheme( - data: sliderTheme, - child: Slider( - value: sliderValue, - label: value, - divisions: 3, - onChanged: (double d) { }, - useV2Slider: true, - ), + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: textScale), + child: Material( + child: Row( + children: [ + Expanded( + child: SliderTheme( + data: sliderTheme, + child: Slider( + value: sliderValue, + label: value, + divisions: 3, + onChanged: (double d) { }, ), ), - ], - ), + ), + ], ), ), ), @@ -468,195 +393,14 @@ void main() { await tester.pumpWidget(buildApp('1')); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); Offset center = tester.getCenter(find.byType(Slider)); TestGesture gesture = await tester.startGesture(center); // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, - paints - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-20.0, -12.0), - Offset(20.0, -34.0), - Offset(0.0, -38.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - - await gesture.up(); - - // Test that it expands with a larger label. - await tester.pumpWidget(buildApp('1000')); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, - paints - ..rrect() - ..rrect() - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-30.0, -12.0), - Offset(30.0, -34.0), - Offset(0.0, -38.0), - ], - color: const Color(0xf55f5f5f), - ), - ); - await gesture.up(); - - // Test that it avoids the left edge of the screen. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0)); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, - paints - ..rrect() - ..rrect() - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-12.0, -12.0), - Offset(110.0, -34.0), - Offset(0.0, -38.0), - ], - color: const Color(0xf55f5f5f), - ) - ); - await gesture.up(); - - // Test that it avoids the right edge of the screen. - await tester.pumpWidget(buildApp('1000000', sliderValue: 1.0)); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, - paints - ..rrect() - ..rrect() - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-110.0, -12.0), - Offset(12.0, -34.0), - Offset(0.0, -38.0), - ], - color: const Color(0xf55f5f5f), - ) - ); - await gesture.up(); - - // Test that the box decreases in height when the text scale gets smaller. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 0.5)); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, - paints - ..rrect() - ..rrect() - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-12.0, -12.0), - Offset(61.0, -16.0), - Offset(0.0, -20.0), - ], - excludes: const [ - Offset(0.0, -38.0) - ], - color: const Color(0xf55f5f5f), - ) - ); - await gesture.up(); - - // Test that the box increases in height when the text scale gets bigger. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.0)); - center = tester.getCenter(find.byType(Slider)); - gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, - paints - ..rrect() - ..rrect() - ..path( - includes: const [ - Offset(0.0, 0.0), - Offset(-12.0, -16.0), - Offset(208.0, -40.0), - Offset(0.0, -50.0), - ], - color: const Color(0xf55f5f5f), - ) - ); - await gesture.up(); - }, skip: isBrowser); - - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { - final ThemeData theme = ThemeData( - platform: TargetPlatform.android, - primarySwatch: Colors.blue, - ); - final SliderThemeData sliderTheme = theme.sliderTheme.copyWith( - thumbColor: Colors.red.shade500, - showValueIndicator: ShowValueIndicator.always, - valueIndicatorShape: const PaddleSliderValueIndicatorShape(), - ); - Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: MediaQueryData.fromWindow(window).copyWith(textScaleFactor: textScale), - child: Material( - child: Row( - children: [ - Expanded( - child: SliderTheme( - data: sliderTheme, - child: Slider( - value: sliderValue, - label: value, - divisions: 3, - onChanged: (double d) { }, - ), - ), - ), - ], - ), - ), - ), - ), - ); - } - - await tester.pumpWidget(buildApp('1')); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - Offset center = tester.getCenter(find.byType(Slider)); - TestGesture gesture = await tester.startGesture(center); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); - expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -678,7 +422,7 @@ void main() { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -699,7 +443,7 @@ void main() { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -720,7 +464,7 @@ void main() { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -741,7 +485,7 @@ void main() { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -767,7 +511,7 @@ void main() { // Wait for value indicator animation to finish. await tester.pumpAndSettle(); expect( - valueIndicatorBox, + sliderBox, paints ..path( color: sliderTheme.valueIndicatorColor, @@ -814,36 +558,6 @@ void main() { ); }); - testWidgets('The slider V2 track height can be overridden', (WidgetTester tester) async { - final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); - const Radius radius = Radius.circular(8); - const Radius activatedRadius = Radius.circular(9); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - - // Top and bottom are centerY (300) + and - trackRadius (8). - expect( - sliderBox, - paints - ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 291.0, 212.0, 309.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.activeTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 292.0, 776.0, 308.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor), - ); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false, useV2Slider: true)); - await tester.pumpAndSettle(); // wait for disable animation - - // The disabled thumb is smaller so the active track has to paint longer to - // get to the edge. - expect( - sliderBox, - paints - ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 291.0, 212.0, 309.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.disabledActiveTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 292.0, 776.0, 308.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor), - ); - }); - testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( @@ -892,6 +606,7 @@ void main() { ); }); + testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), @@ -913,7 +628,7 @@ void main() { ..circle(x: 771, y: 300, radius: 5, color: sliderTheme.inactiveTickMarkColor), ); - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2, enabled: false)); + await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2, enabled: false)); await tester.pumpAndSettle(); expect( @@ -925,39 +640,6 @@ void main() { ); }); - testWidgets('The default slider V2 tick mark shape size can be overridden', (WidgetTester tester) async { - final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( - tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5, useV2Slider: true), - activeTickMarkColor: const Color(0xfadedead), - inactiveTickMarkColor: const Color(0xfadebeef), - disabledActiveTickMarkColor: const Color(0xfadecafe), - disabledInactiveTickMarkColor: const Color(0xfadeface), - ); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2, useV2Slider: true)); - - final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); - - expect( - sliderBox, - paints - ..circle(x: 26, y: 300, radius: 5, color: sliderTheme.activeTickMarkColor) - ..circle(x: 400, y: 300, radius: 5, color: sliderTheme.activeTickMarkColor) - ..circle(x: 774, y: 300, radius: 5, color: sliderTheme.inactiveTickMarkColor), - ); - - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2, enabled: false, useV2Slider: true)); - await tester.pumpAndSettle(); - - expect( - sliderBox, - paints - ..circle(x: 26, y: 300, radius: 5, color: sliderTheme.disabledActiveTickMarkColor) - ..circle(x: 400, y: 300, radius: 5, color: sliderTheme.disabledActiveTickMarkColor) - ..circle(x: 774, y: 300, radius: 5, color: sliderTheme.disabledInactiveTickMarkColor), - ); - }); - testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( @@ -1118,7 +800,7 @@ void main() { divisions: 4, )); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); // Tap the center of the track and wait for animations to finish. final Offset center = tester.getCenter(find.byType(Slider)); @@ -1126,132 +808,41 @@ void main() { await tester.pumpAndSettle(); // Only 1 value indicator. - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawRect, 0)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawCircle, 0)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 1)); - - await gesture.up(); - }); - - testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { - // Pump a slider with just a value indicator. - await tester.pumpWidget(_buildApp( - ThemeData().sliderTheme.copyWith( - trackHeight: 0, - overlayShape: SliderComponentShape.noOverlay, - thumbShape: SliderComponentShape.noThumb, - tickMarkShape: SliderTickMarkShape.noTickMark, - showValueIndicator: ShowValueIndicator.always, - valueIndicatorShape: const PaddleSliderValueIndicatorShape(), - ), - value: 0.5, - divisions: 4, - )); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Tap the center of the track to kick off the animation of the value indicator. - final Offset center = tester.getCenter(find.byType(Slider)); - final TestGesture gesture = await tester.startGesture(center); - - // Nothing to paint at scale 0. - await tester.pump(); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 0)); - - // Painting a path for the value indicator. - await tester.pump(const Duration(milliseconds: 16)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 1)); - - await gesture.up(); - }); - - testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { - // Pump a slider with just a value indicator. - await tester.pumpWidget(_buildApp( - ThemeData().sliderTheme.copyWith( - trackHeight: 0, - overlayShape: SliderComponentShape.noOverlay, - thumbShape: SliderComponentShape.noThumb, - tickMarkShape: SliderTickMarkShape.noTickMark, - showValueIndicator: ShowValueIndicator.always, - ), - value: 0.5, - divisions: 4, - )); - - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Tap the center of the track to kick off the animation of the value indicator. - final Offset center = tester.getCenter(find.byType(Slider)); - final TestGesture gesture = await tester.startGesture(center); - - // Nothing to paint at scale 0. - await tester.pump(); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 0)); - - // Painting a path for the value indicator. - await tester.pump(const Duration(milliseconds: 16)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 1)); + expect(sliderBox, paintsExactlyCountTimes(#drawRect, 0)); + expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 0)); + expect(sliderBox, paintsExactlyCountTimes(#drawPath, 1)); await gesture.up(); }); testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. - await tester.pumpWidget(_buildRangeApp( - ThemeData().sliderTheme.copyWith( - trackHeight: 0, - rangeValueIndicatorShape: const PaddleRangeSliderValueIndicatorShape(), - ), - values: const RangeValues(0, 0.5), - divisions: 4, - )); - -// final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); - - // Tap the center of the track to kick off the animation of the value indicator. - final Offset center = tester.getCenter(find.byType(RangeSlider)); - final TestGesture gesture = await tester.startGesture(center); - - // No value indicator path to paint at scale 0. - await tester.pump(); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 0)); - - // Painting a path for each value indicator. - await tester.pump(const Duration(milliseconds: 16)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 2)); - - await gesture.up(); - }); - - testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { - // Pump a slider with just a value indicator. - await tester.pumpWidget(_buildRangeApp( + await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackHeight: 0, overlayShape: SliderComponentShape.noOverlay, thumbShape: SliderComponentShape.noThumb, tickMarkShape: SliderTickMarkShape.noTickMark, showValueIndicator: ShowValueIndicator.always, + rangeValueIndicatorShape: const PaddleRangeSliderValueIndicatorShape(), ), - values: const RangeValues(0, 0.5), + value: 0.5, divisions: 4, )); - final RenderBox valueIndicatorBox = tester.firstRenderObject(find.byType(Overlay)); + final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); // Tap the center of the track to kick off the animation of the value indicator. - final Offset center = tester.getCenter(find.byType(RangeSlider)); + final Offset center = tester.getCenter(find.byType(Slider)); final TestGesture gesture = await tester.startGesture(center); - // No value indicator path to paint at scale 0. + // Nothing to paint at scale 0. await tester.pump(); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 0)); + expect(sliderBox, paintsNothing); - // Painting a path for each value indicator. + // Painting a path for the value indicator. await tester.pump(const Duration(milliseconds: 16)); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 2)); + expect(sliderBox, paintsExactlyCountTimes(#drawPath, 1)); await gesture.up(); }); @@ -1262,7 +853,6 @@ Widget _buildApp( double value = 0.0, bool enabled = true, int divisions, - bool useV2Slider = false, }) { final ValueChanged onChanged = enabled ? (double d) => value = d : null; return MaterialApp( @@ -1275,31 +865,6 @@ Widget _buildApp( label: '$value', onChanged: onChanged, divisions: divisions, - useV2Slider: useV2Slider - ), - ), - ), - ), - ); -} - -Widget _buildRangeApp( - SliderThemeData sliderTheme, { - RangeValues values = const RangeValues(0, 0), - bool enabled = true, - int divisions, - }) { - final ValueChanged onChanged = enabled ? (RangeValues d) => values = d : null; - return MaterialApp( - home: Scaffold( - body: Center( - child: SliderTheme( - data: sliderTheme, - child: RangeSlider( - values: values, - labels: RangeLabels(values.start.toString(), values.end.toString()), - onChanged: onChanged, - divisions: divisions, ), ), ), diff --git a/packages/flutter/test/painting/system_fonts_test.dart b/packages/flutter/test/painting/system_fonts_test.dart index 9e58f5f378b..ccb04db7aa2 100644 --- a/packages/flutter/test/painting/system_fonts_test.dart +++ b/packages/flutter/test/painting/system_fonts_test.dart @@ -169,10 +169,7 @@ void main() { (ByteData data) { }, ); final RenderObject renderObject = tester.renderObject(find.byType(RangeSlider)); - - bool sliderBoxNeedsLayout; - renderObject.visitChildren((RenderObject child) {sliderBoxNeedsLayout = child.debugNeedsLayout;}); - expect(sliderBoxNeedsLayout, isTrue); + expect(renderObject.debugNeedsLayout, isTrue); }); testWidgets('Slider relayout upon system fonts changes', (WidgetTester tester) async { @@ -194,11 +191,8 @@ void main() { SystemChannels.system.codec.encodeMessage(data), (ByteData data) { }, ); - final RenderObject renderObject = tester.renderObject(find.byType(Slider)); - - bool sliderBoxNeedsLayout; - renderObject.visitChildren((RenderObject child) {sliderBoxNeedsLayout = child.debugNeedsLayout;}); - expect(sliderBoxNeedsLayout, isTrue); + final RenderObject renderObject = tester.renderObject(find.byType(Slider)); + expect(renderObject.debugNeedsLayout, isTrue); }); testWidgets('TimePicker relayout upon system fonts changes', (WidgetTester tester) async {