Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions third_party/packages/flutter_svg/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.3.0

* Adds an `imageBuilder` property to `SvgPicture` for wrapping the loaded SVG
widget.

## 2.2.4

* Updates README with example to scale SVG without losing quality
Expand Down
19 changes: 19 additions & 0 deletions third_party/packages/flutter_svg/lib/svg.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export 'src/loaders.dart';
typedef SvgErrorWidgetBuilder =
Widget Function(BuildContext context, Object error, StackTrace stackTrace);

/// Builder function to wrap the successfully loaded SVG widget.
typedef SvgImageWidgetBuilder =
Widget Function(BuildContext context, Widget child);

/// Instance for [Svg]'s utility methods, which can produce a [DrawableRoot]
/// or [PictureInfo] from [String] or [Uint8List].
final Svg svg = Svg._();
Expand Down Expand Up @@ -92,6 +96,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
@Deprecated(
'No code should use this parameter. It never was implemented properly. '
'The SVG theme must be set on the bytesLoader.',
Expand Down Expand Up @@ -193,6 +198,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
SvgTheme? theme,
ColorMapper? colorMapper,
ui.ColorFilter? colorFilter,
Expand Down Expand Up @@ -261,6 +267,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
@Deprecated('This no longer does anything.') bool cacheColorFilter = false,
SvgTheme? theme,
ColorMapper? colorMapper,
Expand Down Expand Up @@ -323,6 +330,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
SvgTheme? theme,
ColorMapper? colorMapper,
@Deprecated('This no longer does anything.') bool cacheColorFilter = false,
Expand Down Expand Up @@ -379,6 +387,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
SvgTheme? theme,
ColorMapper? colorMapper,
@Deprecated('This no longer does anything.') bool cacheColorFilter = false,
Expand Down Expand Up @@ -435,6 +444,7 @@ class SvgPicture extends StatelessWidget {
this.excludeFromSemantics = false,
this.clipBehavior = Clip.hardEdge,
this.errorBuilder,
this.imageBuilder,
SvgTheme? theme,
ColorMapper? colorMapper,
@Deprecated('This no longer does anything.') bool cacheColorFilter = false,
Expand Down Expand Up @@ -528,6 +538,14 @@ class SvgPicture extends StatelessWidget {
/// Widget displayed while the target image failed loading.
final SvgErrorWidgetBuilder? errorBuilder;

/// A builder that wraps the successfully loaded SVG widget.
///
/// This builder is only called when the SVG has been successfully parsed and
/// is ready to be painted. It can be used to apply decorations such as
/// borders or shadows only when the image is available, without affecting the
/// placeholder or error states.
final SvgImageWidgetBuilder? imageBuilder;

/// The color filter, if any, to apply to this widget.
final ColorFilter? colorFilter;

Expand All @@ -551,6 +569,7 @@ class SvgPicture extends StatelessWidget {
excludeFromSemantics: excludeFromSemantics,
clipBehavior: clipBehavior,
errorBuilder: errorBuilder,
imageBuilder: imageBuilder,
colorFilter: colorFilter,
placeholderBuilder: placeholderBuilder,
strategy: renderingStrategy,
Expand Down
4 changes: 2 additions & 2 deletions third_party/packages/flutter_svg/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: flutter_svg
description: An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files.
repository: https://github.com/flutter/packages/tree/main/third_party/packages/flutter_svg
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_svg%22
version: 2.2.4
version: 2.3.0

environment:
sdk: ^3.9.0
Expand All @@ -12,7 +12,7 @@ dependencies:
flutter:
sdk: flutter
http: ^1.0.0
vector_graphics: ^1.1.13
vector_graphics: ^1.2.0
vector_graphics_codec: ^1.1.11+1
vector_graphics_compiler: ^1.1.14

Expand Down
72 changes: 72 additions & 0 deletions third_party/packages/flutter_svg/test/widget_svg_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

Expand Down Expand Up @@ -981,6 +982,66 @@ void main() {
}
});

group('SvgPicture - imageBuilder', () {
testWidgets('wraps successfully loaded SVG', (WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: SvgPicture.string(
simpleSvg,
imageBuilder: (BuildContext context, Widget child) {
return Container(
key: const ValueKey<String>('image-builder'),
child: child,
);
},
),
),
);
await tester.pumpAndSettle();

expect(
find.byKey(const ValueKey<String>('image-builder')),
findsOneWidget,
);
});

testWidgets('does not wrap placeholder state', (WidgetTester tester) async {
final response = Completer<http.Response>();

await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: SvgPicture.network(
'test.svg',
httpClient: DelayedHttpClient(response.future),
imageBuilder: (BuildContext context, Widget child) {
return Container(
key: const ValueKey<String>('image-builder'),
child: child,
);
},
placeholderBuilder: (BuildContext context) {
return Container(key: const ValueKey<String>('placeholder'));
},
),
),
);

expect(find.byKey(const ValueKey<String>('placeholder')), findsOneWidget);
expect(find.byKey(const ValueKey<String>('image-builder')), findsNothing);

response.complete(http.Response(svgStr, 200));
await tester.pumpAndSettle();

expect(
find.byKey(const ValueKey<String>('image-builder')),
findsOneWidget,
);
expect(find.byKey(const ValueKey<String>('placeholder')), findsNothing);
});
});

group('SvgPicture - errorBuilder', () {
testWidgets('SvgPicture.string handles failure', (
WidgetTester tester,
Expand Down Expand Up @@ -1102,6 +1163,17 @@ class FakeHttpClient extends Fake implements http.Client {
}
}

class DelayedHttpClient extends Fake implements http.Client {
DelayedHttpClient(this.response);

final Future<http.Response> response;

@override
Future<http.Response> get(Uri url, {Map<String, String>? headers}) {
return response;
}
}

const String simpleSvg = '''
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 20 20">
<rect x="5" y="5" width="10" height="10"/>
Expand Down