Skip to content

Commit

Permalink
Use package:http, drop dart:html (#1038)
Browse files Browse the repository at this point in the history
* Use package:http, drop dart:html

* Format
  • Loading branch information
dnfield committed Feb 20, 2024
1 parent a3911bb commit 09fd110
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 150 deletions.
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
13 changes: 9 additions & 4 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 @@ -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

This comment has been minimized.

Copy link
@NotTsunami

NotTsunami Feb 20, 2024

@dnfield This http constraint is really tight and version solving fails when using this package with Flutter 3.16. Flutter 3.16 pins web 0.3.0. http ^1.2.1 wants web 0.5.0. This is okay with Flutter 3.19 because web was moved to a dev_dependency/unpinned. Any chance the requirement can get relaxed to allow earlier versions of the http library?

This comment has been minimized.

Copy link
@dnfield

dnfield Feb 20, 2024

Author Owner

I can do that.

In the mean time, you can also do a depenedncy_override

This comment has been minimized.

Copy link
@dnfield

dnfield Feb 20, 2024

Author Owner

This comment has been minimized.

Copy link
@NotTsunami

NotTsunami Feb 20, 2024

Thanks! Cheers.

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

0 comments on commit 09fd110

Please sign in to comment.