Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
66659229
Unverified
Commit
66659229
authored
Feb 03, 2021
by
Ian Hickson
Committed by
GitHub
Feb 03, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Show an X when images can't load. (#74972)
parent
69882d96
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
384 additions
and
195 deletions
+384
-195
constants.dart
packages/flutter/lib/src/foundation/constants.dart
+28
-0
image_stream.dart
packages/flutter/lib/src/painting/image_stream.dart
+35
-19
image.dart
packages/flutter/lib/src/widgets/image.dart
+42
-6
image_filter_quality_test.dart
packages/flutter/test/widgets/image_filter_quality_test.dart
+156
-0
image_test.dart
packages/flutter/test/widgets/image_test.dart
+123
-170
No files found.
packages/flutter/lib/src/foundation/constants.dart
View file @
66659229
...
...
@@ -10,6 +10,15 @@
/// Since this is a const value, it can be used to indicate to the compiler that
/// a particular block of code will not be executed in release mode, and hence
/// can be removed.
///
/// Generally it is better to use [kDebugMode] or `assert` to gate code, since
/// using [kReleaseMode] will introduce differences between release and profile
/// builds, which makes performance testing less representative.
///
/// See also:
///
/// * [kDebugMode], which is true in debug builds.
/// * [kProfileMode], which is true in profile builds.
const
bool
kReleaseMode
=
bool
.
fromEnvironment
(
'dart.vm.product'
,
defaultValue:
false
);
/// A constant that is true if the application was compiled in profile mode.
...
...
@@ -20,6 +29,11 @@ const bool kReleaseMode = bool.fromEnvironment('dart.vm.product', defaultValue:
/// Since this is a const value, it can be used to indicate to the compiler that
/// a particular block of code will not be executed in profile mode, an hence
/// can be removed.
///
/// See also:
///
/// * [kDebugMode], which is true in debug builds.
/// * [kReleaseMode], which is true in release builds.
const
bool
kProfileMode
=
bool
.
fromEnvironment
(
'dart.vm.profile'
,
defaultValue:
false
);
/// A constant that is true if the application was compiled in debug mode.
...
...
@@ -30,6 +44,20 @@ const bool kProfileMode = bool.fromEnvironment('dart.vm.profile', defaultValue:
/// Since this is a const value, it can be used to indicate to the compiler that
/// a particular block of code will not be executed in debug mode, and hence
/// can be removed.
///
/// An alternative strategy is to use asserts, as in:
///
/// ```dart
/// assert(() {
/// // ...debug-only code here...
/// return true;
/// }());
/// ```
///
/// See also:
///
/// * [kReleaseMode], which is true in release builds.
/// * [kProfileMode], which is true in profile builds.
const
bool
kDebugMode
=
!
kReleaseMode
&&
!
kProfileMode
;
/// The epsilon of tolerable double precision error.
...
...
packages/flutter/lib/src/painting/image_stream.dart
View file @
66659229
...
...
@@ -194,6 +194,15 @@ class ImageStreamListener {
///
/// If an error occurs during loading, [onError] will be called instead of
/// [onImage].
///
/// If [onError] is called and does not throw, then the error is considered to
/// be handled. An error handler can explicitly rethrow the exception reported
/// to it to safely indicate that it did not handle the exception.
///
/// If an image stream has no listeners that handled the error when the error
/// was first encountered, then the error is reported using
/// [FlutterError.reportError], with the [FlutterErrorDetails.silent] flag set
/// to true.
final
ImageErrorListener
?
onError
;
@override
...
...
@@ -504,15 +513,17 @@ abstract class ImageStreamCompleter with Diagnosticable {
if
(
_currentError
!=
null
&&
listener
.
onError
!=
null
)
{
try
{
listener
.
onError
!(
_currentError
!.
exception
,
_currentError
!.
stack
);
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
exception
,
library
:
'image resource service'
,
context:
ErrorDescription
(
'by a synchronously-called image error listener'
),
stack:
stack
,
),
);
}
catch
(
newException
,
newStack
)
{
if
(
newException
!=
_currentError
!.
exception
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
newException
,
library
:
'image resource service'
,
context:
ErrorDescription
(
'by a synchronously-called image error listener'
),
stack:
newStack
,
),
);
}
}
}
}
...
...
@@ -630,7 +641,9 @@ abstract class ImageStreamCompleter with Diagnosticable {
/// occurred while resolving the image.
///
/// If no error listeners (listeners with an [ImageStreamListener.onError]
/// specified) are attached, a [FlutterError] will be reported instead.
/// specified) are attached, or if the handlers all rethrow the exception
/// verbatim (with `throw exception`), a [FlutterError] will be reported using
/// [FlutterError.reportError].
///
/// The `context` should be a string describing where the error was caught, in
/// a form that will make sense in English when following the word "thrown",
...
...
@@ -677,24 +690,27 @@ abstract class ImageStreamCompleter with Diagnosticable {
.
whereType
<
ImageErrorListener
>()
.
toList
();
if
(
localErrorListeners
.
isEmpty
)
{
FlutterError
.
reportError
(
_currentError
!);
}
else
{
for
(
final
ImageErrorListener
errorListener
in
localErrorListeners
)
{
try
{
errorListener
(
exception
,
stack
);
}
catch
(
exception
,
stack
)
{
bool
handled
=
false
;
for
(
final
ImageErrorListener
errorListener
in
localErrorListeners
)
{
try
{
errorListener
(
exception
,
stack
);
handled
=
true
;
}
catch
(
newException
,
newStack
)
{
if
(
newException
!=
exception
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
context:
ErrorDescription
(
'when reporting an error to an image listener'
),
library
:
'image resource service'
,
exception:
e
xception
,
stack:
s
tack
,
exception:
newE
xception
,
stack:
newS
tack
,
),
);
}
}
}
if
(!
handled
)
{
FlutterError
.
reportError
(
_currentError
!);
}
}
/// Calls all the registered [ImageChunkListener]s (listeners with an
...
...
packages/flutter/lib/src/widgets/image.dart
View file @
66659229
...
...
@@ -17,7 +17,9 @@ import 'disposable_build_context.dart';
import
'framework.dart'
;
import
'localizations.dart'
;
import
'media_query.dart'
;
import
'placeholder.dart'
;
import
'scroll_aware_image_provider.dart'
;
import
'text.dart'
;
import
'ticker_provider.dart'
;
export
'package:flutter/painting.dart'
show
...
...
@@ -471,7 +473,6 @@ class Image extends StatefulWidget {
assert
(
isAntiAlias
!=
null
),
super
(
key:
key
);
// TODO(ianh): Implement the following (see ../services/image_resolution.dart):
//
// * If [width] and [height] are both specified, and [scale] is not, then
...
...
@@ -1176,12 +1177,17 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
_imageStreamListener
=
ImageStreamListener
(
_handleImageFrame
,
onChunk:
widget
.
loadingBuilder
==
null
?
null
:
_handleImageChunk
,
onError:
widget
.
errorBuilder
!=
null
?
(
dynamic
error
,
StackTrace
?
stackTrace
)
{
onError:
widget
.
errorBuilder
!=
null
||
kDebugMode
?
(
Object
error
,
StackTrace
?
stackTrace
)
{
setState
(()
{
_lastException
=
error
;
_lastStack
=
stackTrace
;
});
assert
(()
{
if
(
widget
.
errorBuilder
==
null
)
throw
error
;
// Ensures the error message is printed to the console.
return
true
;
}());
}
:
null
,
);
...
...
@@ -1268,11 +1274,41 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
_isListeningToStream
=
false
;
}
Widget
_debugBuildErrorWidget
(
BuildContext
context
,
Object
error
)
{
return
Stack
(
alignment:
Alignment
.
center
,
children:
<
Widget
>[
const
Positioned
.
fill
(
child:
Placeholder
(
color:
Color
(
0xCF8D021F
),
),
),
Padding
(
padding:
const
EdgeInsets
.
all
(
4.0
),
child:
FittedBox
(
child:
Text
(
'
$error
'
,
textAlign:
TextAlign
.
center
,
textDirection:
TextDirection
.
ltr
,
style:
const
TextStyle
(
shadows:
<
Shadow
>[
Shadow
(
blurRadius:
1.0
),
],
),
),
),
),
],
);
}
@override
Widget
build
(
BuildContext
context
)
{
if
(
_lastException
!=
null
)
{
assert
(
widget
.
errorBuilder
!=
null
);
return
widget
.
errorBuilder
!(
context
,
_lastException
!,
_lastStack
);
if
(
_lastException
!=
null
)
{
if
(
widget
.
errorBuilder
!=
null
)
return
widget
.
errorBuilder
!(
context
,
_lastException
!,
_lastStack
);
if
(
kDebugMode
)
return
_debugBuildErrorWidget
(
context
,
_lastException
!);
}
Widget
result
=
RawImage
(
...
...
packages/flutter/test/widgets/image_filter_quality_test.dart
0 → 100644
View file @
66659229
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:typed_data'
;
import
'dart:ui'
as
ui
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
testWidgets
(
'Image at default filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
null
);
});
testWidgets
(
'Image at high filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
ui
.
FilterQuality
.
high
);
});
testWidgets
(
'Image at none filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
ui
.
FilterQuality
.
none
);
});
}
Future
<
void
>
testImageQuality
(
WidgetTester
tester
,
ui
.
FilterQuality
?
quality
)
async
{
await
tester
.
binding
.
setSurfaceSize
(
const
ui
.
Size
(
3
,
3
));
// A 3x3 image encoded as PNG with white background and black pixels on the diagonal:
// ┌──────┐
// │▓▓ │
// │ ▓▓ │
// │ ▓▓│
// └──────┘
// At different levels of quality these pixels are blurred differently.
final
Uint8List
test3x3Image
=
Uint8List
.
fromList
(<
int
>[
0x89
,
0x50
,
0x4e
,
0x47
,
0x0d
,
0x0a
,
0x1a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x0d
,
0x49
,
0x48
,
0x44
,
0x52
,
0x00
,
0x00
,
0x00
,
0x03
,
0x00
,
0x00
,
0x00
,
0x03
,
0x08
,
0x02
,
0x00
,
0x00
,
0x00
,
0xd9
,
0x4a
,
0x22
,
0xe8
,
0x00
,
0x00
,
0x00
,
0x1b
,
0x49
,
0x44
,
0x41
,
0x54
,
0x08
,
0xd7
,
0x63
,
0x64
,
0x60
,
0x60
,
0xf8
,
0xff
,
0xff
,
0x3f
,
0x03
,
0x9c
,
0xfa
,
0xff
,
0xff
,
0x3f
,
0xc3
,
0xff
,
0xff
,
0xff
,
0x21
,
0x1c
,
0x00
,
0xcb
,
0x70
,
0x0e
,
0xf3
,
0x5d
,
0x11
,
0xc2
,
0xf8
,
0x00
,
0x00
,
0x00
,
0x00
,
0x49
,
0x45
,
0x4e
,
0x44
,
0xae
,
0x42
,
0x60
,
0x82
,
]);
final
ui
.
Image
image
=
(
await
tester
.
runAsync
(()
async
{
final
ui
.
Codec
codec
=
await
ui
.
instantiateImageCodec
(
test3x3Image
);
return
(
await
codec
.
getNextFrame
()).
image
;
}))!;
expect
(
image
.
width
,
3
);
expect
(
image
.
height
,
3
);
final
_TestImageStreamCompleter
streamCompleter
=
_TestImageStreamCompleter
();
streamCompleter
.
setData
(
imageInfo:
ImageInfo
(
image:
image
));
final
_TestImageProvider
imageProvider
=
_TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
quality
==
null
?
Image
(
image:
imageProvider
)
:
Image
(
image:
imageProvider
,
filterQuality:
quality
,
),
);
await
expectLater
(
find
.
byType
(
Image
),
matchesGoldenFile
(
'image_quality_
${quality ?? 'default'}
.png'
),
);
}
class
_TestImageStreamCompleter
extends
ImageStreamCompleter
{
_TestImageStreamCompleter
([
this
.
_currentImage
]);
ImageInfo
?
_currentImage
;
final
Set
<
ImageStreamListener
>
listeners
=
<
ImageStreamListener
>{};
@override
void
addListener
(
ImageStreamListener
listener
)
{
listeners
.
add
(
listener
);
if
(
_currentImage
!=
null
)
{
listener
.
onImage
(
_currentImage
!.
clone
(),
true
);
}
}
@override
void
removeListener
(
ImageStreamListener
listener
)
{
listeners
.
remove
(
listener
);
}
void
setData
({
ImageInfo
?
imageInfo
,
ImageChunkEvent
?
chunkEvent
,
})
{
if
(
imageInfo
!=
null
)
{
_currentImage
?.
dispose
();
_currentImage
=
imageInfo
;
}
final
List
<
ImageStreamListener
>
localListeners
=
listeners
.
toList
();
for
(
final
ImageStreamListener
listener
in
localListeners
)
{
if
(
imageInfo
!=
null
)
{
listener
.
onImage
(
imageInfo
.
clone
(),
false
);
}
if
(
chunkEvent
!=
null
&&
listener
.
onChunk
!=
null
)
{
listener
.
onChunk
!(
chunkEvent
);
}
}
}
void
setError
({
required
Object
exception
,
StackTrace
?
stackTrace
,
})
{
final
List
<
ImageStreamListener
>
localListeners
=
listeners
.
toList
();
for
(
final
ImageStreamListener
listener
in
localListeners
)
{
if
(
listener
.
onError
!=
null
)
{
listener
.
onError
!(
exception
,
stackTrace
);
}
}
}
}
class
_TestImageProvider
extends
ImageProvider
<
Object
>
{
_TestImageProvider
({
ImageStreamCompleter
?
streamCompleter
})
{
_streamCompleter
=
streamCompleter
??
OneFrameImageStreamCompleter
(
_completer
.
future
);
}
final
Completer
<
ImageInfo
>
_completer
=
Completer
<
ImageInfo
>();
late
ImageStreamCompleter
_streamCompleter
;
bool
get
loadCalled
=>
_loadCallCount
>
0
;
int
get
loadCallCount
=>
_loadCallCount
;
int
_loadCallCount
=
0
;
@override
Future
<
Object
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
_TestImageProvider
>(
this
);
}
@override
ImageStreamCompleter
load
(
Object
key
,
DecoderCallback
decode
)
{
_loadCallCount
+=
1
;
return
_streamCompleter
;
}
void
complete
(
ui
.
Image
image
)
{
_completer
.
complete
(
ImageInfo
(
image:
image
));
}
void
fail
(
Object
exception
,
StackTrace
?
stackTrace
)
{
_completer
.
completeError
(
exception
,
stackTrace
);
}
@override
String
toString
()
=>
'
${describeIdentity(this)}
()'
;
}
packages/flutter/test/widgets/image_test.dart
View file @
66659229
...
...
@@ -33,7 +33,7 @@ void main() {
testWidgets
(
'Verify Image resets its RenderImage when changing providers'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -55,7 +55,7 @@ void main() {
renderImage
=
key
.
currentContext
!.
findRenderObject
()!
as
RenderImage
;
expect
(
renderImage
.
image
,
isNotNull
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -74,7 +74,7 @@ void main() {
testWidgets
(
"Verify Image doesn't reset its RenderImage when changing providers if it has gaplessPlayback set"
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -97,7 +97,7 @@ void main() {
renderImage
=
key
.
currentContext
!.
findRenderObject
()!
as
RenderImage
;
expect
(
renderImage
.
image
,
isNotNull
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -117,7 +117,7 @@ void main() {
testWidgets
(
'Verify Image resets its RenderImage when changing providers if it has a key'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Image
(
key:
key
,
...
...
@@ -137,7 +137,7 @@ void main() {
renderImage
=
key
.
currentContext
!.
findRenderObject
()!
as
RenderImage
;
expect
(
renderImage
.
image
,
isNotNull
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Image
(
key:
key
,
...
...
@@ -154,7 +154,7 @@ void main() {
testWidgets
(
"Verify Image doesn't reset its RenderImage when changing providers if it has gaplessPlayback set"
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Image
(
key:
key
,
...
...
@@ -175,7 +175,7 @@ void main() {
renderImage
=
key
.
currentContext
!.
findRenderObject
()!
as
RenderImage
;
expect
(
renderImage
.
image
,
isNotNull
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Image
(
key:
key
,
...
...
@@ -195,9 +195,9 @@ void main() {
final
GlobalKey
mediaQueryKey1
=
GlobalKey
(
debugLabel:
'mediaQueryKey1'
);
final
GlobalKey
mediaQueryKey2
=
GlobalKey
(
debugLabel:
'mediaQueryKey2'
);
final
GlobalKey
imageKey
=
GlobalKey
(
debugLabel:
'image'
);
final
ConfigurationKeyedTestImageProvider
imageProvider
=
ConfigurationKeyedTestImageProvider
();
final
_ConfigurationKeyedTestImageProvider
imageProvider
=
_
ConfigurationKeyedTestImageProvider
();
final
Set
<
Object
>
seenKeys
=
<
Object
>{};
final
DebouncingImageProvider
debouncingProvider
=
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
final
_DebouncingImageProvider
debouncingProvider
=
_
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
// Of the two nested MediaQuery objects, the innermost one,
// mediaQuery2, should define the configuration of the imageProvider.
...
...
@@ -257,9 +257,9 @@ void main() {
final
GlobalKey
mediaQueryKey1
=
GlobalKey
(
debugLabel:
'mediaQueryKey1'
);
final
GlobalKey
mediaQueryKey2
=
GlobalKey
(
debugLabel:
'mediaQueryKey2'
);
final
GlobalKey
imageKey
=
GlobalKey
(
debugLabel:
'image'
);
final
ConfigurationKeyedTestImageProvider
imageProvider
=
ConfigurationKeyedTestImageProvider
();
final
_ConfigurationKeyedTestImageProvider
imageProvider
=
_
ConfigurationKeyedTestImageProvider
();
final
Set
<
Object
>
seenKeys
=
<
Object
>{};
final
DebouncingImageProvider
debouncingProvider
=
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
final
_DebouncingImageProvider
debouncingProvider
=
_
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
// This is just a variation on the previous test. In this version the location
// of the Image changes and the MediaQuery widgets do not.
...
...
@@ -328,9 +328,9 @@ void main() {
final
GlobalKey
mediaQueryKey1
=
GlobalKey
(
debugLabel:
'mediaQueryKey1'
);
final
GlobalKey
mediaQueryKey2
=
GlobalKey
(
debugLabel:
'mediaQueryKey2'
);
final
GlobalKey
imageKey
=
GlobalKey
(
debugLabel:
'image'
);
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
final
Set
<
Object
>
seenKeys
=
<
Object
>{};
final
DebouncingImageProvider
debouncingProvider
=
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
final
_DebouncingImageProvider
debouncingProvider
=
_
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
// Of the two nested MediaQuery objects, the innermost one,
// mediaQuery2, should define the configuration of the imageProvider.
...
...
@@ -390,9 +390,9 @@ void main() {
final
GlobalKey
mediaQueryKey1
=
GlobalKey
(
debugLabel:
'mediaQueryKey1'
);
final
GlobalKey
mediaQueryKey2
=
GlobalKey
(
debugLabel:
'mediaQueryKey2'
);
final
GlobalKey
imageKey
=
GlobalKey
(
debugLabel:
'image'
);
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
final
Set
<
Object
>
seenKeys
=
<
Object
>{};
final
DebouncingImageProvider
debouncingProvider
=
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
final
_DebouncingImageProvider
debouncingProvider
=
_
DebouncingImageProvider
(
imageProvider
,
seenKeys
);
// This is just a variation on the previous test. In this version the location
// of the Image changes and the MediaQuery widgets do not.
...
...
@@ -462,7 +462,7 @@ void main() {
// Web does not override the toString, whereas VM does
final
String
imageString
=
image100x100
.
toString
();
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Image
(
image:
imageProvider
,
excludeFromSemantics:
true
));
final
State
<
Image
>
image
=
tester
.
state
/*State<Image>*/
(
find
.
byType
(
Image
));
expect
(
image
.
toString
(),
equalsIgnoringHashCodes
(
'_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, unresolved, 2 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)'
));
...
...
@@ -487,7 +487,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
late
ImageConfiguration
configuration
;
await
tester
.
pumpWidget
(
...
...
@@ -533,7 +533,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
late
ImageConfiguration
configuration
;
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -578,7 +578,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
// Add the exact same listener a second time without the errorListener.
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
));
...
...
@@ -622,7 +622,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
// Add the exact same errorListener a second time.
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
...
...
@@ -667,7 +667,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
// Now remove the listener the error listener is attached to.
// Don't explicitly remove the error listener.
...
...
@@ -707,7 +707,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
// Duplicates the same set of listener and errorListener.
imageProvider
.
_streamCompleter
.
addListener
(
ImageStreamListener
(
listener
,
onError:
errorListener
));
...
...
@@ -743,7 +743,7 @@ void main() {
await
tester
.
pumpWidget
(
Image
(
excludeFromSemantics:
true
,
image:
TestImageProvider
(),
image:
_
TestImageProvider
(),
color:
const
Color
(
0xFF00FF00
),
colorBlendMode:
BlendMode
.
clear
,
),
...
...
@@ -754,7 +754,7 @@ void main() {
});
testWidgets
(
'Precache'
,
(
WidgetTester
tester
)
async
{
final
TestImageProvider
provider
=
TestImageProvider
();
final
_TestImageProvider
provider
=
_
TestImageProvider
();
late
Future
<
void
>
precache
;
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -776,8 +776,8 @@ void main() {
});
testWidgets
(
'Precache removes original listener immediately after future completes, does not crash on successive calls #25143'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
imageStreamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
provider
=
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
final
_TestImageStreamCompleter
imageStreamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
provider
=
_
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -812,7 +812,7 @@ void main() {
final
Exception
testException
=
Exception
(
'cannot resolve host'
);
final
StackTrace
testStack
=
StackTrace
.
current
;
final
TestImageProvider
imageProvider
=
TestImageProvider
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
();
late
Future
<
void
>
precache
;
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -833,10 +833,10 @@ void main() {
});
testWidgets
(
'TickerMode controls stream registration'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
imageStreamCompleter
=
TestImageStreamCompleter
();
final
_TestImageStreamCompleter
imageStreamCompleter
=
_
TestImageStreamCompleter
();
final
Image
image
=
Image
(
excludeFromSemantics:
true
,
image:
TestImageProvider
(
streamCompleter:
imageStreamCompleter
),
image:
_
TestImageProvider
(
streamCompleter:
imageStreamCompleter
),
);
await
tester
.
pumpWidget
(
TickerMode
(
...
...
@@ -857,8 +857,8 @@ void main() {
testWidgets
(
'Verify Image shows correct RenderImage when changing to an already completed provider'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
();
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
final
ui
.
Image
image100x100
=
(
await
tester
.
runAsync
(()
async
=>
createTestImage
(
width:
100
,
height:
100
)))!;
await
tester
.
pumpWidget
(
...
...
@@ -903,8 +903,8 @@ void main() {
});
testWidgets
(
'Image State can be reconfigured to use another image'
,
(
WidgetTester
tester
)
async
{
final
Image
image1
=
Image
(
image:
TestImageProvider
()..
complete
(
image10x10
.
clone
()),
width:
10.0
,
excludeFromSemantics:
true
);
final
Image
image2
=
Image
(
image:
TestImageProvider
()..
complete
(
image10x10
.
clone
()),
width:
20.0
,
excludeFromSemantics:
true
);
final
Image
image1
=
Image
(
image:
_
TestImageProvider
()..
complete
(
image10x10
.
clone
()),
width:
10.0
,
excludeFromSemantics:
true
);
final
Image
image2
=
Image
(
image:
_
TestImageProvider
()..
complete
(
image10x10
.
clone
()),
width:
20.0
,
excludeFromSemantics:
true
);
final
Column
column
=
Column
(
children:
<
Widget
>[
image1
,
image2
]);
await
tester
.
pumpWidget
(
column
,
null
,
EnginePhase
.
layout
);
...
...
@@ -928,7 +928,7 @@ void main() {
child:
Row
(
children:
<
Widget
>[
Image
(
image:
TestImageProvider
(),
image:
_
TestImageProvider
(),
width:
100.0
,
height:
100.0
,
semanticLabel:
'test'
,
...
...
@@ -958,7 +958,7 @@ void main() {
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Image
(
image:
TestImageProvider
(),
image:
_
TestImageProvider
(),
width:
100.0
,
height:
100.0
,
excludeFromSemantics:
true
,
...
...
@@ -982,8 +982,8 @@ void main() {
return
frameInfo
.
image
;
}
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
int
?
lastFrame
;
await
tester
.
pumpWidget
(
...
...
@@ -1012,8 +1012,8 @@ void main() {
});
testWidgets
(
'Image invokes frameBuilder with correct wasSynchronouslyLoaded=false'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
int
?
lastFrame
;
late
bool
lastFrameWasSync
;
...
...
@@ -1038,8 +1038,8 @@ void main() {
});
testWidgets
(
'Image invokes frameBuilder with correct wasSynchronouslyLoaded=true'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
(
ImageInfo
(
image:
image10x10
.
clone
()));
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
(
ImageInfo
(
image:
image10x10
.
clone
()));
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
int
?
lastFrame
;
late
bool
lastFrameWasSync
;
...
...
@@ -1064,8 +1064,8 @@ void main() {
});
testWidgets
(
'Image state handles frameBuilder update'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Image
(
...
...
@@ -1105,8 +1105,8 @@ void main() {
return
frameInfo
.
image
;
}
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
int
?
lastFrame
;
int
buildCount
=
0
;
...
...
@@ -1169,8 +1169,8 @@ void main() {
});
testWidgets
(
'Image invokes loadingBuilder on chunk event notification'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
List
<
ImageChunkEvent
?>
chunkEvents
=
<
ImageChunkEvent
?>[];
await
tester
.
pumpWidget
(
...
...
@@ -1211,8 +1211,8 @@ void main() {
});
testWidgets
(
"Image doesn't rebuild on chunk events if loadingBuilder is null"
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Image
(
...
...
@@ -1233,8 +1233,8 @@ void main() {
});
testWidgets
(
'Image chains the results of frameBuilder and loadingBuilder'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Image
(
...
...
@@ -1263,8 +1263,8 @@ void main() {
});
testWidgets
(
'Image state handles loadingBuilder update from null to non-null'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Image
(
image:
imageProvider
),
...
...
@@ -1295,8 +1295,8 @@ void main() {
});
testWidgets
(
'Image state handles loadingBuilder update from non-null to null'
,
(
WidgetTester
tester
)
async
{
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Image
(
...
...
@@ -1329,8 +1329,8 @@ void main() {
testWidgets
(
'Verify Image resets its ImageListeners'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageStreamCompleter
imageStreamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
final
_TestImageStreamCompleter
imageStreamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -1343,7 +1343,7 @@ void main() {
expect
(
imageStreamCompleter
.
listeners
.
length
,
2
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -1362,8 +1362,8 @@ void main() {
testWidgets
(
'Verify Image resets its ErrorListeners'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
final
TestImageStreamCompleter
imageStreamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider1
=
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
final
_TestImageStreamCompleter
imageStreamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider1
=
_
TestImageProvider
(
streamCompleter:
imageStreamCompleter
);
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -1377,7 +1377,7 @@ void main() {
expect
(
imageStreamCompleter
.
listeners
.
length
,
2
);
final
TestImageProvider
imageProvider2
=
TestImageProvider
();
final
_TestImageProvider
imageProvider2
=
_
TestImageProvider
();
await
tester
.
pumpWidget
(
Container
(
key:
key
,
...
...
@@ -1396,7 +1396,7 @@ void main() {
testWidgets
(
'Image defers loading while fast scrolling'
,
(
WidgetTester
tester
)
async
{
const
int
gridCells
=
1000
;
final
List
<
TestImageProvider
>
imageProviders
=
<
TestImageProvider
>[];
final
List
<
_TestImageProvider
>
imageProviders
=
<
_
TestImageProvider
>[];
final
ScrollController
controller
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
...
...
@@ -1405,7 +1405,7 @@ void main() {
gridDelegate:
const
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
3
),
itemCount:
gridCells
,
itemBuilder:
(
_
,
int
index
)
{
final
TestImageProvider
provider
=
TestImageProvider
();
final
_TestImageProvider
provider
=
_
TestImageProvider
();
imageProviders
.
add
(
provider
);
return
SizedBox
(
height:
250
,
...
...
@@ -1419,8 +1419,8 @@ void main() {
),
));
final
bool
Function
(
TestImageProvider
)
loadCalled
=
(
TestImageProvider
provider
)
=>
provider
.
loadCalled
;
final
bool
Function
(
TestImageProvider
)
loadNotCalled
=
(
TestImageProvider
provider
)
=>
!
provider
.
loadCalled
;
final
bool
Function
(
_TestImageProvider
)
loadCalled
=
(
_
TestImageProvider
provider
)
=>
provider
.
loadCalled
;
final
bool
Function
(
_TestImageProvider
)
loadNotCalled
=
(
_
TestImageProvider
provider
)
=>
!
provider
.
loadCalled
;
expect
(
find
.
bySemanticsLabel
(
'5'
),
findsOneWidget
);
expect
(
imageProviders
.
length
,
12
);
...
...
@@ -1445,8 +1445,8 @@ void main() {
testWidgets
(
'Same image provider in multiple parts of the tree, no cache room left'
,
(
WidgetTester
tester
)
async
{
imageCache
!.
maximumSize
=
0
;
final
TestImageProvider
provider1
=
TestImageProvider
();
final
TestImageProvider
provider2
=
TestImageProvider
();
final
_TestImageProvider
provider1
=
_
TestImageProvider
();
final
_TestImageProvider
provider2
=
_
TestImageProvider
();
expect
(
provider1
.
loadCallCount
,
0
);
expect
(
provider2
.
loadCallCount
,
0
);
...
...
@@ -1499,7 +1499,7 @@ void main() {
testWidgets
(
'precacheImage does not hold weak ref for more than a frame'
,
(
WidgetTester
tester
)
async
{
imageCache
!.
maximumSize
=
0
;
final
TestImageProvider
provider
=
TestImageProvider
();
final
_TestImageProvider
provider
=
_
TestImageProvider
();
late
Future
<
void
>
precache
;
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -1549,7 +1549,7 @@ void main() {
});
testWidgets
(
'precacheImage allows time to take over weak reference'
,
(
WidgetTester
tester
)
async
{
final
TestImageProvider
provider
=
TestImageProvider
();
final
_TestImageProvider
provider
=
_
TestImageProvider
();
late
Future
<
void
>
precache
;
await
tester
.
pumpWidget
(
Builder
(
...
...
@@ -1637,7 +1637,7 @@ void main() {
late
Object
caughtException
;
await
tester
.
pumpWidget
(
Image
(
image:
FailingImageProvider
(
failOnObtainKey:
true
,
throws:
'threw'
,
image:
image10x10
),
image:
_
FailingImageProvider
(
failOnObtainKey:
true
,
throws:
'threw'
,
image:
image10x10
),
errorBuilder:
(
BuildContext
context
,
Object
error
,
StackTrace
?
stackTrace
)
{
caughtException
=
error
;
return
SizedBox
.
expand
(
key:
errorKey
);
...
...
@@ -1657,7 +1657,7 @@ void main() {
late
Object
caughtException
;
await
tester
.
pumpWidget
(
Image
(
image:
FailingImageProvider
(
failOnLoad:
true
,
throws:
'threw'
,
image:
image10x10
),
image:
_
FailingImageProvider
(
failOnLoad:
true
,
throws:
'threw'
,
image:
image10x10
),
errorBuilder:
(
BuildContext
context
,
Object
error
,
StackTrace
?
stackTrace
)
{
caughtException
=
error
;
return
SizedBox
.
expand
(
key:
errorKey
);
...
...
@@ -1675,7 +1675,7 @@ void main() {
testWidgets
(
'no errorBuilder - failure reported to FlutterError'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Image
(
image:
FailingImageProvider
(
failOnLoad:
true
,
throws:
'threw'
,
image:
image10x10
),
image:
_
FailingImageProvider
(
failOnLoad:
true
,
throws:
'threw'
,
image:
image10x10
),
),
);
...
...
@@ -1730,14 +1730,14 @@ void main() {
};
final
ui
.
Image
image
=
(
await
tester
.
runAsync
(()
=>
createTestImage
(
width:
100
,
height:
100
)))!;
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
(
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
(
ImageInfo
(
image:
image
,
scale:
1.0
,
debugLabel:
'test.png'
,
),
);
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Center
(
...
...
@@ -1767,13 +1767,13 @@ void main() {
expect
(
image
.
debugGetOpenHandleStackTraces
()!.
length
,
1
);
final
ImageProvider
provider
=
TestImageProvider
(
final
ImageProvider
provider
=
_
TestImageProvider
(
streamCompleter:
OneFrameImageStreamCompleter
(
Future
<
ImageInfo
>.
value
(
ImageInfo
(
image:
image
,
scale:
1.0
,
debugLabel:
'TestImage'
,
debugLabel:
'
_
TestImage'
,
),
),
),
...
...
@@ -1806,7 +1806,7 @@ void main() {
testWidgets
(
'Keeps stream alive when ticker mode is disabled'
,
(
WidgetTester
tester
)
async
{
imageCache
!.
maximumSize
=
0
;
final
ui
.
Image
image
=
(
await
tester
.
runAsync
(()
=>
createTestImage
(
width:
1
,
height:
1
,
cache:
false
)))!;
final
TestImageProvider
provider
=
TestImageProvider
();
final
_TestImageProvider
provider
=
_
TestImageProvider
();
provider
.
complete
(
image
);
await
tester
.
pumpWidget
(
...
...
@@ -1835,8 +1835,8 @@ void main() {
testWidgets
(
'Load a good image after a bad image was loaded should not call errorBuilder'
,
(
WidgetTester
tester
)
async
{
final
UniqueKey
errorKey
=
UniqueKey
();
final
ui
.
Image
image
=
(
await
tester
.
runAsync
(()
=>
createTestImage
()))!;
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
final
_TestImageStreamCompleter
streamCompleter
=
_
TestImageStreamCompleter
();
final
_TestImageProvider
imageProvider
=
_
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
Center
(
...
...
@@ -1878,81 +1878,40 @@ void main() {
expect
(
find
.
byKey
(
errorKey
),
findsNothing
);
});
testWidgets
(
'Image at default filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
null
);
});
testWidgets
(
'Image at high filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
ui
.
FilterQuality
.
high
);
});
testWidgets
(
'Image at none filterQuality'
,
(
WidgetTester
tester
)
async
{
await
testImageQuality
(
tester
,
ui
.
FilterQuality
.
none
);
});
}
Future
<
void
>
testImageQuality
(
WidgetTester
tester
,
ui
.
FilterQuality
?
quality
)
async
{
await
tester
.
binding
.
setSurfaceSize
(
const
ui
.
Size
(
3
,
3
));
// A 3x3 image encoded as PNG with white background and black pixels on the diagonal:
// ┌──────┐
// │▓▓ │
// │ ▓▓ │
// │ ▓▓│
// └──────┘
// At different levels of quality these pixels are blurred differently.
final
Uint8List
test3x3Image
=
Uint8List
.
fromList
(<
int
>[
0x89
,
0x50
,
0x4e
,
0x47
,
0x0d
,
0x0a
,
0x1a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x0d
,
0x49
,
0x48
,
0x44
,
0x52
,
0x00
,
0x00
,
0x00
,
0x03
,
0x00
,
0x00
,
0x00
,
0x03
,
0x08
,
0x02
,
0x00
,
0x00
,
0x00
,
0xd9
,
0x4a
,
0x22
,
0xe8
,
0x00
,
0x00
,
0x00
,
0x1b
,
0x49
,
0x44
,
0x41
,
0x54
,
0x08
,
0xd7
,
0x63
,
0x64
,
0x60
,
0x60
,
0xf8
,
0xff
,
0xff
,
0x3f
,
0x03
,
0x9c
,
0xfa
,
0xff
,
0xff
,
0x3f
,
0xc3
,
0xff
,
0xff
,
0xff
,
0x21
,
0x1c
,
0x00
,
0xcb
,
0x70
,
0x0e
,
0xf3
,
0x5d
,
0x11
,
0xc2
,
0xf8
,
0x00
,
0x00
,
0x00
,
0x00
,
0x49
,
0x45
,
0x4e
,
0x44
,
0xae
,
0x42
,
0x60
,
0x82
,
]);
final
ui
.
Image
image
=
(
await
tester
.
runAsync
(()
async
{
final
ui
.
Codec
codec
=
await
ui
.
instantiateImageCodec
(
test3x3Image
);
return
(
await
codec
.
getNextFrame
()).
image
;
}))!;
expect
(
image
.
width
,
3
);
expect
(
image
.
height
,
3
);
final
TestImageStreamCompleter
streamCompleter
=
TestImageStreamCompleter
();
streamCompleter
.
setData
(
imageInfo:
ImageInfo
(
image:
image
));
final
TestImageProvider
imageProvider
=
TestImageProvider
(
streamCompleter:
streamCompleter
);
await
tester
.
pumpWidget
(
quality
==
null
?
Image
(
image:
imageProvider
)
:
Image
(
image:
imageProvider
,
filterQuality:
quality
,
testWidgets
(
'Failed image loads in debug mode'
,
(
WidgetTester
tester
)
async
{
final
Key
key
=
UniqueKey
();
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
key:
key
,
child:
Container
(
width:
150.0
,
height:
50.0
,
decoration:
BoxDecoration
(
border:
Border
.
all
(
width:
2.0
,
color:
const
Color
(
0xFF00FF99
),
),
),
child:
Image
.
asset
(
'missing-asset'
),
),
);
await
expectLater
(
find
.
byType
(
Image
),
matchesGoldenFile
(
'image_quality_
${quality ?? 'default'}
.png'
),
);
}
class
ImagePainter
extends
CustomPainter
{
ImagePainter
(
this
.
image
);
@override
void
paint
(
ui
.
Canvas
canvas
,
ui
.
Size
size
)
{
canvas
.
drawImage
(
image
,
Offset
.
zero
,
Paint
());
}
@override
bool
shouldRepaint
(
CustomPainter
oldDelegate
)
{
return
false
;
}
final
ui
.
Image
image
;
),
));
await
expectLater
(
find
.
byKey
(
key
),
matchesGoldenFile
(
'image_test.missing.1.png'
),
);
expect
(
tester
.
takeException
().
toString
(),
startsWith
(
'Unable to load asset: '
));
await
tester
.
pump
();
await
expectLater
(
find
.
byKey
(
key
),
matchesGoldenFile
(
'image_test.missing.2.png'
),
);
},
skip:
kIsWeb
);
// https://github.com/flutter/flutter/issues/74935 (broken assets not being reported on web)
}
@immutable
class
ConfigurationAwareKey
{
const
ConfigurationAwareKey
(
this
.
provider
,
this
.
configuration
)
class
_
ConfigurationAwareKey
{
const
_
ConfigurationAwareKey
(
this
.
provider
,
this
.
configuration
)
:
assert
(
provider
!=
null
),
assert
(
configuration
!=
null
);
...
...
@@ -1964,7 +1923,7 @@ class ConfigurationAwareKey {
if
(
other
.
runtimeType
!=
runtimeType
)
{
return
false
;
}
return
other
is
ConfigurationAwareKey
return
other
is
_
ConfigurationAwareKey
&&
other
.
provider
==
provider
&&
other
.
configuration
==
configuration
;
}
...
...
@@ -1973,15 +1932,15 @@ class ConfigurationAwareKey {
int
get
hashCode
=>
hashValues
(
provider
,
configuration
);
}
class
ConfigurationKeyedTestImageProvider
extends
TestImageProvider
{
class
_ConfigurationKeyedTestImageProvider
extends
_
TestImageProvider
{
@override
Future
<
ConfigurationAwareKey
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
ConfigurationAwareKey
>(
ConfigurationAwareKey
(
this
,
configuration
));
Future
<
_
ConfigurationAwareKey
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
_ConfigurationAwareKey
>(
_
ConfigurationAwareKey
(
this
,
configuration
));
}
}
class
TestImageProvider
extends
ImageProvider
<
Object
>
{
TestImageProvider
({
ImageStreamCompleter
?
streamCompleter
})
{
class
_
TestImageProvider
extends
ImageProvider
<
Object
>
{
_
TestImageProvider
({
ImageStreamCompleter
?
streamCompleter
})
{
_streamCompleter
=
streamCompleter
??
OneFrameImageStreamCompleter
(
_completer
.
future
);
}
...
...
@@ -1996,7 +1955,7 @@ class TestImageProvider extends ImageProvider<Object> {
@override
Future
<
Object
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
SynchronousFuture
<
TestImageProvider
>(
this
);
return
SynchronousFuture
<
_
TestImageProvider
>(
this
);
}
@override
...
...
@@ -2023,14 +1982,8 @@ class TestImageProvider extends ImageProvider<Object> {
String
toString
()
=>
'
${describeIdentity(this)}
()'
;
}
class
SimpleTestImageStreamCompleter
extends
ImageStreamCompleter
{
void
testSetImage
(
ui
.
Image
image
)
{
setImage
(
ImageInfo
(
image:
image
,
scale:
1.0
));
}
}
class
TestImageStreamCompleter
extends
ImageStreamCompleter
{
TestImageStreamCompleter
([
this
.
_currentImage
]);
class
_TestImageStreamCompleter
extends
ImageStreamCompleter
{
_TestImageStreamCompleter
([
this
.
_currentImage
]);
ImageInfo
?
_currentImage
;
final
Set
<
ImageStreamListener
>
listeners
=
<
ImageStreamListener
>{};
...
...
@@ -2080,8 +2033,8 @@ class TestImageStreamCompleter extends ImageStreamCompleter {
}
}
class
DebouncingImageProvider
extends
ImageProvider
<
Object
>
{
DebouncingImageProvider
(
this
.
imageProvider
,
this
.
seenKeys
);
class
_
DebouncingImageProvider
extends
ImageProvider
<
Object
>
{
_
DebouncingImageProvider
(
this
.
imageProvider
,
this
.
seenKeys
);
/// A set of keys that will only get resolved the _first_ time they are seen.
///
...
...
@@ -2107,8 +2060,8 @@ class DebouncingImageProvider extends ImageProvider<Object> {
ImageStreamCompleter
load
(
Object
key
,
DecoderCallback
decode
)
=>
imageProvider
.
load
(
key
,
decode
);
}
class
FailingImageProvider
extends
ImageProvider
<
int
>
{
const
FailingImageProvider
({
class
_
FailingImageProvider
extends
ImageProvider
<
int
>
{
const
_
FailingImageProvider
({
this
.
failOnObtainKey
=
false
,
this
.
failOnLoad
=
false
,
required
this
.
throws
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment