Unverified Commit 4e3f4bb6 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Migrated the Slider widget and tests to null safety. (#68232)

parent 5aef988a
......@@ -1317,6 +1317,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
final bool startThumbSelected = _lastThumbSelection == Thumb.start;
final bool endThumbSelected = _lastThumbSelection == Thumb.end;
final Size resolvedscreenSize = screenSize.isEmpty ? size : screenSize;
if (!_overlayAnimation.isDismissed) {
if (startThumbSelected) {
......@@ -1331,6 +1332,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: startValue,
textScaleFactor: _textScaleFactor,
sizeWithOverflow: resolvedscreenSize,
);
}
if (endThumbSelected) {
......@@ -1345,6 +1348,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: endValue,
textScaleFactor: _textScaleFactor,
sizeWithOverflow: resolvedscreenSize,
);
}
}
......@@ -1392,7 +1397,6 @@ 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) {
......
......@@ -1385,6 +1385,8 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: _value,
textScaleFactor: _textScaleFactor,
sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
);
}
......@@ -1451,8 +1453,9 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
parentBox: this,
sliderTheme: _sliderTheme,
textDirection: _textDirection,
sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
value: _value,
textScaleFactor: textScaleFactor,
sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
);
}
......
......@@ -870,14 +870,14 @@ abstract class SliderComponentShape {
Offset center, {
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
bool isDiscrete,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
double textScaleFactor,
Size sizeWithOverflow,
required double textScaleFactor,
required Size sizeWithOverflow,
});
/// Special instance of [SliderComponentShape] to skip the thumb drawing.
......@@ -927,7 +927,7 @@ abstract class SliderTickMarkShape {
/// {@endtemplate}
Size getPreferredSize({
required SliderThemeData sliderTheme,
bool isEnabled,
required bool isEnabled,
});
/// Paints the slider track.
......@@ -958,7 +958,7 @@ abstract class SliderTickMarkShape {
required SliderThemeData sliderTheme,
required Animation<double> enableAnimation,
required Offset thumbCenter,
bool isEnabled,
required bool isEnabled,
required TextDirection textDirection,
});
......@@ -2012,7 +2012,7 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape {
@override
Size getPreferredSize({
required SliderThemeData sliderTheme,
bool isEnabled = false,
required bool isEnabled,
}) {
assert(sliderTheme != null);
assert(sliderTheme.trackHeight != null);
......@@ -2032,7 +2032,7 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape {
required Animation<double> enableAnimation,
required TextDirection textDirection,
required Offset thumbCenter,
bool isEnabled = false,
required bool isEnabled,
}) {
assert(context != null);
assert(center != null);
......@@ -2178,8 +2178,8 @@ class RoundRangeSliderTickMarkShape extends RangeSliderTickMarkShape {
class _EmptySliderTickMarkShape extends SliderTickMarkShape {
@override
Size getPreferredSize({
SliderThemeData? sliderTheme,
bool? isEnabled,
required SliderThemeData sliderTheme,
required bool isEnabled,
}) {
return Size.zero;
}
......@@ -2192,7 +2192,7 @@ class _EmptySliderTickMarkShape extends SliderTickMarkShape {
required SliderThemeData sliderTheme,
required Animation<double> enableAnimation,
required Offset thumbCenter,
bool? isEnabled,
required bool isEnabled,
required TextDirection textDirection,
}) {
// no-op.
......@@ -2216,16 +2216,16 @@ class _EmptySliderComponentShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
Animation<double>? enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
RenderBox? parentBox,
SliderThemeData? sliderTheme,
TextDirection? textDirection,
double? value,
double? textScaleFactor,
Size? sizeWithOverflow,
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
// no-op.
}
......@@ -2290,16 +2290,16 @@ class RoundSliderThumbShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
RenderBox? parentBox,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
TextDirection? textDirection,
double? value,
double? textScaleFactor,
Size? sizeWithOverflow,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
assert(context != null);
assert(center != null);
......@@ -2326,7 +2326,7 @@ class RoundSliderThumbShape extends SliderComponentShape {
end: pressedElevation,
);
final double evaluatedElevation = elevationTween.evaluate(activationAnimation!);
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);
......@@ -2484,14 +2484,14 @@ class RoundSliderOverlayShape extends SliderComponentShape {
Offset center, {
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
bool isDiscrete = false,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
double? textScaleFactor,
Size? sizeWithOverflow,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
assert(context != null);
assert(center != null);
......@@ -2549,28 +2549,28 @@ class RectangularSliderValueIndicatorShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
Animation<double>? enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
SliderThemeData? sliderTheme,
TextDirection? textDirection,
double? value,
double? textScaleFactor,
Size? sizeWithOverflow,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
final Canvas canvas = context.canvas;
final double scale = activationAnimation!.value;
final double scale = activationAnimation.value;
_pathPainter.paint(
parentBox: parentBox,
canvas: canvas,
center: center,
scale: scale,
labelPainter: labelPainter!,
textScaleFactor: textScaleFactor!,
sizeWithOverflow: sizeWithOverflow!,
backgroundPaintColor: sliderTheme!.valueIndicatorColor!);
labelPainter: labelPainter,
textScaleFactor: textScaleFactor,
sizeWithOverflow: sizeWithOverflow,
backgroundPaintColor: sliderTheme.valueIndicatorColor!);
}
}
......@@ -2815,16 +2815,16 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
Animation<double>? enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
RenderBox? parentBox,
SliderThemeData? sliderTheme,
TextDirection? textDirection,
double? value,
double? textScaleFactor,
Size? sizeWithOverflow,
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
assert(context != null);
assert(center != null);
......@@ -2833,19 +2833,19 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
assert(labelPainter != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(!sizeWithOverflow!.isEmpty);
assert(!sizeWithOverflow.isEmpty);
final ColorTween enableColor = ColorTween(
begin: sliderTheme!.disabledThumbColor,
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.valueIndicatorColor,
);
_pathPainter.paint(
context.canvas,
center,
Paint()..color = enableColor.evaluate(enableAnimation!)!,
activationAnimation!.value,
labelPainter!,
textScaleFactor!,
sizeWithOverflow!,
Paint()..color = enableColor.evaluate(enableAnimation)!,
activationAnimation.value,
labelPainter,
textScaleFactor,
sizeWithOverflow,
null,
);
}
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:ui';
import 'package:flutter/cupertino.dart';
......@@ -33,18 +31,16 @@ class LoggingThumbShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset thumbCenter, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isEnabled,
bool isDiscrete,
bool onActiveTrack,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
double textScaleFactor,
Size sizeWithOverflow,
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
log.add(thumbCenter);
final Paint thumbPaint = Paint()..color = Colors.red;
......@@ -54,7 +50,7 @@ class LoggingThumbShape extends SliderComponentShape {
class TallSliderTickMarkShape extends SliderTickMarkShape {
@override
Size getPreferredSize({SliderThemeData sliderTheme, bool isEnabled}) {
Size getPreferredSize({required SliderThemeData sliderTheme, required bool isEnabled}) {
return const Size(10.0, 200.0);
}
......@@ -62,12 +58,12 @@ class TallSliderTickMarkShape extends SliderTickMarkShape {
void paint(
PaintingContext context,
Offset offset, {
Offset thumbCenter,
RenderBox parentBox,
SliderThemeData sliderTheme,
Animation<double> enableAnimation,
bool isEnabled,
TextDirection textDirection,
required Offset thumbCenter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required Animation<double> enableAnimation,
required bool isEnabled,
required TextDirection textDirection,
}) {
final Paint paint = Paint()..color = Colors.red;
context.canvas.drawRect(Rect.fromLTWH(offset.dx, offset.dy, 10.0, 20.0), paint);
......@@ -78,8 +74,8 @@ void main() {
testWidgets('Slider can move when tapped (LTR)', (WidgetTester tester) async {
final Key sliderKey = UniqueKey();
double value = 0.0;
double startValue;
double endValue;
double? startValue;
double? endValue;
await tester.pumpWidget(
MaterialApp(
......@@ -123,7 +119,7 @@ void main() {
startValue = null;
endValue = null;
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));
......@@ -134,7 +130,7 @@ void main() {
expect(startValue, equals(0.5));
expect(endValue, moreOrLessEquals(0.25, epsilon: 0.05));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
});
testWidgets('Slider can move when tapped (RTL)', (WidgetTester tester) async {
......@@ -173,7 +169,7 @@ void main() {
await tester.tap(find.byKey(sliderKey));
expect(value, equals(0.5));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));
......@@ -182,14 +178,14 @@ void main() {
await tester.tapAt(target);
expect(value, moreOrLessEquals(0.75, epsilon: 0.05));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
});
testWidgets("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async {
final Key sliderKey = UniqueKey();
double value = 0.0;
double startValue;
double endValue;
late double startValue;
late double endValue;
int updates = 0;
int startValueUpdates = 0;
int endValueUpdates = 0;
......@@ -284,19 +280,19 @@ void main() {
expect(value, equals(0.5));
await tester.pump(const Duration(milliseconds: 100));
// Starts with the position animation and value indicator
expect(SchedulerBinding.instance.transientCallbackCount, equals(2));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(2));
await tester.pump(const Duration(milliseconds: 100));
// Value indicator is longer than position.
expect(SchedulerBinding.instance.transientCallbackCount, equals(1));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(1));
await tester.pump(const Duration(milliseconds: 100));
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
await tester.pump(const Duration(milliseconds: 100));
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
await tester.pump(const Duration(milliseconds: 100));
// Shown for long enough, value indicator is animated closed.
expect(SchedulerBinding.instance.transientCallbackCount, equals(1));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(1));
await tester.pump(const Duration(milliseconds: 101));
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
});
testWidgets('Discrete Slider repaints and animates when dragged', (WidgetTester tester) async {
......@@ -532,13 +528,13 @@ void main() {
expect(value, equals(80.0));
await tester.pump(); // Starts animation.
expect(SchedulerBinding.instance.transientCallbackCount, greaterThan(0));
expect(SchedulerBinding.instance!.transientCallbackCount, greaterThan(0));
await tester.pump(const Duration(milliseconds: 200));
await tester.pump(const Duration(milliseconds: 200));
await tester.pump(const Duration(milliseconds: 200));
await tester.pump(const Duration(milliseconds: 200));
// Animation complete.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
});
testWidgets('Slider can be given zero values', (WidgetTester tester) async {
......@@ -618,12 +614,12 @@ void main() {
final SliderThemeData sliderTheme = theme.sliderTheme;
double value = 0.45;
Widget buildApp({
Color activeColor,
Color inactiveColor,
int divisions,
Color? activeColor,
Color? inactiveColor,
int? divisions,
bool enabled = true,
}) {
final ValueChanged<double> onChanged = !enabled
final ValueChanged<double>? onChanged = !enabled
? null
: (double d) {
value = d;
......@@ -655,7 +651,7 @@ void main() {
await tester.pumpWidget(buildApp());
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
// Check default theme for enabled widget.
......@@ -982,7 +978,7 @@ void main() {
double value = 0.0;
Widget buildSlider({
double textScaleFactor,
required double textScaleFactor,
bool isDiscrete = true,
ShowValueIndicator show = ShowValueIndicator.onlyForDiscrete,
}) {
......@@ -995,8 +991,8 @@ void main() {
data: MediaQueryData(textScaleFactor: textScaleFactor),
child: Material(
child: Theme(
data: Theme.of(context).copyWith(
sliderTheme: Theme.of(context).sliderTheme.copyWith(showValueIndicator: show),
data: Theme.of(context)!.copyWith(
sliderTheme: Theme.of(context)!.sliderTheme.copyWith(showValueIndicator: show),
),
child: Center(
child: OverflowBox(
......@@ -1129,7 +1125,7 @@ void main() {
testWidgets('Tick marks are skipped when they are too dense', (WidgetTester tester) async {
Widget buildSlider({
int divisions,
required int divisions,
}) {
return MaterialApp(
home: Directionality(
......@@ -1160,7 +1156,7 @@ void main() {
),
);
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
// 5 tick marks and a thumb.
expect(material, paintsExactlyCountTimes(#drawCircle, 6));
......@@ -1219,14 +1215,14 @@ void main() {
}
Future<void> testReparenting(bool reparent) async {
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
final MaterialInkController material = Material.of(tester.element(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(SchedulerBinding.instance!.transientCallbackCount, equals(0));
expect(
material,
paints
......@@ -1242,7 +1238,7 @@ void main() {
await tester.pump();
// Wait for animations to start.
await tester.pump(const Duration(milliseconds: 25));
expect(SchedulerBinding.instance.transientCallbackCount, equals(2));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(2));
expect(
material,
paints
......@@ -1262,7 +1258,7 @@ void main() {
// Move a little further in the animations.
await tester.pump(const Duration(milliseconds: 10));
expect(SchedulerBinding.instance.transientCallbackCount, equals(2));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(2));
expect(
material,
paints
......@@ -1276,7 +1272,7 @@ void main() {
);
// Wait for animations to finish.
await tester.pumpAndSettle();
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
expect(
material,
paints
......@@ -1290,7 +1286,7 @@ void main() {
);
await gesture.up();
await tester.pumpAndSettle();
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
expect(SchedulerBinding.instance!.transientCallbackCount, equals(0));
expect(
material,
paints
......@@ -1933,8 +1929,8 @@ void main() {
);
SliderThemeData theme = baseTheme.sliderTheme;
double value = 0.45;
Widget buildApp({ SliderThemeData sliderTheme, int divisions, bool enabled = true }) {
final ValueChanged<double> onChanged = enabled ? (double d) => value = d : null;
Widget buildApp({ required SliderThemeData sliderTheme, int? divisions, bool enabled = true }) {
final ValueChanged<double>? onChanged = enabled ? (double d) => value = d : null;
return MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
......@@ -1962,9 +1958,9 @@ void main() {
}
Future<void> expectValueIndicator({
bool isVisible,
SliderThemeData theme,
int divisions,
required bool isVisible,
required SliderThemeData theme,
int? divisions,
bool enabled = true,
}) async {
// Discrete enabled widget.
......@@ -2062,9 +2058,7 @@ void main() {
double value = 0.0;
Widget buildApp({
Color activeColor,
Color inactiveColor,
int divisions,
int? divisions,
bool enabled = true,
}) {
return MaterialApp(
......@@ -2090,12 +2084,12 @@ void main() {
ElevatedButton(
child: const Text('Next'),
onPressed: () {
Navigator.of(context).pushReplacement(
Navigator.of(context)!.pushReplacement(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return ElevatedButton(
child: const Text('Inner page'),
onPressed: () { Navigator.of(context).pop(); },
onPressed: () { Navigator.of(context)!.pop(); },
);
},
),
......@@ -2280,7 +2274,7 @@ void main() {
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
// Test Slider.adaptive() constructor
await tester.pumpWidget(
......@@ -2303,7 +2297,7 @@ void main() {
)
);
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
// Test default cursor
await tester.pumpWidget(
......@@ -2325,7 +2319,7 @@ void main() {
)
);
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
});
testWidgets('Slider implements debugFillProperties', (WidgetTester tester) async {
......@@ -2459,7 +2453,7 @@ void main() {
await tester.pumpWidget(buildFrame(15));
await tester.pumpAndSettle(); // Finish the animation.
RRect activeTrackRRect;
late RRect activeTrackRRect;
expect(renderObject, paints..something((Symbol method, List<dynamic> arguments) {
if (method != #drawRRect)
return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment