Commit 4a18cbdf authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add RTL support to progress indicators (#11840)

Fixes #11374
parent d4e52ccb
......@@ -73,12 +73,14 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
this.valueColor,
this.value,
this.animationValue,
});
@required this.textDirection,
}) : assert(textDirection != null);
final Color backgroundColor;
final Color valueColor;
final double value;
final double animationValue;
final TextDirection textDirection;
@override
void paint(Canvas canvas, Size size) {
......@@ -90,13 +92,35 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
paint.color = valueColor;
if (value != null) {
final double width = value.clamp(0.0, 1.0) * size.width;
canvas.drawRect(Offset.zero & new Size(width, size.height), paint);
double left;
switch (textDirection) {
case TextDirection.rtl:
left = size.width - width;
break;
case TextDirection.ltr:
left = 0.0;
break;
}
canvas.drawRect(new Offset(left, 0.0) & new Size(width, size.height), paint);
} else {
final double startX = size.width * (1.5 * animationValue - 0.5);
final double endX = startX + 0.5 * size.width;
final double x = startX.clamp(0.0, size.width);
final double width = endX.clamp(0.0, size.width) - x;
canvas.drawRect(new Offset(x, 0.0) & new Size(width, size.height), paint);
double left;
switch (textDirection) {
case TextDirection.rtl:
left = size.width - width - x;
break;
case TextDirection.ltr:
left = x;
break;
}
canvas.drawRect(new Offset(left, 0.0) & new Size(width, size.height), paint);
}
}
......@@ -105,7 +129,8 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
return oldPainter.backgroundColor != backgroundColor
|| oldPainter.valueColor != valueColor
|| oldPainter.value != value
|| oldPainter.animationValue != animationValue;
|| oldPainter.animationValue != animationValue
|| oldPainter.textDirection != textDirection;
}
}
......@@ -152,8 +177,20 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
_controller = new AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
)..repeat();
);
_animation = new CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn);
if (widget.value == null)
_controller.repeat();
}
@override
void didUpdateWidget(LinearProgressIndicator oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.value == null && !_controller.isAnimating)
_controller.repeat();
else if (widget.value != null && _controller.isAnimating)
_controller.stop();
}
@override
......@@ -162,7 +199,7 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
super.dispose();
}
Widget _buildIndicator(BuildContext context, double animationValue) {
Widget _buildIndicator(BuildContext context, double animationValue, TextDirection textDirection) {
return new Container(
constraints: const BoxConstraints.tightFor(
width: double.INFINITY,
......@@ -174,6 +211,7 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
valueColor: widget._getValueColor(context),
value: widget.value, // may be null
animationValue: animationValue, // ignored if widget.value is not null
textDirection: textDirection,
),
),
);
......@@ -181,13 +219,15 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
@override
Widget build(BuildContext context) {
final TextDirection textDirection = Directionality.of(context);
if (widget.value != null)
return _buildIndicator(context, _animation.value);
return _buildIndicator(context, _animation.value, textDirection);
return new AnimatedBuilder(
animation: _animation,
builder: (BuildContext context, Widget child) {
return _buildIndicator(context, _animation.value);
return _buildIndicator(context, _animation.value, textDirection);
},
);
}
......
......@@ -15,26 +15,134 @@ void main() {
testWidgets('LinearProgressIndicator(value: 0.0) can be constructed', (WidgetTester tester) async {
await tester.pumpWidget(
const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: 0.0)
)
)
const Directionality(
textDirection: TextDirection.ltr,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: 0.0),
),
),
),
);
});
testWidgets('LinearProgressIndicator(value: null) can be constructed', (WidgetTester tester) async {
await tester.pumpWidget(
const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: null)
)
)
const Directionality(
textDirection: TextDirection.rtl,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: null),
),
),
),
);
});
testWidgets('LinearProgressIndicator paint (LTR)', (WidgetTester tester) async {
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: 0.25),
),
),
),
);
expect(
find.byType(LinearProgressIndicator),
paints
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 200.0, 6.0))
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 50.0, 6.0))
);
expect(tester.binding.transientCallbackCount, 0);
});
testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async {
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.rtl,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(value: 0.25),
),
),
),
);
expect(
find.byType(LinearProgressIndicator),
paints
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 200.0, 6.0))
..rect(rect: new Rect.fromLTRB(150.0, 0.0, 200.0, 6.0))
);
expect(tester.binding.transientCallbackCount, 0);
});
testWidgets('LinearProgressIndicator indeterminate (LTR)', (WidgetTester tester) async {
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(),
),
),
),
);
await tester.pump(const Duration(milliseconds: 750));
final double animationValue = Curves.fastOutSlowIn.transform(0.5);
final double startX = 200.0 * (1.5 * animationValue - 0.5);
expect(
find.byType(LinearProgressIndicator),
paints
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 200.0, 6.0))
..rect(rect: new Rect.fromLTRB(startX, 0.0, 200.0, 6.0))
);
expect(tester.binding.transientCallbackCount, 1);
});
testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async {
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.rtl,
child: const Center(
child: const SizedBox(
width: 200.0,
child: const LinearProgressIndicator(),
),
),
),
);
await tester.pump(const Duration(milliseconds: 750));
final double animationValue = Curves.fastOutSlowIn.transform(0.5);
final double startX = 200.0 * (1.5 * animationValue - 0.5);
expect(
find.byType(LinearProgressIndicator),
paints
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 200.0, 6.0))
..rect(rect: new Rect.fromLTRB(0.0, 0.0, 200.0 - startX, 6.0))
);
expect(tester.binding.transientCallbackCount, 1);
});
testWidgets('CircularProgressIndicator(value: 0.0) can be constructed', (WidgetTester tester) async {
await tester.pumpWidget(
const Center(
......@@ -52,9 +160,15 @@ void main() {
});
testWidgets('LinearProgressIndicator causes a repaint when it changes', (WidgetTester tester) async {
await tester.pumpWidget(new ListView(children: <Widget>[const LinearProgressIndicator(value: 0.0)]));
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: <Widget>[const LinearProgressIndicator(value: 0.0)]),
));
final List<Layer> layers1 = tester.layers;
await tester.pumpWidget(new ListView(children: <Widget>[const LinearProgressIndicator(value: 0.5)]));
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: <Widget>[const LinearProgressIndicator(value: 0.5)])),
);
final List<Layer> layers2 = tester.layers;
expect(layers1, isNot(equals(layers2)));
});
......
......@@ -9,7 +9,7 @@ void main() {
testWidgets('TickerMode', (WidgetTester tester) async {
final Widget widget = const TickerMode(
enabled: false,
child: const LinearProgressIndicator()
child: const CircularProgressIndicator()
);
expect(widget.toString, isNot(throwsException));
......@@ -19,14 +19,14 @@ void main() {
await tester.pumpWidget(const TickerMode(
enabled: true,
child: const LinearProgressIndicator()
child: const CircularProgressIndicator()
));
expect(tester.binding.transientCallbackCount, 1);
await tester.pumpWidget(const TickerMode(
enabled: false,
child: const LinearProgressIndicator()
child: const CircularProgressIndicator()
));
expect(tester.binding.transientCallbackCount, 0);
......
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