Unverified Commit e8c94210 authored by Alexandre Ardhuin's avatar Alexandre Ardhuin Committed by GitHub

migrate part of painting to nullsafety (#62951)

parent 2c1b95b9
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
...@@ -33,7 +32,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm ...@@ -33,7 +32,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
final double scale; final double scale;
@override @override
final Map<String, String> headers; final Map<String, String>? headers;
@override @override
Future<NetworkImage> obtainKey(image_provider.ImageConfiguration configuration) { Future<NetworkImage> obtainKey(image_provider.ImageConfiguration configuration) {
...@@ -71,7 +70,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm ...@@ -71,7 +70,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
HttpClient client = _sharedHttpClient; HttpClient client = _sharedHttpClient;
assert(() { assert(() {
if (debugNetworkImageHttpClientProvider != null) if (debugNetworkImageHttpClientProvider != null)
client = debugNetworkImageHttpClientProvider(); client = debugNetworkImageHttpClientProvider!();
return true; return true;
}()); }());
return client; return client;
...@@ -102,7 +101,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm ...@@ -102,7 +101,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
final Uint8List bytes = await consolidateHttpClientResponseBytes( final Uint8List bytes = await consolidateHttpClientResponseBytes(
response, response,
onBytesReceived: (int cumulative, int total) { onBytesReceived: (int cumulative, int? total) {
chunkEvents.add(ImageChunkEvent( chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: cumulative, cumulativeBytesLoaded: cumulative,
expectedTotalBytes: total, expectedTotalBytes: total,
...@@ -118,7 +117,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm ...@@ -118,7 +117,7 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
// have had a chance to track the key in the cache at all. // have had a chance to track the key in the cache at all.
// Schedule a microtask to give the cache a chance to add the key. // Schedule a microtask to give the cache a chance to add the key.
scheduleMicrotask(() { scheduleMicrotask(() {
PaintingBinding.instance.imageCache.evict(key); PaintingBinding.instance!.imageCache!.evict(key);
}); });
rethrow; rethrow;
} finally { } finally {
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
...@@ -33,7 +32,7 @@ class NetworkImage ...@@ -33,7 +32,7 @@ class NetworkImage
final double scale; final double scale;
@override @override
final Map<String, String> headers; final Map<String, String>? headers;
@override @override
Future<NetworkImage> obtainKey( Future<NetworkImage> obtainKey(
...@@ -58,9 +57,9 @@ class NetworkImage ...@@ -58,9 +57,9 @@ class NetworkImage
informationCollector: _imageStreamInformationCollector(key)); informationCollector: _imageStreamInformationCollector(key));
} }
InformationCollector _imageStreamInformationCollector( InformationCollector? _imageStreamInformationCollector(
image_provider.NetworkImage key) { image_provider.NetworkImage key) {
InformationCollector collector; InformationCollector? collector;
assert(() { assert(() {
collector = () { collector = () {
return <DiagnosticsNode>[ return <DiagnosticsNode>[
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
...@@ -57,24 +56,24 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -57,24 +56,24 @@ class BeveledRectangleBorder extends OutlinedBorder {
} }
@override @override
ShapeBorder lerpFrom(ShapeBorder a, double t) { ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
assert(t != null); assert(t != null);
if (a is BeveledRectangleBorder) { if (a is BeveledRectangleBorder) {
return BeveledRectangleBorder( return BeveledRectangleBorder(
side: BorderSide.lerp(a.side, side, t), side: BorderSide.lerp(a.side, side, t),
borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t)!,
); );
} }
return super.lerpFrom(a, t); return super.lerpFrom(a, t);
} }
@override @override
ShapeBorder lerpTo(ShapeBorder b, double t) { ShapeBorder? lerpTo(ShapeBorder? b, double t) {
assert(t != null); assert(t != null);
if (b is BeveledRectangleBorder) { if (b is BeveledRectangleBorder) {
return BeveledRectangleBorder( return BeveledRectangleBorder(
side: BorderSide.lerp(side, b.side, t), side: BorderSide.lerp(side, b.side, t),
borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t), borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t)!,
); );
} }
return super.lerpTo(b, t); return super.lerpTo(b, t);
...@@ -83,7 +82,7 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -83,7 +82,7 @@ class BeveledRectangleBorder extends OutlinedBorder {
/// Returns a copy of this RoundedRectangleBorder with the given fields /// Returns a copy of this RoundedRectangleBorder with the given fields
/// replaced with the new values. /// replaced with the new values.
@override @override
BeveledRectangleBorder copyWith({ BorderSide side, BorderRadius borderRadius }) { BeveledRectangleBorder copyWith({ BorderSide? side, BorderRadius? borderRadius }) {
return BeveledRectangleBorder( return BeveledRectangleBorder(
side: side ?? this.side, side: side ?? this.side,
borderRadius: borderRadius ?? this.borderRadius, borderRadius: borderRadius ?? this.borderRadius,
...@@ -120,17 +119,17 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -120,17 +119,17 @@ class BeveledRectangleBorder extends OutlinedBorder {
} }
@override @override
Path getInnerPath(Rect rect, { TextDirection textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width)); return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width));
} }
@override @override
Path getOuterPath(Rect rect, { TextDirection textDirection }) { Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect)); return _getPath(borderRadius.resolve(textDirection).toRRect(rect));
} }
@override @override
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) { void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) {
if (rect.isEmpty) if (rect.isEmpty)
return; return;
switch (side.style) { switch (side.style) {
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -130,7 +129,7 @@ abstract class BorderRadiusGeometry { ...@@ -130,7 +129,7 @@ abstract class BorderRadiusGeometry {
/// into a concrete [BorderRadius] using [resolve]. /// into a concrete [BorderRadius] using [resolve].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BorderRadiusGeometry lerp(BorderRadiusGeometry a, BorderRadiusGeometry b, double t) { static BorderRadiusGeometry? lerp(BorderRadiusGeometry? a, BorderRadiusGeometry? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
...@@ -148,11 +147,11 @@ abstract class BorderRadiusGeometry { ...@@ -148,11 +147,11 @@ abstract class BorderRadiusGeometry {
/// * [BorderRadius], for which this is a no-op (returns itself). /// * [BorderRadius], for which this is a no-op (returns itself).
/// * [BorderRadiusDirectional], which flips the horizontal direction /// * [BorderRadiusDirectional], which flips the horizontal direction
/// based on the `direction` argument. /// based on the `direction` argument.
BorderRadius resolve(TextDirection direction); BorderRadius resolve(TextDirection? direction);
@override @override
String toString() { String toString() {
String visual, logical; String? visual, logical;
if (_topLeft == _topRight && if (_topLeft == _topRight &&
_topRight == _bottomLeft && _topRight == _bottomLeft &&
_bottomLeft == _bottomRight) { _bottomLeft == _bottomRight) {
...@@ -474,24 +473,24 @@ class BorderRadius extends BorderRadiusGeometry { ...@@ -474,24 +473,24 @@ class BorderRadius extends BorderRadiusGeometry {
/// If either is null, this function interpolates from [BorderRadius.zero]. /// If either is null, this function interpolates from [BorderRadius.zero].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BorderRadius lerp(BorderRadius a, BorderRadius b, double t) { static BorderRadius? lerp(BorderRadius? a, BorderRadius? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
return BorderRadius.only( return BorderRadius.only(
topLeft: Radius.lerp(a.topLeft, b.topLeft, t), topLeft: Radius.lerp(a.topLeft, b.topLeft, t)!,
topRight: Radius.lerp(a.topRight, b.topRight, t), topRight: Radius.lerp(a.topRight, b.topRight, t)!,
bottomLeft: Radius.lerp(a.bottomLeft, b.bottomLeft, t), bottomLeft: Radius.lerp(a.bottomLeft, b.bottomLeft, t)!,
bottomRight: Radius.lerp(a.bottomRight, b.bottomRight, t), bottomRight: Radius.lerp(a.bottomRight, b.bottomRight, t)!,
); );
} }
@override @override
BorderRadius resolve(TextDirection direction) => this; BorderRadius resolve(TextDirection? direction) => this;
} }
/// An immutable set of radii for each corner of a rectangle, but with the /// An immutable set of radii for each corner of a rectangle, but with the
...@@ -691,26 +690,26 @@ class BorderRadiusDirectional extends BorderRadiusGeometry { ...@@ -691,26 +690,26 @@ class BorderRadiusDirectional extends BorderRadiusGeometry {
/// If either is null, this function interpolates from [BorderRadiusDirectional.zero]. /// If either is null, this function interpolates from [BorderRadiusDirectional.zero].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BorderRadiusDirectional lerp(BorderRadiusDirectional a, BorderRadiusDirectional b, double t) { static BorderRadiusDirectional? lerp(BorderRadiusDirectional? a, BorderRadiusDirectional? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
return BorderRadiusDirectional.only( return BorderRadiusDirectional.only(
topStart: Radius.lerp(a.topStart, b.topStart, t), topStart: Radius.lerp(a.topStart, b.topStart, t)!,
topEnd: Radius.lerp(a.topEnd, b.topEnd, t), topEnd: Radius.lerp(a.topEnd, b.topEnd, t)!,
bottomStart: Radius.lerp(a.bottomStart, b.bottomStart, t), bottomStart: Radius.lerp(a.bottomStart, b.bottomStart, t)!,
bottomEnd: Radius.lerp(a.bottomEnd, b.bottomEnd, t), bottomEnd: Radius.lerp(a.bottomEnd, b.bottomEnd, t)!,
); );
} }
@override @override
BorderRadius resolve(TextDirection direction) { BorderRadius resolve(TextDirection? direction) {
assert(direction != null); assert(direction != null);
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return BorderRadius.only( return BorderRadius.only(
topLeft: topEnd, topLeft: topEnd,
...@@ -726,7 +725,6 @@ class BorderRadiusDirectional extends BorderRadiusGeometry { ...@@ -726,7 +725,6 @@ class BorderRadiusDirectional extends BorderRadiusGeometry {
bottomRight: bottomEnd, bottomRight: bottomEnd,
); );
} }
return null;
} }
} }
...@@ -838,9 +836,9 @@ class _MixedBorderRadius extends BorderRadiusGeometry { ...@@ -838,9 +836,9 @@ class _MixedBorderRadius extends BorderRadiusGeometry {
} }
@override @override
BorderRadius resolve(TextDirection direction) { BorderRadius resolve(TextDirection? direction) {
assert(direction != null); assert(direction != null);
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return BorderRadius.only( return BorderRadius.only(
topLeft: _topLeft + _topEnd, topLeft: _topLeft + _topEnd,
...@@ -856,6 +854,5 @@ class _MixedBorderRadius extends BorderRadiusGeometry { ...@@ -856,6 +854,5 @@ class _MixedBorderRadius extends BorderRadiusGeometry {
bottomRight: _bottomRight + _bottomEnd, bottomRight: _bottomRight + _bottomEnd,
); );
} }
return null;
} }
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' as ui show lerpDouble; import 'dart:ui' as ui show lerpDouble;
...@@ -130,9 +129,9 @@ class BorderSide { ...@@ -130,9 +129,9 @@ class BorderSide {
/// Creates a copy of this border but with the given fields replaced with the new values. /// Creates a copy of this border but with the given fields replaced with the new values.
BorderSide copyWith({ BorderSide copyWith({
Color color, Color? color,
double width, double? width,
BorderStyle style, BorderStyle? style,
}) { }) {
assert(width == null || width >= 0.0); assert(width == null || width >= 0.0);
return BorderSide( return BorderSide(
...@@ -186,7 +185,6 @@ class BorderSide { ...@@ -186,7 +185,6 @@ class BorderSide {
..strokeWidth = 0.0 ..strokeWidth = 0.0
..style = PaintingStyle.stroke; ..style = PaintingStyle.stroke;
} }
return null;
} }
/// Whether the two given [BorderSide]s can be merged using [new /// Whether the two given [BorderSide]s can be merged using [new
...@@ -219,12 +217,12 @@ class BorderSide { ...@@ -219,12 +217,12 @@ class BorderSide {
return a; return a;
if (t == 1.0) if (t == 1.0)
return b; return b;
final double width = ui.lerpDouble(a.width, b.width, t); final double width = ui.lerpDouble(a.width, b.width, t)!;
if (width < 0.0) if (width < 0.0)
return BorderSide.none; return BorderSide.none;
if (a.style == b.style) { if (a.style == b.style) {
return BorderSide( return BorderSide(
color: Color.lerp(a.color, b.color, t), color: Color.lerp(a.color, b.color, t)!,
width: width, width: width,
style: a.style, // == b.style style: a.style, // == b.style
); );
...@@ -247,7 +245,7 @@ class BorderSide { ...@@ -247,7 +245,7 @@ class BorderSide {
break; break;
} }
return BorderSide( return BorderSide(
color: Color.lerp(colorA, colorB, t), color: Color.lerp(colorA, colorB, t)!,
width: width, width: width,
style: BorderStyle.solid, style: BorderStyle.solid,
); );
...@@ -319,7 +317,7 @@ abstract class ShapeBorder { ...@@ -319,7 +317,7 @@ abstract class ShapeBorder {
/// The `reversed` argument is true if this object was the right operand of /// The `reversed` argument is true if this object was the right operand of
/// the `+` operator, and false if it was the left operand. /// the `+` operator, and false if it was the left operand.
@protected @protected
ShapeBorder add(ShapeBorder other, { bool reversed = false }) => null; ShapeBorder? add(ShapeBorder other, { bool reversed = false }) => null;
/// Creates a new border consisting of the two borders on either side of the /// Creates a new border consisting of the two borders on either side of the
/// operator. /// operator.
...@@ -382,7 +380,7 @@ abstract class ShapeBorder { ...@@ -382,7 +380,7 @@ abstract class ShapeBorder {
/// ///
/// Instead of calling this directly, use [ShapeBorder.lerp]. /// Instead of calling this directly, use [ShapeBorder.lerp].
@protected @protected
ShapeBorder lerpFrom(ShapeBorder a, double t) { ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a == null) if (a == null)
return scale(t); return scale(t);
return null; return null;
...@@ -414,7 +412,7 @@ abstract class ShapeBorder { ...@@ -414,7 +412,7 @@ abstract class ShapeBorder {
/// ///
/// Instead of calling this directly, use [ShapeBorder.lerp]. /// Instead of calling this directly, use [ShapeBorder.lerp].
@protected @protected
ShapeBorder lerpTo(ShapeBorder b, double t) { ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b == null) if (b == null)
return scale(1.0 - t); return scale(1.0 - t);
return null; return null;
...@@ -428,9 +426,9 @@ abstract class ShapeBorder { ...@@ -428,9 +426,9 @@ abstract class ShapeBorder {
/// and `b` after `t=0.5`. /// and `b` after `t=0.5`.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static ShapeBorder lerp(ShapeBorder a, ShapeBorder b, double t) { static ShapeBorder? lerp(ShapeBorder? a, ShapeBorder? b, double t) {
assert(t != null); assert(t != null);
ShapeBorder result; ShapeBorder? result;
if (b != null) if (b != null)
result = b.lerpFrom(a, t); result = b.lerpFrom(a, t);
if (result == null && a != null) if (result == null && a != null)
...@@ -457,7 +455,7 @@ abstract class ShapeBorder { ...@@ -457,7 +455,7 @@ abstract class ShapeBorder {
/// ///
/// * [getInnerPath], which creates the path for the inner edge. /// * [getInnerPath], which creates the path for the inner edge.
/// * [Path.contains], which can tell if an [Offset] is within a [Path]. /// * [Path.contains], which can tell if an [Offset] is within a [Path].
Path getOuterPath(Rect rect, { TextDirection textDirection }); Path getOuterPath(Rect rect, { TextDirection? textDirection });
/// Create a [Path] that describes the inner edge of the border. /// Create a [Path] that describes the inner edge of the border.
/// ///
...@@ -478,7 +476,7 @@ abstract class ShapeBorder { ...@@ -478,7 +476,7 @@ abstract class ShapeBorder {
/// ///
/// * [getOuterPath], which creates the path for the outer edge. /// * [getOuterPath], which creates the path for the outer edge.
/// * [Path.contains], which can tell if an [Offset] is within a [Path]. /// * [Path.contains], which can tell if an [Offset] is within a [Path].
Path getInnerPath(Rect rect, { TextDirection textDirection }); Path getInnerPath(Rect rect, { TextDirection? textDirection });
/// Paints the border within the given [Rect] on the given [Canvas]. /// Paints the border within the given [Rect] on the given [Canvas].
/// ///
...@@ -486,7 +484,7 @@ abstract class ShapeBorder { ...@@ -486,7 +484,7 @@ abstract class ShapeBorder {
/// has a text direction dependency (for example if it is expressed in terms /// has a text direction dependency (for example if it is expressed in terms
/// of "start" and "end" instead of "left" and "right"). It may be null if /// of "start" and "end" instead of "left" and "right"). It may be null if
/// the border will not need the text direction to paint itself. /// the border will not need the text direction to paint itself.
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }); void paint(Canvas canvas, Rect rect, { TextDirection? textDirection });
@override @override
String toString() { String toString() {
...@@ -548,7 +546,7 @@ class _CompoundBorder extends ShapeBorder { ...@@ -548,7 +546,7 @@ class _CompoundBorder extends ShapeBorder {
// border, and "merged" is the result of attempting to merge it with the // border, and "merged" is the result of attempting to merge it with the
// new border. If it's null, it couldn't be merged. // new border. If it's null, it couldn't be merged.
final ShapeBorder ours = reversed ? borders.last : borders.first; final ShapeBorder ours = reversed ? borders.last : borders.first;
final ShapeBorder merged = ours.add(other, reversed: reversed) final ShapeBorder? merged = ours.add(other, reversed: reversed)
?? other.add(ours, reversed: !reversed); ?? other.add(ours, reversed: !reversed);
if (merged != null) { if (merged != null) {
final List<ShapeBorder> result = <ShapeBorder>[...borders]; final List<ShapeBorder> result = <ShapeBorder>[...borders];
...@@ -574,27 +572,27 @@ class _CompoundBorder extends ShapeBorder { ...@@ -574,27 +572,27 @@ class _CompoundBorder extends ShapeBorder {
} }
@override @override
ShapeBorder lerpFrom(ShapeBorder a, double t) { ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
return _CompoundBorder.lerp(a, this, t); return _CompoundBorder.lerp(a, this, t);
} }
@override @override
ShapeBorder lerpTo(ShapeBorder b, double t) { ShapeBorder? lerpTo(ShapeBorder? b, double t) {
return _CompoundBorder.lerp(this, b, t); return _CompoundBorder.lerp(this, b, t);
} }
static _CompoundBorder lerp(ShapeBorder a, ShapeBorder b, double t) { static _CompoundBorder lerp(ShapeBorder? a, ShapeBorder? b, double t) {
assert(t != null); assert(t != null);
assert(a is _CompoundBorder || b is _CompoundBorder); // Not really necessary, but all call sites currently intend this. assert(a is _CompoundBorder || b is _CompoundBorder); // Not really necessary, but all call sites currently intend this.
final List<ShapeBorder> aList = a is _CompoundBorder ? a.borders : <ShapeBorder>[a]; final List<ShapeBorder?> aList = a is _CompoundBorder ? a.borders : <ShapeBorder?>[a];
final List<ShapeBorder> bList = b is _CompoundBorder ? b.borders : <ShapeBorder>[b]; final List<ShapeBorder?> bList = b is _CompoundBorder ? b.borders : <ShapeBorder?>[b];
final List<ShapeBorder> results = <ShapeBorder>[]; final List<ShapeBorder> results = <ShapeBorder>[];
final int length = math.max(aList.length, bList.length); final int length = math.max(aList.length, bList.length);
for (int index = 0; index < length; index += 1) { for (int index = 0; index < length; index += 1) {
final ShapeBorder localA = index < aList.length ? aList[index] : null; final ShapeBorder? localA = index < aList.length ? aList[index] : null;
final ShapeBorder localB = index < bList.length ? bList[index] : null; final ShapeBorder? localB = index < bList.length ? bList[index] : null;
if (localA != null && localB != null) { if (localA != null && localB != null) {
final ShapeBorder localResult = localA.lerpTo(localB, t) ?? localB.lerpFrom(localA, t); final ShapeBorder? localResult = localA.lerpTo(localB, t) ?? localB.lerpFrom(localA, t);
if (localResult != null) { if (localResult != null) {
results.add(localResult); results.add(localResult);
continue; continue;
...@@ -613,19 +611,19 @@ class _CompoundBorder extends ShapeBorder { ...@@ -613,19 +611,19 @@ class _CompoundBorder extends ShapeBorder {
} }
@override @override
Path getInnerPath(Rect rect, { TextDirection textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
for (int index = 0; index < borders.length - 1; index += 1) for (int index = 0; index < borders.length - 1; index += 1)
rect = borders[index].dimensions.resolve(textDirection).deflateRect(rect); rect = borders[index].dimensions.resolve(textDirection).deflateRect(rect);
return borders.last.getInnerPath(rect, textDirection: textDirection); return borders.last.getInnerPath(rect, textDirection: textDirection);
} }
@override @override
Path getOuterPath(Rect rect, { TextDirection textDirection }) { Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
return borders.first.getOuterPath(rect, textDirection: textDirection); return borders.first.getOuterPath(rect, textDirection: textDirection);
} }
@override @override
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) { void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) {
for (final ShapeBorder border in borders) { for (final ShapeBorder border in borders) {
border.paint(canvas, rect, textDirection: textDirection); border.paint(canvas, rect, textDirection: textDirection);
rect = border.dimensions.resolve(textDirection).deflateRect(rect); rect = border.dimensions.resolve(textDirection).deflateRect(rect);
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -85,7 +84,7 @@ abstract class BoxBorder extends ShapeBorder { ...@@ -85,7 +84,7 @@ abstract class BoxBorder extends ShapeBorder {
// We override this to tighten the return value, so that callers can assume // We override this to tighten the return value, so that callers can assume
// that we'll return a [BoxBorder]. // that we'll return a [BoxBorder].
@override @override
BoxBorder add(ShapeBorder other, { bool reversed = false }) => null; BoxBorder? add(ShapeBorder other, { bool reversed = false }) => null;
/// Linearly interpolate between two borders. /// Linearly interpolate between two borders.
/// ///
...@@ -104,12 +103,12 @@ abstract class BoxBorder extends ShapeBorder { ...@@ -104,12 +103,12 @@ abstract class BoxBorder extends ShapeBorder {
/// instead [add] the two sets of sides and interpolate them simultaneously. /// instead [add] the two sets of sides and interpolate them simultaneously.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BoxBorder lerp(BoxBorder a, BoxBorder b, double t) { static BoxBorder? lerp(BoxBorder? a, BoxBorder? b, double t) {
assert(t != null); assert(t != null);
if ((a is Border || a == null) && (b is Border || b == null)) if ((a is Border?) && (b is Border?))
return Border.lerp(a as Border, b as Border, t); return Border.lerp(a, b, t);
if ((a is BorderDirectional || a == null) && (b is BorderDirectional || b == null)) if ((a is BorderDirectional?) && (b is BorderDirectional?))
return BorderDirectional.lerp(a as BorderDirectional, b as BorderDirectional, t); return BorderDirectional.lerp(a, b, t);
if (b is Border && a is BorderDirectional) { if (b is Border && a is BorderDirectional) {
final BoxBorder c = b; final BoxBorder c = b;
b = a; b = a;
...@@ -167,14 +166,14 @@ abstract class BoxBorder extends ShapeBorder { ...@@ -167,14 +166,14 @@ abstract class BoxBorder extends ShapeBorder {
} }
@override @override
Path getInnerPath(Rect rect, { @required TextDirection textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
assert(textDirection != null, 'The textDirection argument to $runtimeType.getInnerPath must not be null.'); assert(textDirection != null, 'The textDirection argument to $runtimeType.getInnerPath must not be null.');
return Path() return Path()
..addRect(dimensions.resolve(textDirection).deflateRect(rect)); ..addRect(dimensions.resolve(textDirection).deflateRect(rect));
} }
@override @override
Path getOuterPath(Rect rect, { @required TextDirection textDirection }) { Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
assert(textDirection != null, 'The textDirection argument to $runtimeType.getOuterPath must not be null.'); assert(textDirection != null, 'The textDirection argument to $runtimeType.getOuterPath must not be null.');
return Path() return Path()
..addRect(rect); ..addRect(rect);
...@@ -203,9 +202,9 @@ abstract class BoxBorder extends ShapeBorder { ...@@ -203,9 +202,9 @@ abstract class BoxBorder extends ShapeBorder {
void paint( void paint(
Canvas canvas, Canvas canvas,
Rect rect, { Rect rect, {
TextDirection textDirection, TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle, BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius, BorderRadius? borderRadius,
}); });
static void _paintUniformBorderWithRadius(Canvas canvas, Rect rect, BorderSide side, BorderRadius borderRadius) { static void _paintUniformBorderWithRadius(Canvas canvas, Rect rect, BorderSide side, BorderRadius borderRadius) {
...@@ -414,7 +413,7 @@ class Border extends BoxBorder { ...@@ -414,7 +413,7 @@ class Border extends BoxBorder {
} }
@override @override
Border add(ShapeBorder other, { bool reversed = false }) { Border? add(ShapeBorder other, { bool reversed = false }) {
if (other is Border && if (other is Border &&
BorderSide.canMerge(top, other.top) && BorderSide.canMerge(top, other.top) &&
BorderSide.canMerge(right, other.right) && BorderSide.canMerge(right, other.right) &&
...@@ -436,14 +435,14 @@ class Border extends BoxBorder { ...@@ -436,14 +435,14 @@ class Border extends BoxBorder {
} }
@override @override
ShapeBorder lerpFrom(ShapeBorder a, double t) { ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a is Border) if (a is Border)
return Border.lerp(a, this, t); return Border.lerp(a, this, t);
return super.lerpFrom(a, t); return super.lerpFrom(a, t);
} }
@override @override
ShapeBorder lerpTo(ShapeBorder b, double t) { ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b is Border) if (b is Border)
return Border.lerp(this, b, t); return Border.lerp(this, b, t);
return super.lerpTo(b, t); return super.lerpTo(b, t);
...@@ -455,12 +454,12 @@ class Border extends BoxBorder { ...@@ -455,12 +454,12 @@ class Border extends BoxBorder {
/// borders. /// borders.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static Border lerp(Border a, Border b, double t) { static Border? lerp(Border? a, Border? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b.scale(t); return b!.scale(t);
if (b == null) if (b == null)
return a.scale(1.0 - t); return a.scale(1.0 - t);
return Border( return Border(
...@@ -494,9 +493,9 @@ class Border extends BoxBorder { ...@@ -494,9 +493,9 @@ class Border extends BoxBorder {
void paint( void paint(
Canvas canvas, Canvas canvas,
Rect rect, { Rect rect, {
TextDirection textDirection, TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle, BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius, BorderRadius? borderRadius,
}) { }) {
if (isUniform) { if (isUniform) {
switch (top.style) { switch (top.style) {
...@@ -694,7 +693,7 @@ class BorderDirectional extends BoxBorder { ...@@ -694,7 +693,7 @@ class BorderDirectional extends BoxBorder {
} }
@override @override
BoxBorder add(ShapeBorder other, { bool reversed = false }) { BoxBorder? add(ShapeBorder other, { bool reversed = false }) {
if (other is BorderDirectional) { if (other is BorderDirectional) {
final BorderDirectional typedOther = other; final BorderDirectional typedOther = other;
if (BorderSide.canMerge(top, typedOther.top) && if (BorderSide.canMerge(top, typedOther.top) &&
...@@ -747,14 +746,14 @@ class BorderDirectional extends BoxBorder { ...@@ -747,14 +746,14 @@ class BorderDirectional extends BoxBorder {
} }
@override @override
ShapeBorder lerpFrom(ShapeBorder a, double t) { ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a is BorderDirectional) if (a is BorderDirectional)
return BorderDirectional.lerp(a, this, t); return BorderDirectional.lerp(a, this, t);
return super.lerpFrom(a, t); return super.lerpFrom(a, t);
} }
@override @override
ShapeBorder lerpTo(ShapeBorder b, double t) { ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b is BorderDirectional) if (b is BorderDirectional)
return BorderDirectional.lerp(this, b, t); return BorderDirectional.lerp(this, b, t);
return super.lerpTo(b, t); return super.lerpTo(b, t);
...@@ -766,12 +765,12 @@ class BorderDirectional extends BoxBorder { ...@@ -766,12 +765,12 @@ class BorderDirectional extends BoxBorder {
/// borders. /// borders.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BorderDirectional lerp(BorderDirectional a, BorderDirectional b, double t) { static BorderDirectional? lerp(BorderDirectional? a, BorderDirectional? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b.scale(t); return b!.scale(t);
if (b == null) if (b == null)
return a.scale(1.0 - t); return a.scale(1.0 - t);
return BorderDirectional( return BorderDirectional(
...@@ -808,9 +807,9 @@ class BorderDirectional extends BoxBorder { ...@@ -808,9 +807,9 @@ class BorderDirectional extends BoxBorder {
void paint( void paint(
Canvas canvas, Canvas canvas,
Rect rect, { Rect rect, {
TextDirection textDirection, TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle, BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius, BorderRadius? borderRadius,
}) { }) {
if (isUniform) { if (isUniform) {
switch (top.style) { switch (top.style) {
...@@ -839,7 +838,7 @@ class BorderDirectional extends BoxBorder { ...@@ -839,7 +838,7 @@ class BorderDirectional extends BoxBorder {
BorderSide left, right; BorderSide left, right;
assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.'); assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.');
switch (textDirection) { switch (textDirection!) {
case TextDirection.rtl: case TextDirection.rtl:
left = end; left = end;
right = start; right = start;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' as ui show Shadow, lerpDouble; import 'dart:ui' as ui show Shadow, lerpDouble;
...@@ -79,19 +78,19 @@ class BoxShadow extends ui.Shadow { ...@@ -79,19 +78,19 @@ class BoxShadow extends ui.Shadow {
/// offset and a zero blurRadius. /// offset and a zero blurRadius.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) { static BoxShadow? lerp(BoxShadow? a, BoxShadow? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b.scale(t); return b!.scale(t);
if (b == null) if (b == null)
return a.scale(1.0 - t); return a.scale(1.0 - t);
return BoxShadow( return BoxShadow(
color: Color.lerp(a.color, b.color, t), color: Color.lerp(a.color, b.color, t)!,
offset: Offset.lerp(a.offset, b.offset, t), offset: Offset.lerp(a.offset, b.offset, t)!,
blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t), blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t)!,
spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t), spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t)!,
); );
} }
...@@ -100,7 +99,7 @@ class BoxShadow extends ui.Shadow { ...@@ -100,7 +99,7 @@ class BoxShadow extends ui.Shadow {
/// If the lists differ in length, excess items are lerped with null. /// If the lists differ in length, excess items are lerped with null.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static List<BoxShadow> lerpList(List<BoxShadow> a, List<BoxShadow> b, double t) { static List<BoxShadow>? lerpList(List<BoxShadow>? a, List<BoxShadow>? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
...@@ -108,7 +107,7 @@ class BoxShadow extends ui.Shadow { ...@@ -108,7 +107,7 @@ class BoxShadow extends ui.Shadow {
b ??= <BoxShadow>[]; b ??= <BoxShadow>[];
final int commonLength = math.min(a.length, b.length); final int commonLength = math.min(a.length, b.length);
return <BoxShadow>[ return <BoxShadow>[
for (int i = 0; i < commonLength; i += 1) BoxShadow.lerp(a[i], b[i], t), for (int i = 0; i < commonLength; i += 1) BoxShadow.lerp(a[i], b[i], t)!,
for (int i = commonLength; i < a.length; i += 1) a[i].scale(1.0 - t), for (int i = commonLength; i < a.length; i += 1) a[i].scale(1.0 - t),
for (int i = commonLength; i < b.length; i += 1) b[i].scale(t), for (int i = commonLength; i < b.length; i += 1) b[i].scale(t),
]; ];
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:ui' as ui show lerpDouble, WindowPadding; import 'dart:ui' as ui show lerpDouble, WindowPadding;
...@@ -73,7 +72,6 @@ abstract class EdgeInsetsGeometry { ...@@ -73,7 +72,6 @@ abstract class EdgeInsetsGeometry {
case Axis.vertical: case Axis.vertical:
return vertical; return vertical;
} }
return null;
} }
/// The size that this [EdgeInsets] would occupy with an empty interior. /// The size that this [EdgeInsets] would occupy with an empty interior.
...@@ -218,12 +216,12 @@ abstract class EdgeInsetsGeometry { ...@@ -218,12 +216,12 @@ abstract class EdgeInsetsGeometry {
/// into a concrete [EdgeInsets] using [resolve]. /// into a concrete [EdgeInsets] using [resolve].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static EdgeInsetsGeometry lerp(EdgeInsetsGeometry a, EdgeInsetsGeometry b, double t) { static EdgeInsetsGeometry? lerp(EdgeInsetsGeometry? a, EdgeInsetsGeometry? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
if (a is EdgeInsets && b is EdgeInsets) if (a is EdgeInsets && b is EdgeInsets)
...@@ -231,12 +229,12 @@ abstract class EdgeInsetsGeometry { ...@@ -231,12 +229,12 @@ abstract class EdgeInsetsGeometry {
if (a is EdgeInsetsDirectional && b is EdgeInsetsDirectional) if (a is EdgeInsetsDirectional && b is EdgeInsetsDirectional)
return EdgeInsetsDirectional.lerp(a, b, t); return EdgeInsetsDirectional.lerp(a, b, t);
return _MixedEdgeInsets.fromLRSETB( return _MixedEdgeInsets.fromLRSETB(
ui.lerpDouble(a._left, b._left, t), ui.lerpDouble(a._left, b._left, t)!,
ui.lerpDouble(a._right, b._right, t), ui.lerpDouble(a._right, b._right, t)!,
ui.lerpDouble(a._start, b._start, t), ui.lerpDouble(a._start, b._start, t)!,
ui.lerpDouble(a._end, b._end, t), ui.lerpDouble(a._end, b._end, t)!,
ui.lerpDouble(a._top, b._top, t), ui.lerpDouble(a._top, b._top, t)!,
ui.lerpDouble(a._bottom, b._bottom, t), ui.lerpDouble(a._bottom, b._bottom, t)!,
); );
} }
...@@ -249,7 +247,7 @@ abstract class EdgeInsetsGeometry { ...@@ -249,7 +247,7 @@ abstract class EdgeInsetsGeometry {
/// * [EdgeInsets], for which this is a no-op (returns itself). /// * [EdgeInsets], for which this is a no-op (returns itself).
/// * [EdgeInsetsDirectional], which flips the horizontal direction /// * [EdgeInsetsDirectional], which flips the horizontal direction
/// based on the `direction` argument. /// based on the `direction` argument.
EdgeInsets resolve(TextDirection direction); EdgeInsets resolve(TextDirection? direction);
@override @override
String toString() { String toString() {
...@@ -597,32 +595,32 @@ class EdgeInsets extends EdgeInsetsGeometry { ...@@ -597,32 +595,32 @@ class EdgeInsets extends EdgeInsetsGeometry {
/// If either is null, this function interpolates from [EdgeInsets.zero]. /// If either is null, this function interpolates from [EdgeInsets.zero].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static EdgeInsets lerp(EdgeInsets a, EdgeInsets b, double t) { static EdgeInsets? lerp(EdgeInsets? a, EdgeInsets? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
return EdgeInsets.fromLTRB( return EdgeInsets.fromLTRB(
ui.lerpDouble(a.left, b.left, t), ui.lerpDouble(a.left, b.left, t)!,
ui.lerpDouble(a.top, b.top, t), ui.lerpDouble(a.top, b.top, t)!,
ui.lerpDouble(a.right, b.right, t), ui.lerpDouble(a.right, b.right, t)!,
ui.lerpDouble(a.bottom, b.bottom, t), ui.lerpDouble(a.bottom, b.bottom, t)!,
); );
} }
@override @override
EdgeInsets resolve(TextDirection direction) => this; EdgeInsets resolve(TextDirection? direction) => this;
/// Creates a copy of this EdgeInsets but with the given fields replaced /// Creates a copy of this EdgeInsets but with the given fields replaced
/// with the new values. /// with the new values.
EdgeInsets copyWith({ EdgeInsets copyWith({
double left, double? left,
double top, double? top,
double right, double? right,
double bottom, double? bottom,
}) { }) {
return EdgeInsets.only( return EdgeInsets.only(
left: left ?? this.left, left: left ?? this.left,
...@@ -822,32 +820,31 @@ class EdgeInsetsDirectional extends EdgeInsetsGeometry { ...@@ -822,32 +820,31 @@ class EdgeInsetsDirectional extends EdgeInsetsGeometry {
/// [EdgeInsetsGeometry.lerp] static method. /// [EdgeInsetsGeometry.lerp] static method.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static EdgeInsetsDirectional lerp(EdgeInsetsDirectional a, EdgeInsetsDirectional b, double t) { static EdgeInsetsDirectional? lerp(EdgeInsetsDirectional? a, EdgeInsetsDirectional? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
return EdgeInsetsDirectional.fromSTEB( return EdgeInsetsDirectional.fromSTEB(
ui.lerpDouble(a.start, b.start, t), ui.lerpDouble(a.start, b.start, t)!,
ui.lerpDouble(a.top, b.top, t), ui.lerpDouble(a.top, b.top, t)!,
ui.lerpDouble(a.end, b.end, t), ui.lerpDouble(a.end, b.end, t)!,
ui.lerpDouble(a.bottom, b.bottom, t), ui.lerpDouble(a.bottom, b.bottom, t)!,
); );
} }
@override @override
EdgeInsets resolve(TextDirection direction) { EdgeInsets resolve(TextDirection? direction) {
assert(direction != null); assert(direction != null);
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return EdgeInsets.fromLTRB(end, top, start, bottom); return EdgeInsets.fromLTRB(end, top, start, bottom);
case TextDirection.ltr: case TextDirection.ltr:
return EdgeInsets.fromLTRB(start, top, end, bottom); return EdgeInsets.fromLTRB(start, top, end, bottom);
} }
return null;
} }
} }
...@@ -943,14 +940,13 @@ class _MixedEdgeInsets extends EdgeInsetsGeometry { ...@@ -943,14 +940,13 @@ class _MixedEdgeInsets extends EdgeInsetsGeometry {
} }
@override @override
EdgeInsets resolve(TextDirection direction) { EdgeInsets resolve(TextDirection? direction) {
assert(direction != null); assert(direction != null);
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return EdgeInsets.fromLTRB(_end + _left, _top, _start + _right, _bottom); return EdgeInsets.fromLTRB(_end + _left, _top, _start + _right, _bottom);
case TextDirection.ltr: case TextDirection.ltr:
return EdgeInsets.fromLTRB(_start + _left, _top, _end + _right, _bottom); return EdgeInsets.fromLTRB(_start + _left, _top, _end + _right, _bottom);
} }
return null;
} }
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
...@@ -23,7 +22,7 @@ import 'image_stream.dart'; ...@@ -23,7 +22,7 @@ import 'image_stream.dart';
typedef _KeyAndErrorHandlerCallback<T> = void Function(T key, ImageErrorListener handleError); typedef _KeyAndErrorHandlerCallback<T> = void Function(T key, ImageErrorListener handleError);
/// Signature used for error handling by [_createErrorHandlerAndKey]. /// Signature used for error handling by [_createErrorHandlerAndKey].
typedef _AsyncKeyErrorHandler<T> = Future<void> Function(T key, dynamic exception, StackTrace stack); typedef _AsyncKeyErrorHandler<T> = Future<void> Function(T key, dynamic exception, StackTrace? stack);
/// Configuration information passed to the [ImageProvider.resolve] method to /// Configuration information passed to the [ImageProvider.resolve] method to
/// select a specific image. /// select a specific image.
...@@ -54,12 +53,12 @@ class ImageConfiguration { ...@@ -54,12 +53,12 @@ class ImageConfiguration {
/// All the arguments are optional. Configuration information is merely /// All the arguments are optional. Configuration information is merely
/// advisory and best-effort. /// advisory and best-effort.
ImageConfiguration copyWith({ ImageConfiguration copyWith({
AssetBundle bundle, AssetBundle? bundle,
double devicePixelRatio, double? devicePixelRatio,
Locale locale, Locale? locale,
TextDirection textDirection, TextDirection? textDirection,
Size size, Size? size,
TargetPlatform platform, TargetPlatform? platform,
}) { }) {
return ImageConfiguration( return ImageConfiguration(
bundle: bundle ?? this.bundle, bundle: bundle ?? this.bundle,
...@@ -73,25 +72,25 @@ class ImageConfiguration { ...@@ -73,25 +72,25 @@ class ImageConfiguration {
/// The preferred [AssetBundle] to use if the [ImageProvider] needs one and /// The preferred [AssetBundle] to use if the [ImageProvider] needs one and
/// does not have one already selected. /// does not have one already selected.
final AssetBundle bundle; final AssetBundle? bundle;
/// The device pixel ratio where the image will be shown. /// The device pixel ratio where the image will be shown.
final double devicePixelRatio; final double? devicePixelRatio;
/// The language and region for which to select the image. /// The language and region for which to select the image.
final Locale locale; final Locale? locale;
/// The reading direction of the language for which to select the image. /// The reading direction of the language for which to select the image.
final TextDirection textDirection; final TextDirection? textDirection;
/// The size at which the image will be rendered. /// The size at which the image will be rendered.
final Size size; final Size? size;
/// The [TargetPlatform] for which assets should be used. This allows images /// The [TargetPlatform] for which assets should be used. This allows images
/// to be specified in a platform-neutral fashion yet use different assets on /// to be specified in a platform-neutral fashion yet use different assets on
/// different platforms, to match local conventions e.g. for color matching or /// different platforms, to match local conventions e.g. for color matching or
/// shadows. /// shadows.
final TargetPlatform platform; final TargetPlatform? platform;
/// An image configuration that provides no additional information. /// An image configuration that provides no additional information.
/// ///
...@@ -128,7 +127,7 @@ class ImageConfiguration { ...@@ -128,7 +127,7 @@ class ImageConfiguration {
if (devicePixelRatio != null) { if (devicePixelRatio != null) {
if (hasArguments) if (hasArguments)
result.write(', '); result.write(', ');
result.write('devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}'); result.write('devicePixelRatio: ${devicePixelRatio!.toStringAsFixed(1)}');
hasArguments = true; hasArguments = true;
} }
if (locale != null) { if (locale != null) {
...@@ -152,7 +151,7 @@ class ImageConfiguration { ...@@ -152,7 +151,7 @@ class ImageConfiguration {
if (platform != null) { if (platform != null) {
if (hasArguments) if (hasArguments)
result.write(', '); result.write(', ');
result.write('platform: ${describeEnum(platform)}'); result.write('platform: ${describeEnum(platform!)}');
hasArguments = true; hasArguments = true;
} }
result.write(')'); result.write(')');
...@@ -170,7 +169,7 @@ class ImageConfiguration { ...@@ -170,7 +169,7 @@ class ImageConfiguration {
/// ///
/// * [ResizeImage], which uses this to override the `cacheWidth`, /// * [ResizeImage], which uses this to override the `cacheWidth`,
/// `cacheHeight`, and `allowUpscaling` parameters. /// `cacheHeight`, and `allowUpscaling` parameters.
typedef DecoderCallback = Future<ui.Codec> Function(Uint8List bytes, {int cacheWidth, int cacheHeight, bool allowUpscaling}); typedef DecoderCallback = Future<ui.Codec> Function(Uint8List bytes, {int? cacheWidth, int? cacheHeight, bool allowUpscaling});
/// Identifies an image without committing to the precise final asset. This /// Identifies an image without committing to the precise final asset. This
/// allows a set of images to be identified and for the precise image to later /// allows a set of images to be identified and for the precise image to later
...@@ -306,7 +305,7 @@ typedef DecoderCallback = Future<ui.Codec> Function(Uint8List bytes, {int cacheW ...@@ -306,7 +305,7 @@ typedef DecoderCallback = Future<ui.Codec> Function(Uint8List bytes, {int cacheW
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
@optionalTypeArgs @optionalTypeArgs
abstract class ImageProvider<T> { abstract class ImageProvider<T extends Object> {
/// Abstract const constructor. This constructor enables subclasses to provide /// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions. /// const constructors so that they can be used in const expressions.
const ImageProvider(); const ImageProvider();
...@@ -333,11 +332,11 @@ abstract class ImageProvider<T> { ...@@ -333,11 +332,11 @@ abstract class ImageProvider<T> {
(T key, ImageErrorListener errorHandler) { (T key, ImageErrorListener errorHandler) {
resolveStreamForKey(configuration, stream, key, errorHandler); resolveStreamForKey(configuration, stream, key, errorHandler);
}, },
(T key, dynamic exception, StackTrace stack) async { (T? key, dynamic exception, StackTrace? stack) async {
await null; // wait an event turn in case a listener has been added to the image stream. await null; // wait an event turn in case a listener has been added to the image stream.
final _ErrorImageCompleter imageCompleter = _ErrorImageCompleter(); final _ErrorImageCompleter imageCompleter = _ErrorImageCompleter();
stream.setCompleter(imageCompleter); stream.setCompleter(imageCompleter);
InformationCollector collector; InformationCollector? collector;
assert(() { assert(() {
collector = () sync* { collector = () sync* {
yield DiagnosticsProperty<ImageProvider>('Image provider', this); yield DiagnosticsProperty<ImageProvider>('Image provider', this);
...@@ -379,21 +378,21 @@ abstract class ImageProvider<T> { ...@@ -379,21 +378,21 @@ abstract class ImageProvider<T> {
/// ///
/// A completed return value of null indicates that an error has occurred. /// A completed return value of null indicates that an error has occurred.
Future<ImageCacheStatus> obtainCacheStatus({ Future<ImageCacheStatus> obtainCacheStatus({
@required ImageConfiguration configuration, required ImageConfiguration configuration,
ImageErrorListener handleError, ImageErrorListener? handleError,
}) { }) {
assert(configuration != null); assert(configuration != null);
final Completer<ImageCacheStatus> completer = Completer<ImageCacheStatus>(); final Completer<ImageCacheStatus> completer = Completer<ImageCacheStatus>();
_createErrorHandlerAndKey( _createErrorHandlerAndKey(
configuration, configuration,
(T key, ImageErrorListener innerHandleError) { (T key, ImageErrorListener innerHandleError) {
completer.complete(PaintingBinding.instance.imageCache.statusForKey(key)); completer.complete(PaintingBinding.instance!.imageCache!.statusForKey(key));
}, },
(T key, dynamic exception, StackTrace stack) async { (T? key, dynamic exception, StackTrace? stack) async {
if (handleError != null) { if (handleError != null) {
handleError(exception, stack); handleError(exception, stack);
} else { } else {
InformationCollector collector; InformationCollector? collector;
assert(() { assert(() {
collector = () sync* { collector = () sync* {
yield DiagnosticsProperty<ImageProvider>('Image provider', this); yield DiagnosticsProperty<ImageProvider>('Image provider', this);
...@@ -402,12 +401,14 @@ abstract class ImageProvider<T> { ...@@ -402,12 +401,14 @@ abstract class ImageProvider<T> {
}; };
return true; return true;
}()); }());
FlutterError.onError(FlutterErrorDetails( if (FlutterError.onError != null) {
FlutterError.onError!(FlutterErrorDetails(
context: ErrorDescription('while checking the cache location of an image'), context: ErrorDescription('while checking the cache location of an image'),
informationCollector: collector, informationCollector: collector,
exception: exception, exception: exception,
stack: stack, stack: stack,
)); ));
}
completer.complete(null); completer.complete(null);
} }
}, },
...@@ -421,11 +422,11 @@ abstract class ImageProvider<T> { ...@@ -421,11 +422,11 @@ abstract class ImageProvider<T> {
void _createErrorHandlerAndKey( void _createErrorHandlerAndKey(
ImageConfiguration configuration, ImageConfiguration configuration,
_KeyAndErrorHandlerCallback<T> successCallback, _KeyAndErrorHandlerCallback<T> successCallback,
_AsyncKeyErrorHandler<T> errorCallback, _AsyncKeyErrorHandler<T?> errorCallback,
) { ) {
T obtainedKey; T? obtainedKey;
bool didError = false; bool didError = false;
Future<void> handleError(dynamic exception, StackTrace stack) async { Future<void> handleError(dynamic exception, StackTrace? stack) async {
if (didError) { if (didError) {
return; return;
} }
...@@ -492,17 +493,17 @@ abstract class ImageProvider<T> { ...@@ -492,17 +493,17 @@ abstract class ImageProvider<T> {
// the image we want before getting to this method. We should avoid calling // the image we want before getting to this method. We should avoid calling
// load again, but still update the image cache with LRU information. // load again, but still update the image cache with LRU information.
if (stream.completer != null) { if (stream.completer != null) {
final ImageStreamCompleter completer = PaintingBinding.instance.imageCache.putIfAbsent( final ImageStreamCompleter? completer = PaintingBinding.instance!.imageCache!.putIfAbsent(
key, key,
() => stream.completer, () => stream.completer!,
onError: handleError, onError: handleError,
); );
assert(identical(completer, stream.completer)); assert(identical(completer, stream.completer));
return; return;
} }
final ImageStreamCompleter completer = PaintingBinding.instance.imageCache.putIfAbsent( final ImageStreamCompleter? completer = PaintingBinding.instance!.imageCache!.putIfAbsent(
key, key,
() => load(key, PaintingBinding.instance.instantiateImageCodec), () => load(key, PaintingBinding.instance!.instantiateImageCodec),
onError: handleError, onError: handleError,
); );
if (completer != null) { if (completer != null) {
...@@ -548,10 +549,10 @@ abstract class ImageProvider<T> { ...@@ -548,10 +549,10 @@ abstract class ImageProvider<T> {
/// } /// }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
Future<bool> evict({ ImageCache cache, ImageConfiguration configuration = ImageConfiguration.empty }) async { Future<bool> evict({ ImageCache? cache, ImageConfiguration configuration = ImageConfiguration.empty }) async {
cache ??= imageCache; cache ??= imageCache;
final T key = await obtainKey(configuration); final T key = await obtainKey(configuration);
return cache.evict(key); return cache!.evict(key);
} }
/// Converts an ImageProvider's settings plus an ImageConfiguration to a key /// Converts an ImageProvider's settings plus an ImageConfiguration to a key
...@@ -590,9 +591,9 @@ class AssetBundleImageKey { ...@@ -590,9 +591,9 @@ class AssetBundleImageKey {
/// ///
/// The arguments must not be null. /// The arguments must not be null.
const AssetBundleImageKey({ const AssetBundleImageKey({
@required this.bundle, required this.bundle,
@required this.name, required this.name,
@required this.scale, required this.scale,
}) : assert(bundle != null), }) : assert(bundle != null),
assert(name != null), assert(name != null),
assert(scale != null); assert(scale != null);
...@@ -640,7 +641,7 @@ abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKe ...@@ -640,7 +641,7 @@ abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKe
/// image. /// image.
@override @override
ImageStreamCompleter load(AssetBundleImageKey key, DecoderCallback decode) { ImageStreamCompleter load(AssetBundleImageKey key, DecoderCallback decode) {
InformationCollector collector; InformationCollector? collector;
assert(() { assert(() {
collector = () sync* { collector = () sync* {
yield DiagnosticsProperty<ImageProvider>('Image provider', this); yield DiagnosticsProperty<ImageProvider>('Image provider', this);
...@@ -662,17 +663,17 @@ abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKe ...@@ -662,17 +663,17 @@ abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKe
/// This function is used by [load]. /// This function is used by [load].
@protected @protected
Future<ui.Codec> _loadAsync(AssetBundleImageKey key, DecoderCallback decode) async { Future<ui.Codec> _loadAsync(AssetBundleImageKey key, DecoderCallback decode) async {
ByteData data; ByteData? data;
// Hot reload/restart could change whether an asset bundle or key in a // Hot reload/restart could change whether an asset bundle or key in a
// bundle are available, or if it is a network backed bundle. // bundle are available, or if it is a network backed bundle.
try { try {
data = await key.bundle.load(key.name); data = await key.bundle.load(key.name);
} on FlutterError { } on FlutterError {
PaintingBinding.instance.imageCache.evict(key); PaintingBinding.instance!.imageCache!.evict(key);
rethrow; rethrow;
} }
if (data == null) { if (data == null) {
PaintingBinding.instance.imageCache.evict(key); PaintingBinding.instance!.imageCache!.evict(key);
throw StateError('Unable to read data'); throw StateError('Unable to read data');
} }
return await decode(data.buffer.asUint8List()); return await decode(data.buffer.asUint8List());
...@@ -685,9 +686,9 @@ class _SizeAwareCacheKey { ...@@ -685,9 +686,9 @@ class _SizeAwareCacheKey {
final Object providerCacheKey; final Object providerCacheKey;
final int width; final int? width;
final int height; final int? height;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
...@@ -729,10 +730,10 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> { ...@@ -729,10 +730,10 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
final ImageProvider imageProvider; final ImageProvider imageProvider;
/// The width the image should decode to and cache. /// The width the image should decode to and cache.
final int width; final int? width;
/// The height the image should decode to and cache. /// The height the image should decode to and cache.
final int height; final int? height;
/// Whether the [width] and [height] parameters should be clamped to the /// Whether the [width] and [height] parameters should be clamped to the
/// intrinsic width and height of the image. /// intrinsic width and height of the image.
...@@ -748,7 +749,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> { ...@@ -748,7 +749,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
/// ///
/// When `cacheWidth` and `cacheHeight` are both null, this will return the /// When `cacheWidth` and `cacheHeight` are both null, this will return the
/// `provider` directly. /// `provider` directly.
static ImageProvider<dynamic> resizeIfNeeded(int cacheWidth, int cacheHeight, ImageProvider<dynamic> provider) { static ImageProvider<Object> resizeIfNeeded(int? cacheWidth, int? cacheHeight, ImageProvider<Object> provider) {
if (cacheWidth != null || cacheHeight != null) { if (cacheWidth != null || cacheHeight != null) {
return ResizeImage(provider, width: cacheWidth, height: cacheHeight); return ResizeImage(provider, width: cacheWidth, height: cacheHeight);
} }
...@@ -757,7 +758,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> { ...@@ -757,7 +758,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
@override @override
ImageStreamCompleter load(_SizeAwareCacheKey key, DecoderCallback decode) { ImageStreamCompleter load(_SizeAwareCacheKey key, DecoderCallback decode) {
final DecoderCallback decodeResize = (Uint8List bytes, {int cacheWidth, int cacheHeight, bool allowUpscaling}) { final DecoderCallback decodeResize = (Uint8List bytes, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) {
assert( assert(
cacheWidth == null && cacheHeight == null && allowUpscaling == null, cacheWidth == null && cacheHeight == null && allowUpscaling == null,
'ResizeImage cannot be composed with another ImageProvider that applies ' 'ResizeImage cannot be composed with another ImageProvider that applies '
...@@ -774,10 +775,10 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> { ...@@ -774,10 +775,10 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
@override @override
Future<_SizeAwareCacheKey> obtainKey(ImageConfiguration configuration) { Future<_SizeAwareCacheKey> obtainKey(ImageConfiguration configuration) {
Completer<_SizeAwareCacheKey> completer; Completer<_SizeAwareCacheKey>? completer;
// If the imageProvider.obtainKey future is synchronous, then we will be able to fill in result with // If the imageProvider.obtainKey future is synchronous, then we will be able to fill in result with
// a value before completer is initialized below. // a value before completer is initialized below.
SynchronousFuture<_SizeAwareCacheKey> result; SynchronousFuture<_SizeAwareCacheKey>? result;
imageProvider.obtainKey(configuration).then((Object key) { imageProvider.obtainKey(configuration).then((Object key) {
if (completer == null) { if (completer == null) {
// This future has completed synchronously (completer was never assigned), // This future has completed synchronously (completer was never assigned),
...@@ -789,7 +790,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> { ...@@ -789,7 +790,7 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
} }
}); });
if (result != null) { if (result != null) {
return result; return result!;
} }
// If the code reaches here, it means the imageProvider.obtainKey was not // If the code reaches here, it means the imageProvider.obtainKey was not
// completed sync, so we initialize the completer for completion later. // completed sync, so we initialize the completer for completion later.
...@@ -817,7 +818,7 @@ abstract class NetworkImage extends ImageProvider<NetworkImage> { ...@@ -817,7 +818,7 @@ abstract class NetworkImage extends ImageProvider<NetworkImage> {
/// Creates an object that fetches the image at the given URL. /// Creates an object that fetches the image at the given URL.
/// ///
/// The arguments [url] and [scale] must not be null. /// The arguments [url] and [scale] must not be null.
const factory NetworkImage(String url, { double scale, Map<String, String> headers }) = network_image.NetworkImage; const factory NetworkImage(String url, { double scale, Map<String, String>? headers }) = network_image.NetworkImage;
/// The URL from which the image will be fetched. /// The URL from which the image will be fetched.
String get url; String get url;
...@@ -828,7 +829,7 @@ abstract class NetworkImage extends ImageProvider<NetworkImage> { ...@@ -828,7 +829,7 @@ abstract class NetworkImage extends ImageProvider<NetworkImage> {
/// The HTTP headers that will be used with [HttpClient.get] to fetch image from network. /// The HTTP headers that will be used with [HttpClient.get] to fetch image from network.
/// ///
/// When running flutter on the web, headers are not used. /// When running flutter on the web, headers are not used.
Map<String, String> get headers; Map<String, String>? get headers;
@override @override
ImageStreamCompleter load(NetworkImage key, DecoderCallback decode); ImageStreamCompleter load(NetworkImage key, DecoderCallback decode);
...@@ -870,7 +871,7 @@ class FileImage extends ImageProvider<FileImage> { ...@@ -870,7 +871,7 @@ class FileImage extends ImageProvider<FileImage> {
scale: key.scale, scale: key.scale,
debugLabel: key.file.path, debugLabel: key.file.path,
informationCollector: () sync* { informationCollector: () sync* {
yield ErrorDescription('Path: ${file?.path}'); yield ErrorDescription('Path: ${file.path}');
}, },
); );
} }
...@@ -882,7 +883,7 @@ class FileImage extends ImageProvider<FileImage> { ...@@ -882,7 +883,7 @@ class FileImage extends ImageProvider<FileImage> {
if (bytes.lengthInBytes == 0) { if (bytes.lengthInBytes == 0) {
// The file may become available later. // The file may become available later.
PaintingBinding.instance.imageCache.evict(key); PaintingBinding.instance!.imageCache!.evict(key);
throw StateError('$file is empty and cannot be loaded as an image.'); throw StateError('$file is empty and cannot be loaded as an image.');
} }
...@@ -894,15 +895,15 @@ class FileImage extends ImageProvider<FileImage> { ...@@ -894,15 +895,15 @@ class FileImage extends ImageProvider<FileImage> {
if (other.runtimeType != runtimeType) if (other.runtimeType != runtimeType)
return false; return false;
return other is FileImage return other is FileImage
&& other.file?.path == file?.path && other.file.path == file.path
&& other.scale == scale; && other.scale == scale;
} }
@override @override
int get hashCode => hashValues(file?.path, scale); int get hashCode => hashValues(file.path, scale);
@override @override
String toString() => '${objectRuntimeType(this, 'FileImage')}("${file?.path}", scale: $scale)'; String toString() => '${objectRuntimeType(this, 'FileImage')}("${file.path}", scale: $scale)';
} }
/// Decodes the given [Uint8List] buffer as an image, associating it with the /// Decodes the given [Uint8List] buffer as an image, associating it with the
...@@ -1075,11 +1076,11 @@ class ExactAssetImage extends AssetBundleImageProvider { ...@@ -1075,11 +1076,11 @@ class ExactAssetImage extends AssetBundleImageProvider {
/// ///
/// The image is obtained by calling [AssetBundle.load] on the given [bundle] /// The image is obtained by calling [AssetBundle.load] on the given [bundle]
/// using the key given by [keyName]. /// using the key given by [keyName].
final AssetBundle bundle; final AssetBundle? bundle;
/// The name of the package from which the image is included. See the /// The name of the package from which the image is included. See the
/// documentation for the [ExactAssetImage] class itself for details. /// documentation for the [ExactAssetImage] class itself for details.
final String package; final String? package;
@override @override
Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) { Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
...@@ -1112,10 +1113,10 @@ class _ErrorImageCompleter extends ImageStreamCompleter { ...@@ -1112,10 +1113,10 @@ class _ErrorImageCompleter extends ImageStreamCompleter {
_ErrorImageCompleter(); _ErrorImageCompleter();
void setError({ void setError({
DiagnosticsNode context, DiagnosticsNode? context,
dynamic exception, dynamic exception,
StackTrace stack, StackTrace? stack,
InformationCollector informationCollector, InformationCollector? informationCollector,
bool silent = false, bool silent = false,
}) { }) {
reportError( reportError(
...@@ -1132,7 +1133,7 @@ class _ErrorImageCompleter extends ImageStreamCompleter { ...@@ -1132,7 +1133,7 @@ class _ErrorImageCompleter extends ImageStreamCompleter {
class NetworkImageLoadException implements Exception { class NetworkImageLoadException implements Exception {
/// Creates a [NetworkImageLoadException] with the specified http [statusCode] /// Creates a [NetworkImageLoadException] with the specified http [statusCode]
/// and [uri]. /// and [uri].
NetworkImageLoadException({@required this.statusCode, @required this.uri}) NetworkImageLoadException({required this.statusCode, required this.uri})
: assert(uri != null), : assert(uri != null),
assert(statusCode != null), assert(statusCode != null),
_message = 'HTTP request failed, statusCode: $statusCode, $uri'; _message = 'HTTP request failed, statusCode: $statusCode, $uri';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment