diff --git a/packages/flutter/lib/src/material/progress_indicator.dart b/packages/flutter/lib/src/material/progress_indicator.dart index a3074f58d6..d99681bd9d 100644 --- a/packages/flutter/lib/src/material/progress_indicator.dart +++ b/packages/flutter/lib/src/material/progress_indicator.dart @@ -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 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 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 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 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); }, ); } diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 139103ab1d..1bedc24bf9 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -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: [const LinearProgressIndicator(value: 0.0)])); + await tester.pumpWidget(new Directionality( + textDirection: TextDirection.ltr, + child: new ListView(children: [const LinearProgressIndicator(value: 0.0)]), + )); final List layers1 = tester.layers; - await tester.pumpWidget(new ListView(children: [const LinearProgressIndicator(value: 0.5)])); + await tester.pumpWidget(new Directionality( + textDirection: TextDirection.ltr, + child: new ListView(children: [const LinearProgressIndicator(value: 0.5)])), + ); final List layers2 = tester.layers; expect(layers1, isNot(equals(layers2))); }); diff --git a/packages/flutter/test/widgets/ticker_provider_test.dart b/packages/flutter/test/widgets/ticker_provider_test.dart index ff273917a3..67991c5f0b 100644 --- a/packages/flutter/test/widgets/ticker_provider_test.dart +++ b/packages/flutter/test/widgets/ticker_provider_test.dart @@ -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);