From 0d3d8d4bfded8e0d005e1f325acf7da523ea4499 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 6 Jun 2022 16:38:07 -0700 Subject: [PATCH] [framework] respect debugDisableShadows in slider thumbs (#105467) --- .../lib/src/material/slider_theme.dart | 40 +- .../test/material/range_slider_test.dart | 20 +- .../flutter/test/material/slider_test.dart | 674 +++++++------- .../test/material/slider_theme_test.dart | 873 ++++++++++-------- 4 files changed, 867 insertions(+), 740 deletions(-) diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index a6da38021866..eeed8a280813 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -2366,7 +2366,19 @@ class RoundSliderThumbShape extends SliderComponentShape { 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); + + bool paintShadows = true; + assert(() { + if (debugDisableShadows) { + _debugDrawShadow(canvas, path, evaluatedElevation); + paintShadows = false; + } + return true; + }()); + + if (paintShadows) { + canvas.drawShadow(path, Colors.black, evaluatedElevation, true); + } canvas.drawCircle( center, @@ -2475,7 +2487,19 @@ class RoundRangeSliderThumbShape extends RangeSliderThumbShape { 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); + + bool paintShadows = true; + assert(() { + if (debugDisableShadows) { + _debugDrawShadow(canvas, shadowPath, evaluatedElevation); + paintShadows = false; + } + return true; + }()); + + if (paintShadows) { + canvas.drawShadow(shadowPath, Colors.black, evaluatedElevation, true); + } canvas.drawCircle( center, @@ -3359,3 +3383,15 @@ class RangeLabels { return '${objectRuntimeType(this, 'RangeLabels')}($start, $end)'; } } + +void _debugDrawShadow(Canvas canvas, Path path, double elevation) { + if (elevation > 0.0) { + canvas.drawPath( + path, + Paint() + ..color = Colors.black + ..style = PaintingStyle.stroke + ..strokeWidth = elevation * 2.0, + ); + } +} diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index e713958af7f9..44a9dff231b4 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -1276,8 +1276,10 @@ void main() { expect( valueIndicatorBox, paints + ..path(color: Colors.black) // shadow + ..path(color: Colors.black) // shadow ..path(color: sliderTheme.valueIndicatorColor) - ..paragraph(), + ..paragraph() ); await gesture.up(); // Wait for value indicator animation to finish. @@ -1360,7 +1362,7 @@ void main() { ); // Represents the Raised Button and Range Slider. - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 4)); + expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 6)); expect(valueIndicatorBox, paintsExactlyCountTimes(#drawParagraph, 3)); await tester.tap(find.text('Next')); @@ -1370,11 +1372,11 @@ void main() { expect( valueIndicatorBox, isNot( - paints - ..path(color: fillColor) - ..paragraph() - ..path(color: fillColor) - ..paragraph(), + paints + ..path(color: fillColor) + ..paragraph() + ..path(color: fillColor) + ..paragraph(), ), ); @@ -1519,6 +1521,8 @@ void main() { expect( valueIndicatorBox, paints + ..path(color: Colors.black) // shadow + ..path(color: Colors.black) // shadow ..path(color: sliderTheme.valueIndicatorColor) ..paragraph(), ); @@ -1594,6 +1598,8 @@ void main() { expect( valueIndicatorBox, paints + ..path(color: Colors.black) // shadow + ..path(color: Colors.black) // shadow ..path(color: sliderTheme.valueIndicatorColor) ..paragraph(), ); diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 949b86197059..ff39275a166c 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -627,217 +627,222 @@ void main() { }); 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: Material( - child: Center( - child: Theme( - data: theme, - child: Slider( - value: value, - label: '$value', - divisions: divisions, - activeColor: activeColor, - inactiveColor: inactiveColor, - onChanged: onChanged, + debugDisableShadows = false; + try { + 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: 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()); + await tester.pumpWidget(buildApp()); - final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; - final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay)); - - // Check default theme for enabled widget. - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); - expect(material, paints..shadow(color: const Color(0xff000000))); - expect(material, paints..circle(color: sliderTheme.thumbColor)); - expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - - // Test setting only the activeColor. - await tester.pumpWidget(buildApp(activeColor: customColor1)); - expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)); - expect(material, paints..shadow(color: Colors.black)); - expect(material, paints..circle(color: customColor1)); - expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test setting only the inactiveColor. - await tester.pumpWidget(buildApp(inactiveColor: customColor1)); - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)); - expect(material, paints..shadow(color: Colors.black)); - expect(material, paints..circle(color: sliderTheme.thumbColor)); - expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test setting both activeColor and inactiveColor. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2)); - expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); - expect(material, paints..shadow(color: Colors.black)); - expect(material, paints..circle(color: customColor1)); - expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - - // Test colors for discrete slider. - await tester.pumpWidget(buildApp(divisions: 3)); - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); - expect( - material, - 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(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, 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(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); - expect( - material, - paints - ..circle(color: customColor2) - ..circle(color: customColor2) - ..circle(color: customColor1) - ..circle(color: customColor1) - ..shadow(color: Colors.black) - ..circle(color: customColor1), - ); - expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); - expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); - expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); - - // Test default theme for disabled widget. - await tester.pumpWidget(buildApp(enabled: false)); - await tester.pumpAndSettle(); - expect( - material, - paints - ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor), - ); - expect(material, paints..shadow(color: Colors.black)..circle(color: sliderTheme.disabledThumbColor)); - expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); + final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; + final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay)); - // Test setting the activeColor and inactiveColor for disabled widget. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, enabled: false)); - expect( - material, - paints - ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor), - ); - expect(material, paints..circle(color: sliderTheme.disabledThumbColor)); - expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); - expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); + // Check default theme for enabled widget. + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); + expect(material, paints..shadow(color: const Color(0xff000000))); + expect(material, paints..circle(color: sliderTheme.thumbColor)); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); + expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); + + // Test setting only the activeColor. + await tester.pumpWidget(buildApp(activeColor: customColor1)); + expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)); + expect(material, paints..shadow(color: Colors.black)); + expect(material, paints..circle(color: customColor1)); + expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + + // Test setting only the inactiveColor. + await tester.pumpWidget(buildApp(inactiveColor: customColor1)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)); + expect(material, paints..shadow(color: Colors.black)); + expect(material, paints..circle(color: sliderTheme.thumbColor)); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + + // Test setting both activeColor and inactiveColor. + await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2)); + expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); + expect(material, paints..shadow(color: Colors.black)); + expect(material, paints..circle(color: customColor1)); + expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + + // Test colors for discrete slider. + await tester.pumpWidget(buildApp(divisions: 3)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); + expect( + material, + 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(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, 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(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); + expect( + material, + paints + ..circle(color: customColor2) + ..circle(color: customColor2) + ..circle(color: customColor1) + ..circle(color: customColor1) + ..shadow(color: Colors.black) + ..circle(color: customColor1), + ); + expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); + expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); + + // Test default theme for disabled widget. + await tester.pumpWidget(buildApp(enabled: false)); + await tester.pumpAndSettle(); + expect( + material, + paints + ..rrect(color: sliderTheme.disabledActiveTrackColor) + ..rrect(color: sliderTheme.disabledInactiveTrackColor), + ); + expect(material, paints..shadow(color: Colors.black)..circle(color: sliderTheme.disabledThumbColor)); + expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); + expect(material, 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 - ..path(color: sliderTheme.valueIndicatorColor) - ..paragraph(), - ); - await gesture.up(); - // Wait for value indicator animation to finish. - await tester.pumpAndSettle(); + // Test setting the activeColor and inactiveColor for disabled widget. + await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, enabled: false)); + expect( + material, + paints + ..rrect(color: sliderTheme.disabledActiveTrackColor) + ..rrect(color: sliderTheme.disabledInactiveTrackColor), + ); + expect(material, paints..circle(color: sliderTheme.disabledThumbColor)); + expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); + expect(material, 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 + ..path(color: sliderTheme.valueIndicatorColor) + ..paragraph(), + ); + 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: const Color(0xfffafafa)) - ..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(); + // 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: const Color(0xfffafafa)) + ..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(); + } finally { + debugDisableShadows = true; + } }); testWidgets('Slider can tap in vertical scroller', (WidgetTester tester) async { @@ -1033,152 +1038,157 @@ void main() { }); testWidgets('Slider respects textScaleFactor', (WidgetTester tester) async { - final Key sliderKey = UniqueKey(); - double value = 0.0; - - Widget buildSlider({ - required 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, - max: 100.0, - divisions: isDiscrete ? 10 : null, - label: '${value.round()}', - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, + debugDisableShadows = false; + try { + final Key sliderKey = UniqueKey(); + double value = 0.0; + + Widget buildSlider({ + required 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, + max: 100.0, + divisions: isDiscrete ? 10 : null, + label: '${value.round()}', + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, + ), ), ), ), ), - ), - ); - }, + ); + }, + ), ), - ), - ); - } + ); + } - await tester.pumpWidget(buildSlider(textScaleFactor: 1.0)); - Offset center = tester.getCenter(find.byType(Slider)); - TestGesture gesture = await tester.startGesture(center); - await tester.pumpAndSettle(); + 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.renderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset.zero, - Offset(0.0, -8.0), - Offset(-276.0, -16.0), - Offset(-216.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ) - ..paragraph(), - ); + expect( + tester.renderObject(find.byType(Overlay)), + paints + ..path( + includes: const [ + Offset.zero, + Offset(0.0, -8.0), + Offset(-276.0, -16.0), + Offset(-216.0, -16.0), + ], + color: const Color(0xf55f5f5f), + ) + ..paragraph(), + ); - await gesture.up(); - await tester.pumpAndSettle(); + 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(); + await tester.pumpWidget(buildSlider(textScaleFactor: 2.0)); + center = tester.getCenter(find.byType(Slider)); + gesture = await tester.startGesture(center); + await tester.pumpAndSettle(); - expect( - tester.renderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset.zero, - Offset(0.0, -8.0), - Offset(-304.0, -16.0), - Offset(-216.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ) - ..paragraph(), - ); + expect( + tester.renderObject(find.byType(Overlay)), + paints + ..path( + includes: const [ + Offset.zero, + Offset(0.0, -8.0), + Offset(-304.0, -16.0), + Offset(-216.0, -16.0), + ], + color: const Color(0xf55f5f5f), + ) + ..paragraph(), + ); - await gesture.up(); - await tester.pumpAndSettle(); + 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(); + // 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.renderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset.zero, - Offset(0.0, -8.0), - Offset(-276.0, -16.0), - Offset(-216.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ) - ..paragraph(), - ); + expect(tester.renderObject(find.byType(Overlay)), + paints + ..path( + includes: const [ + Offset.zero, + Offset(0.0, -8.0), + Offset(-276.0, -16.0), + Offset(-216.0, -16.0), + ], + color: const Color(0xf55f5f5f), + ) + ..paragraph(), + ); - await gesture.up(); - await tester.pumpAndSettle(); + 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(); + 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.renderObject(find.byType(Overlay)), - paints - ..path( - includes: const [ - Offset.zero, - Offset(0.0, -8.0), - Offset(-276.0, -16.0), - Offset(-216.0, -16.0), - ], - color: const Color(0xf55f5f5f), - ) - ..paragraph(), - ); + expect( + tester.renderObject(find.byType(Overlay)), + paints + ..path( + includes: const [ + Offset.zero, + Offset(0.0, -8.0), + Offset(-276.0, -16.0), + Offset(-216.0, -16.0), + ], + color: const Color(0xf55f5f5f), + ) + ..paragraph(), + ); - await gesture.up(); - await tester.pumpAndSettle(); + await gesture.up(); + await tester.pumpAndSettle(); + } finally { + debugDisableShadows = true; + } }); testWidgets('Tick marks are skipped when they are too dense', (WidgetTester tester) async { @@ -2552,7 +2562,7 @@ void main() { ..paragraph(), ); - expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 3)); + expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 4)); expect(valueIndicatorBox, paintsExactlyCountTimes(#drawParagraph, 2)); await tester.tap(find.text('Next')); diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index a03438df2d5b..111da30fef01 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -362,357 +362,367 @@ void main() { }); 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(WidgetsBinding.instance.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) { }, + debugDisableShadows = false; + try { + 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(WidgetsBinding.instance.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.renderObject(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, + paints + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(15.9, -40.0), + const Offset(-15.9, -40.0), + ], + excludes: [const Offset(16.1, -40.0), const Offset(-16.1, -40.0)], + ), ); - } - await tester.pumpWidget(buildApp('1')); - - final RenderBox valueIndicatorBox = tester.renderObject(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, - paints - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(15.9, -40.0), - const Offset(-15.9, -40.0), - ], - excludes: [const Offset(16.1, -40.0), const Offset(-16.1, -40.0)], - ), - ); - - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(35.9, -40.0), - const Offset(-35.9, -40.0), - ], - excludes: [const Offset(36.1, -40.0), const Offset(-36.1, -40.0)], - ), - ); - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(92.0, -40.0), - const Offset(-16.0, -40.0), - ], - excludes: [const Offset(98.1, -40.0), const Offset(-20.1, -40.0)], - ), - ); - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(16.0, -40.0), - const Offset(-92.0, -40.0), - ], - excludes: [const Offset(20.1, -40.0), const Offset(-98.1, -40.0)], - ), - ); - await gesture.up(); - - // Test that the neck stretches 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -49.0), - const Offset(68.0, -49.0), - const Offset(-24.0, -49.0), - ], - excludes: [ - const Offset(98.0, -32.0), // inside full size, outside small - const Offset(-40.0, -32.0), // inside full size, outside small - const Offset(90.1, -49.0), - const Offset(-40.1, -49.0), - ], - ), - ); - await gesture.up(); - - // Test that the neck shrinks when the text scale gets larger. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -38.8), - const Offset(92.0, -38.8), - const Offset(8.0, -23.0), // Inside large, outside scale=1.0 - const Offset(-2.0, -23.0), // Inside large, outside scale=1.0 - ], - excludes: [ - const Offset(98.5, -38.8), - const Offset(-16.1, -38.8), - ], - ), - ); - await gesture.up(); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(35.9, -40.0), + const Offset(-35.9, -40.0), + ], + excludes: [const Offset(36.1, -40.0), const Offset(-36.1, -40.0)], + ), + ); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(92.0, -40.0), + const Offset(-16.0, -40.0), + ], + excludes: [const Offset(98.1, -40.0), const Offset(-20.1, -40.0)], + ), + ); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(16.0, -40.0), + const Offset(-92.0, -40.0), + ], + excludes: [const Offset(20.1, -40.0), const Offset(-98.1, -40.0)], + ), + ); + await gesture.up(); + + // Test that the neck stretches 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -49.0), + const Offset(68.0, -49.0), + const Offset(-24.0, -49.0), + ], + excludes: [ + const Offset(98.0, -32.0), // inside full size, outside small + const Offset(-40.0, -32.0), // inside full size, outside small + const Offset(90.1, -49.0), + const Offset(-40.1, -49.0), + ], + ), + ); + await gesture.up(); + + // Test that the neck shrinks when the text scale gets larger. + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -38.8), + const Offset(92.0, -38.8), + const Offset(8.0, -23.0), // Inside large, outside scale=1.0 + const Offset(-2.0, -23.0), // Inside large, outside scale=1.0 + ], + excludes: [ + const Offset(98.5, -38.8), + const Offset(-16.1, -38.8), + ], + ), + ); + await gesture.up(); + } finally { + debugDisableShadows = true; + } }); 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(WidgetsBinding.instance.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) { }, + debugDisableShadows = false; + try { + 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(WidgetsBinding.instance.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.renderObject(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, + paints + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(15.9, -40.0), + const Offset(-15.9, -40.0), + ], + excludes: [const Offset(16.1, -40.0), const Offset(-16.1, -40.0)], + ), ); - } - - await tester.pumpWidget(buildApp('1')); - - final RenderBox valueIndicatorBox = tester.renderObject(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, - paints - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(15.9, -40.0), - const Offset(-15.9, -40.0), - ], - excludes: [const Offset(16.1, -40.0), const Offset(-16.1, -40.0)], - ), - ); - - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(35.9, -40.0), - const Offset(-35.9, -40.0), - ], - excludes: [const Offset(36.1, -40.0), const Offset(-36.1, -40.0)], - ), - ); - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(92.0, -40.0), - const Offset(-16.0, -40.0), - ], - excludes: [const Offset(98.1, -40.0), const Offset(-20.1, -40.0)], - ), - ); - 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -40.0), - const Offset(16.0, -40.0), - const Offset(-92.0, -40.0), - ], - excludes: [const Offset(20.1, -40.0), const Offset(-98.1, -40.0)], - ), - ); - await gesture.up(); - - // Test that the neck stretches 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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -49.0), - const Offset(68.0, -49.0), - const Offset(-24.0, -49.0), - ], - excludes: [ - const Offset(98.0, -32.0), // inside full size, outside small - const Offset(-40.0, -32.0), // inside full size, outside small - const Offset(90.1, -49.0), - const Offset(-40.1, -49.0), - ], - ), - ); - await gesture.up(); - // Test that the neck shrinks when the text scale gets larger. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.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 - ..path( - color: sliderTheme.valueIndicatorColor, - includes: [ - const Offset(0.0, -38.8), - const Offset(92.0, -38.8), - const Offset(8.0, -23.0), // Inside large, outside scale=1.0 - const Offset(-2.0, -23.0), // Inside large, outside scale=1.0 - ], - excludes: [ - const Offset(98.5, -38.8), - const Offset(-16.1, -38.8), - ], - ), - ); - await gesture.up(); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(35.9, -40.0), + const Offset(-35.9, -40.0), + ], + excludes: [const Offset(36.1, -40.0), const Offset(-36.1, -40.0)], + ), + ); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(92.0, -40.0), + const Offset(-16.0, -40.0), + ], + excludes: [const Offset(98.1, -40.0), const Offset(-20.1, -40.0)], + ), + ); + 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -40.0), + const Offset(16.0, -40.0), + const Offset(-92.0, -40.0), + ], + excludes: [const Offset(20.1, -40.0), const Offset(-98.1, -40.0)], + ), + ); + await gesture.up(); + + // Test that the neck stretches 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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -49.0), + const Offset(68.0, -49.0), + const Offset(-24.0, -49.0), + ], + excludes: [ + const Offset(98.0, -32.0), // inside full size, outside small + const Offset(-40.0, -32.0), // inside full size, outside small + const Offset(90.1, -49.0), + const Offset(-40.1, -49.0), + ], + ), + ); + await gesture.up(); + + // Test that the neck shrinks when the text scale gets larger. + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.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 + ..path( + color: sliderTheme.valueIndicatorColor, + includes: [ + const Offset(0.0, -38.8), + const Offset(92.0, -38.8), + const Offset(8.0, -23.0), // Inside large, outside scale=1.0 + const Offset(-2.0, -23.0), // Inside large, outside scale=1.0 + ], + excludes: [ + const Offset(98.5, -38.8), + const Offset(-16.1, -38.8), + ], + ), + ); + await gesture.up(); + } finally { + debugDisableShadows = true; + } }); testWidgets('The slider track height can be overridden', (WidgetTester tester) async { @@ -967,24 +977,29 @@ void main() { }); testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { - // Pump a slider with just a thumb. - await tester.pumpWidget(_buildApp( - ThemeData().sliderTheme.copyWith( - trackHeight: 0, - overlayShape: SliderComponentShape.noOverlay, - tickMarkShape: SliderTickMarkShape.noTickMark, - showValueIndicator: ShowValueIndicator.never, - ), - value: 0.5, - divisions: 4, - )); - - final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; - - // Only 1 thumb. - expect(material, paintsExactlyCountTimes(#drawRect, 0)); - expect(material, paintsExactlyCountTimes(#drawCircle, 1)); - expect(material, paintsExactlyCountTimes(#drawPath, 0)); + debugDisableShadows = false; + try { + // Pump a slider with just a thumb. + await tester.pumpWidget(_buildApp( + ThemeData().sliderTheme.copyWith( + trackHeight: 0, + overlayShape: SliderComponentShape.noOverlay, + tickMarkShape: SliderTickMarkShape.noTickMark, + showValueIndicator: ShowValueIndicator.never, + ), + value: 0.5, + divisions: 4, + )); + + final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; + + // Only 1 thumb. + expect(material, paintsExactlyCountTimes(#drawRect, 0)); + expect(material, paintsExactlyCountTimes(#drawCircle, 1)); + expect(material, paintsExactlyCountTimes(#drawPath, 0)); + } finally { + debugDisableShadows = true; + } }); testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { @@ -1113,6 +1128,57 @@ void main() { testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + debugDisableShadows = false; + try { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + primarySwatch: Colors.blue, + ); + final SliderThemeData sliderTheme = theme.sliderTheme.copyWith( + thumbColor: Colors.red.shade500, + showValueIndicator: ShowValueIndicator.always, + rangeValueIndicatorShape: const PaddleRangeSliderValueIndicatorShape(), + ); + + await tester.pumpWidget(_buildRangeApp(sliderTheme)); + + final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay)); + + final Offset center = tester.getCenter(find.byType(RangeSlider)); + final TestGesture gesture = await tester.startGesture(center); + // Wait for value indicator animation to finish. + await tester.pumpAndSettle(); + expect( + valueIndicatorBox, + paints + // physical model + ..rrect() + ..rrect(rrect: RRect.fromLTRBAndCorners( + 24.0, 298.0, 24.0, 302.0, + topLeft: const Radius.circular(2.0), + bottomLeft: const Radius.circular(2.0), + )) + ..rect(rect: const Rect.fromLTRB(24.0, 297.0, 24.0, 303.0)) + ..rrect(rrect: RRect.fromLTRBAndCorners( + 24.0, 298.0, 776.0, 302.0, + topRight: const Radius.circular(2.0), + bottomRight: const Radius.circular(2.0), + )) + ..circle(x: 24.0, y: 300.0) + ..shadow(elevation: 1.0) + ..circle(x: 24.0, y: 300.0) + ..shadow(elevation: 6.0) + ..circle(x: 24.0, y: 300.0), + ); + + await gesture.up(); + } finally { + debugDisableShadows = true; + } + }); + + testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -1148,74 +1214,83 @@ void main() { bottomRight: const Radius.circular(2.0), )) ..circle(x: 24.0, y: 300.0) - ..shadow(elevation: 1.0) + ..path(strokeWidth: 1.0 * 2.0, color: Colors.black) ..circle(x: 24.0, y: 300.0) - ..shadow(elevation: 6.0) + ..path(strokeWidth: 6.0 * 2.0, color: Colors.black) ..circle(x: 24.0, y: 300.0), ); 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, - )); + debugDisableShadows = false; + try { + // 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.renderObject(find.byType(Overlay)); + // final RenderBox sliderBox = tester.firstRenderObject(find.byType(RangeSlider)); + final RenderBox valueIndicatorBox = tester.renderObject(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); + // 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)); + // 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)); + // Painting a path for each value indicator. + await tester.pump(const Duration(milliseconds: 16)); + expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 2)); - await gesture.up(); + await gesture.up(); + } finally { + debugDisableShadows = true; + } }); 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( - ThemeData().sliderTheme.copyWith( - trackHeight: 0, - overlayShape: SliderComponentShape.noOverlay, - thumbShape: SliderComponentShape.noThumb, - tickMarkShape: SliderTickMarkShape.noTickMark, - showValueIndicator: ShowValueIndicator.always, - ), - values: const RangeValues(0, 0.5), - divisions: 4, - )); + debugDisableShadows = false; + try { + // Pump a slider with just a value indicator. + await tester.pumpWidget(_buildRangeApp( + ThemeData().sliderTheme.copyWith( + trackHeight: 0, + overlayShape: SliderComponentShape.noOverlay, + thumbShape: SliderComponentShape.noThumb, + tickMarkShape: SliderTickMarkShape.noTickMark, + showValueIndicator: ShowValueIndicator.always, + ), + values: const RangeValues(0, 0.5), + divisions: 4, + )); - final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay)); + final RenderBox valueIndicatorBox = tester.renderObject(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); + // 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)); + // 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)); + // Painting a path for each value indicator. + await tester.pump(const Duration(milliseconds: 16)); + expect(valueIndicatorBox, paintsExactlyCountTimes(#drawPath, 2)); - await gesture.up(); + await gesture.up(); + } finally { + debugDisableShadows = true; + } }); testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async {