Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use package:http, drop dart:html #1038

Merged
merged 2 commits into from
Feb 20, 2024
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ coverage/
.project

# golden failure diffs
test/failures
**/test/failures
# Flutter crash logs
/flutter_*.log
5 changes: 5 additions & 0 deletions packages/flutter_svg/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGES

## 2.0.10

- Use package:http for network requests, and allow injection of the client.
- Bump vector_graphics dependency.

## 2.0.9

- Adds back `SvgPicture(theme:)` parameter with a deprecation. Although this
Expand Down
15 changes: 10 additions & 5 deletions packages/flutter_svg/lib/src/loaders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import 'dart:convert' show utf8;
import 'package:flutter/foundation.dart' hide compute;
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:vector_graphics/vector_graphics.dart';
import 'package:vector_graphics_compiler/vector_graphics_compiler.dart' as vg;

import '../svg.dart' show svg;
import 'default_theme.dart';
import 'utilities/compute.dart';
import 'utilities/file.dart';
import 'utilities/http.dart';

/// A theme used when decoding an SVG picture.
@immutable
Expand Down Expand Up @@ -54,7 +54,7 @@ class SvgTheme {
}

@override
bool operator ==(dynamic other) {
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
Expand Down Expand Up @@ -109,6 +109,7 @@ class _DelegateVgColorMapper extends vg.ColorMapper {

/// A [BytesLoader] that parses a SVG data in an isolate and creates a
/// vector_graphics binary representation.
@immutable
abstract class SvgLoader<T> extends BytesLoader {
/// See class doc.
const SvgLoader({
Expand Down Expand Up @@ -423,17 +424,21 @@ class SvgNetworkLoader extends SvgLoader<Uint8List> {
this.headers,
super.theme,
super.colorMapper,
});
http.Client? httpClient,
}) : _httpClient = httpClient;

/// The [Uri] encoded resource address.
final String url;

/// Optional HTTP headers to send as part of the request.
final Map<String, String>? headers;

final http.Client? _httpClient;

@override
Future<Uint8List?> prepareMessage(BuildContext? context) {
return httpGet(url, headers: headers);
Future<Uint8List?> prepareMessage(BuildContext? context) async {
final http.Client client = _httpClient ?? http.Client();
return (await client.get(Uri.parse(url), headers: headers)).bodyBytes;
}

@override
Expand Down
22 changes: 0 additions & 22 deletions packages/flutter_svg/lib/src/utilities/_http_io.dart

This file was deleted.

12 changes: 0 additions & 12 deletions packages/flutter_svg/lib/src/utilities/_http_web.dart

This file was deleted.

1 change: 0 additions & 1 deletion packages/flutter_svg/lib/src/utilities/http.dart

This file was deleted.

9 changes: 8 additions & 1 deletion packages/flutter_svg/lib/svg.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:vector_graphics/vector_graphics_compat.dart';

import 'src/cache.dart';
Expand Down Expand Up @@ -248,7 +249,13 @@ class SvgPicture extends StatelessWidget {
this.clipBehavior = Clip.hardEdge,
@deprecated bool cacheColorFilter = false,
SvgTheme? theme,
}) : bytesLoader = SvgNetworkLoader(url, headers: headers, theme: theme),
http.Client? httpClient,
}) : bytesLoader = SvgNetworkLoader(
url,
headers: headers,
theme: theme,
httpClient: httpClient,
),
colorFilter = colorFilter ?? _getColorFilter(color, colorBlendMode),
super(key: key);

Expand Down
9 changes: 5 additions & 4 deletions packages/flutter_svg/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ 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/dnfield/flutter_svg/tree/master/packages/flutter_svg
issue_tracker: https://github.com/dnfield/flutter_svg/issues
version: 2.0.9
version: 2.0.10

dependencies:
flutter:
sdk: flutter
vector_graphics: ^1.1.9+1
vector_graphics_codec: ^1.1.9+1
vector_graphics_compiler: ^1.1.9+1
http: ^1.2.1
vector_graphics: ^1.1.11
vector_graphics_codec: ^1.1.11
vector_graphics_compiler: ^1.1.11

dev_dependencies:
flutter_test:
Expand Down
154 changes: 49 additions & 105 deletions packages/flutter_svg/test/widget_svg_test.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';

import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;

class _TolerantComparator extends LocalFileComparator {
_TolerantComparator(Uri testFile) : super(testFile);
Expand Down Expand Up @@ -39,9 +38,6 @@ Future<void> _checkWidgetAndGolden(Key key, String filename) async {
}

void main() {
late FakeHttpClientResponse fakeResponse;
late FakeHttpClientRequest fakeRequest;
late FakeHttpClient fakeHttpClient;
final MediaQueryData mediaQueryData =
MediaQueryData.fromView(PlatformDispatcher.instance.implicitView!);

Expand All @@ -54,12 +50,6 @@ void main() {
goldenFileComparator = newComparator;
});

setUp(() {
fakeResponse = FakeHttpClientResponse();
fakeRequest = FakeHttpClientRequest(fakeResponse);
fakeHttpClient = FakeHttpClient(fakeRequest);
});

testWidgets(
'SvgPicture does not use a color filtering widget when no color specified',
(WidgetTester tester) async {
Expand Down Expand Up @@ -306,40 +296,41 @@ void main() {
});

testWidgets('SvgPicture.network', (WidgetTester tester) async {
await HttpOverrides.runZoned(() async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: RepaintBoundary(
key: key,
child: SvgPicture.network(
'test.svg',
),
final GlobalKey key = GlobalKey();
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: RepaintBoundary(
key: key,
child: SvgPicture.network(
'test.svg',
httpClient: FakeHttpClient(),
),
),
);
await tester.pumpAndSettle();
await _checkWidgetAndGolden(key, 'flutter_logo.network.png');
}, createHttpClient: (SecurityContext? c) => fakeHttpClient);
),
);
await tester.pumpAndSettle();
await _checkWidgetAndGolden(key, 'flutter_logo.network.png');
});

testWidgets('SvgPicture.network with headers', (WidgetTester tester) async {
await HttpOverrides.runZoned(() async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: RepaintBoundary(
key: key,
child: SvgPicture.network('test.svg',
headers: const <String, String>{'a': 'b'}),
final GlobalKey key = GlobalKey();
final FakeHttpClient client = FakeHttpClient();
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: RepaintBoundary(
key: key,
child: SvgPicture.network(
'test.svg',
headers: const <String, String>{'a': 'b'},
httpClient: client,
),
),
);
await tester.pumpAndSettle();
expect(fakeRequest.headers['a']!.single, 'b');
}, createHttpClient: (SecurityContext? c) => fakeHttpClient);
),
);
await tester.pumpAndSettle();
expect(client.headers['a'], 'b');
});

testWidgets('SvgPicture can be created without a MediaQuery',
Expand All @@ -361,19 +352,18 @@ void main() {
});

testWidgets('SvgPicture.network HTTP exception', (WidgetTester tester) async {
await HttpOverrides.runZoned(() async {
expect(() async {
fakeResponse.statusCode = 400;
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: SvgPicture.network(
'notFound.svg',
),
expect(() async {
final http.Client client = FakeHttpClient(400);
await tester.pumpWidget(
MediaQuery(
data: mediaQueryData,
child: SvgPicture.network(
'notFound.svg',
httpClient: client,
),
);
}, isNotNull);
}, createHttpClient: (SecurityContext? c) => fakeHttpClient);
),
);
}, isNotNull);
});

testWidgets('SvgPicture semantics', (WidgetTester tester) async {
Expand Down Expand Up @@ -791,65 +781,19 @@ class FakeAssetBundle extends Fake implements AssetBundle {
}
}

class FakeHttpClient extends Fake implements HttpClient {
FakeHttpClient(this.request);
class FakeHttpClient extends Fake implements http.Client {
FakeHttpClient([this.statusCode = 200]);

FakeHttpClientRequest request;
final int statusCode;

@override
Future<HttpClientRequest> getUrl(Uri url) async => request;
}

class FakeHttpHeaders extends Fake implements HttpHeaders {
final Map<String, String?> values = <String, String?>{};

@override
void add(String name, Object value, {bool preserveHeaderCase = false}) {
values[name] = value.toString();
}
final Map<String, String> headers = <String, String>{};

@override
List<String>? operator [](String key) {
return <String>[values[key]!];
}
}

class FakeHttpClientRequest extends Fake implements HttpClientRequest {
FakeHttpClientRequest(this.response);

FakeHttpClientResponse response;

@override
final HttpHeaders headers = FakeHttpHeaders();

@override
Future<HttpClientResponse> close() async => response;
}

class FakeHttpClientResponse extends Fake implements HttpClientResponse {
@override
int statusCode = 200;

@override
int contentLength = svgStr.length;

@override
HttpClientResponseCompressionState get compressionState =>
HttpClientResponseCompressionState.notCompressed;

@override
StreamSubscription<List<int>> listen(
void Function(List<int> event)? onData, {
Function? onError,
void Function()? onDone,
bool? cancelOnError,
}) {
return Stream<Uint8List>.fromIterable(<Uint8List>[svgBytes]).listen(
onData,
onDone: onDone,
onError: onError,
cancelOnError: cancelOnError,
);
Future<http.Response> get(Uri url, {Map<String, String>? headers}) async {
if (headers != null) {
this.headers.addAll(headers);
}
return http.Response(svgStr, statusCode);
}
}

Expand Down
Loading