From f6353b686d45db642161bc4c364d84d511846185 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Tue, 30 Aug 2016 08:51:28 -0700 Subject: [PATCH] Image should handle InheritedWidget ancestor changes (#5656) --- packages/flutter/lib/src/widgets/image.dart | 15 ++- packages/flutter/test/widget/image_test.dart | 130 +++++++++++++++++++ 2 files changed, 139 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 21ba912f3a..0c303992d8 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -193,6 +193,15 @@ class _ImageState extends State { _resolveImage(); } + @override + void deactivate() { + // If this image is activated again then force _imageStream to be recreated, + // in case the InheritedWidget ancestors it depends on have changed. + _imageStream?.removeListener(_handleImageChanged); + _imageStream = null; + super.deactivate(); + } + @override void dependenciesChanged() { _resolveImage(); @@ -205,12 +214,6 @@ class _ImageState extends State { super.reassemble(); } - @override - void dispose() { - _imageStream.removeListener(_handleImageChanged); - super.dispose(); - } - void _resolveImage() { final ImageStream oldImageStream = _imageStream; _imageStream = config.image.resolve(createLocalImageConfiguration( diff --git a/packages/flutter/test/widget/image_test.dart b/packages/flutter/test/widget/image_test.dart index 73f5e1fc84..698e2de8e6 100644 --- a/packages/flutter/test/widget/image_test.dart +++ b/packages/flutter/test/widget/image_test.dart @@ -163,16 +163,146 @@ void main() { expect(renderImage.image, isNotNull); }); + testWidgets('Verify ImageProvider configuration inheritance', (WidgetTester tester) async { + final GlobalKey mediaQueryKey1 = new GlobalKey(debugLabel: 'mediaQueryKey1'); + final GlobalKey mediaQueryKey2 = new GlobalKey(debugLabel: 'mediaQueryKey2'); + final GlobalKey imageKey = new GlobalKey(debugLabel: 'image'); + final TestImageProvider imageProvider = new TestImageProvider(); + + // Of the two nested MediaQuery objects, the innermost one, + // mediaQuery2, should define the configuration of the imageProvider. + await tester.pumpWidget( + new MediaQuery( + key: mediaQueryKey1, + data: new MediaQueryData( + devicePixelRatio: 10.0, + padding: EdgeInsets.zero, + ), + child: new MediaQuery( + key: mediaQueryKey2, + data: new MediaQueryData( + devicePixelRatio: 5.0, + padding: EdgeInsets.zero, + ), + child: new Image( + key: imageKey, + image: imageProvider + ), + ) + ) + ); + + expect(imageProvider._configuration.devicePixelRatio, 5.0); + + // This is the same widget hierarchy as before except that the + // two MediaQuery objects have exchanged places. The imageProvider + // should be resolved again, with the new innermost MediaQuery. + await tester.pumpWidget( + new MediaQuery( + key: mediaQueryKey2, + data: new MediaQueryData( + devicePixelRatio: 5.0, + padding: EdgeInsets.zero, + ), + child: new MediaQuery( + key: mediaQueryKey1, + data: new MediaQueryData( + devicePixelRatio: 10.0, + padding: EdgeInsets.zero, + ), + child: new Image( + key: imageKey, + image: imageProvider + ), + ) + ) + ); + + expect(imageProvider._configuration.devicePixelRatio, 10.0); + }); + + testWidgets('Verify ImageProvider configuration inheritance again', (WidgetTester tester) async { + final GlobalKey mediaQueryKey1 = new GlobalKey(debugLabel: 'mediaQueryKey1'); + final GlobalKey mediaQueryKey2 = new GlobalKey(debugLabel: 'mediaQueryKey2'); + final GlobalKey imageKey = new GlobalKey(debugLabel: 'image'); + final TestImageProvider imageProvider = new TestImageProvider(); + + // This is just a variation on the previous test. In this version the location + // of the Image changes and the MediaQuery widgets do not. + await tester.pumpWidget( + new Row( + children: [ + new MediaQuery( + key: mediaQueryKey2, + data: new MediaQueryData( + devicePixelRatio: 5.0, + padding: EdgeInsets.zero, + ), + child: new Image( + key: imageKey, + image: imageProvider + ) + ), + new MediaQuery( + key: mediaQueryKey1, + data: new MediaQueryData( + devicePixelRatio: 10.0, + padding: EdgeInsets.zero, + ), + child: new Container(width: 100.0) + ) + ] + ) + ); + + expect(imageProvider._configuration.devicePixelRatio, 5.0); + + await tester.pumpWidget( + new Row( + children: [ + new MediaQuery( + key: mediaQueryKey2, + data: new MediaQueryData( + devicePixelRatio: 5.0, + padding: EdgeInsets.zero, + ), + child: new Container(width: 100.0) + ), + new MediaQuery( + key: mediaQueryKey1, + data: new MediaQueryData( + devicePixelRatio: 10.0, + padding: EdgeInsets.zero, + ), + child: new Image( + key: imageKey, + image: imageProvider + ) + ) + ] + ) + ); + + expect(imageProvider._configuration.devicePixelRatio, 10.0); + }); + } class TestImageProvider extends ImageProvider { final Completer _completer = new Completer(); + ImageConfiguration _configuration; @override Future obtainKey(ImageConfiguration configuration) { return new SynchronousFuture(this); } + @override + ImageStream resolve(ImageConfiguration configuration) { + _configuration = configuration; + return super.resolve(configuration); + } + @override ImageStreamCompleter load(TestImageProvider key) => new OneFrameImageStreamCompleter(_completer.future);