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
ed67c479
Unverified
Commit
ed67c479
authored
Mar 26, 2020
by
Dan Field
Committed by
GitHub
Mar 26, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add error callbacks to other image resolving code (#53329)
parent
0d111bc9
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
153 additions
and
10 deletions
+153
-10
circle_avatar.dart
packages/flutter/lib/src/material/circle_avatar.dart
+14
-1
ink_decoration.dart
packages/flutter/lib/src/material/ink_decoration.dart
+4
-1
switch.dart
packages/flutter/lib/src/material/switch.dart
+62
-5
decoration_image.dart
packages/flutter/lib/src/painting/decoration_image.dart
+12
-2
fade_in_image.dart
packages/flutter/lib/src/widgets/fade_in_image.dart
+25
-1
decoration_test.dart
packages/flutter/test/painting/decoration_test.dart
+36
-0
No files found.
packages/flutter/lib/src/material/circle_avatar.dart
View file @
ed67c479
...
...
@@ -17,6 +17,9 @@ import 'theme_data.dart';
/// such an image, the user's initials. A given user's initials should
/// always be paired with the same background color, for consistency.
///
/// The [onBackgroundImageError] parameter must be null if the [backgroundImage]
/// is null.
///
/// {@tool snippet}
///
/// If the avatar is to have an image, the image should be specified in the
...
...
@@ -57,11 +60,13 @@ class CircleAvatar extends StatelessWidget {
this
.
child
,
this
.
backgroundColor
,
this
.
backgroundImage
,
this
.
onBackgroundImageError
,
this
.
foregroundColor
,
this
.
radius
,
this
.
minRadius
,
this
.
maxRadius
,
})
:
assert
(
radius
==
null
||
(
minRadius
==
null
&&
maxRadius
==
null
)),
assert
(
backgroundImage
!=
null
||
onBackgroundImageError
==
null
),
super
(
key:
key
);
/// The widget below this widget in the tree.
...
...
@@ -93,6 +98,10 @@ class CircleAvatar extends StatelessWidget {
/// If the [CircleAvatar] is to have the user's initials, use [child] instead.
final
ImageProvider
backgroundImage
;
/// An optional error callback for errors emitted when loading
/// [backgroundImage].
final
ImageErrorListener
onBackgroundImageError
;
/// The size of the avatar, expressed as the radius (half the diameter).
///
/// If [radius] is specified, then neither [minRadius] nor [maxRadius] may be
...
...
@@ -200,7 +209,11 @@ class CircleAvatar extends StatelessWidget {
decoration:
BoxDecoration
(
color:
effectiveBackgroundColor
,
image:
backgroundImage
!=
null
?
DecorationImage
(
image:
backgroundImage
,
fit:
BoxFit
.
cover
)
?
DecorationImage
(
image:
backgroundImage
,
onError:
onBackgroundImageError
,
fit:
BoxFit
.
cover
,
)
:
null
,
shape:
BoxShape
.
circle
,
),
...
...
packages/flutter/lib/src/material/ink_decoration.dart
View file @
ed67c479
...
...
@@ -145,7 +145,8 @@ class Ink extends StatefulWidget {
///
/// The `image` argument must not be null. If there is no
/// intention to render anything on this image, consider using a
/// [Container] with a [BoxDecoration.image] instead.
/// [Container] with a [BoxDecoration.image] instead. The `onImageError`
/// argument may be provided to listen for errors when resolving the image.
///
/// The `alignment`, `repeat`, and `matchTextDirection` arguments must not
/// be null either, but they have default values.
...
...
@@ -155,6 +156,7 @@ class Ink extends StatefulWidget {
Key
key
,
this
.
padding
,
@required
ImageProvider
image
,
ImageErrorListener
onImageError
,
ColorFilter
colorFilter
,
BoxFit
fit
,
AlignmentGeometry
alignment
=
Alignment
.
center
,
...
...
@@ -172,6 +174,7 @@ class Ink extends StatefulWidget {
decoration
=
BoxDecoration
(
image:
DecorationImage
(
image:
image
,
onError:
onImageError
,
colorFilter:
colorFilter
,
fit:
fit
,
alignment:
alignment
,
...
...
packages/flutter/lib/src/material/switch.dart
View file @
ed67c479
...
...
@@ -71,7 +71,9 @@ class Switch extends StatefulWidget {
this
.
inactiveThumbColor
,
this
.
inactiveTrackColor
,
this
.
activeThumbImage
,
this
.
onActiveThumbImageError
,
this
.
inactiveThumbImage
,
this
.
onInactiveThumbImageError
,
this
.
materialTapTargetSize
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
focusColor
,
...
...
@@ -80,6 +82,8 @@ class Switch extends StatefulWidget {
this
.
autofocus
=
false
,
})
:
_switchType
=
_SwitchType
.
material
,
assert
(
dragStartBehavior
!=
null
),
assert
(
activeThumbImage
!=
null
||
onActiveThumbImageError
==
null
),
assert
(
inactiveThumbImage
!=
null
||
onInactiveThumbImageError
==
null
),
super
(
key:
key
);
/// Creates a [CupertinoSwitch] if the target platform is iOS, creates a
...
...
@@ -87,7 +91,8 @@ class Switch extends StatefulWidget {
///
/// If a [CupertinoSwitch] is created, the following parameters are
/// ignored: [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor],
/// [activeThumbImage], [inactiveThumbImage], [materialTapTargetSize].
/// [activeThumbImage], [onActiveThumbImageError], [inactiveThumbImage],
/// [onInactiveImageThumbError], [materialTapTargetSize].
///
/// The target platform is based on the current [Theme]: [ThemeData.platform].
const
Switch
.
adaptive
({
...
...
@@ -99,7 +104,9 @@ class Switch extends StatefulWidget {
this
.
inactiveThumbColor
,
this
.
inactiveTrackColor
,
this
.
activeThumbImage
,
this
.
onActiveThumbImageError
,
this
.
inactiveThumbImage
,
this
.
onInactiveThumbImageError
,
this
.
materialTapTargetSize
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
focusColor
,
...
...
@@ -107,6 +114,8 @@ class Switch extends StatefulWidget {
this
.
focusNode
,
this
.
autofocus
=
false
,
})
:
assert
(
autofocus
!=
null
),
assert
(
activeThumbImage
!=
null
||
onActiveThumbImageError
==
null
),
assert
(
inactiveThumbImage
!=
null
||
onInactiveThumbImageError
==
null
),
_switchType
=
_SwitchType
.
adaptive
,
super
(
key:
key
);
...
...
@@ -170,11 +179,19 @@ class Switch extends StatefulWidget {
/// Ignored if this switch is created with [Switch.adaptive].
final
ImageProvider
activeThumbImage
;
/// An optional error callback for errors emitted when loading
/// [activeThumbImage].
final
ImageErrorListener
onActiveThumbImageError
;
/// An image to use on the thumb of this switch when the switch is off.
///
/// Ignored if this switch is created with [Switch.adaptive].
final
ImageProvider
inactiveThumbImage
;
/// An optional error callback for errors emitted when loading
/// [inactiveThumbImage].
final
ImageErrorListener
onInactiveThumbImageError
;
/// Configures the minimum size of the tap target.
///
/// Defaults to [ThemeData.materialTapTargetSize].
...
...
@@ -311,7 +328,9 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
hoverColor:
hoverColor
,
focusColor:
focusColor
,
activeThumbImage:
widget
.
activeThumbImage
,
onActiveThumbImageError:
widget
.
onActiveThumbImageError
,
inactiveThumbImage:
widget
.
inactiveThumbImage
,
onInactiveThumbImageError:
widget
.
onInactiveThumbImageError
,
activeTrackColor:
activeTrackColor
,
inactiveTrackColor:
inactiveTrackColor
,
configuration:
createLocalImageConfiguration
(
context
),
...
...
@@ -381,7 +400,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
this
.
hoverColor
,
this
.
focusColor
,
this
.
activeThumbImage
,
this
.
onActiveThumbImageError
,
this
.
inactiveThumbImage
,
this
.
onInactiveThumbImageError
,
this
.
activeTrackColor
,
this
.
inactiveTrackColor
,
this
.
configuration
,
...
...
@@ -399,7 +420,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
final
Color
hoverColor
;
final
Color
focusColor
;
final
ImageProvider
activeThumbImage
;
final
ImageErrorListener
onActiveThumbImageError
;
final
ImageProvider
inactiveThumbImage
;
final
ImageErrorListener
onInactiveThumbImageError
;
final
Color
activeTrackColor
;
final
Color
inactiveTrackColor
;
final
ImageConfiguration
configuration
;
...
...
@@ -420,7 +443,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
hoverColor:
hoverColor
,
focusColor:
focusColor
,
activeThumbImage:
activeThumbImage
,
onActiveThumbImageError:
onActiveThumbImageError
,
inactiveThumbImage:
inactiveThumbImage
,
onInactiveThumbImageError:
onInactiveThumbImageError
,
activeTrackColor:
activeTrackColor
,
inactiveTrackColor:
inactiveTrackColor
,
configuration:
configuration
,
...
...
@@ -442,7 +467,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
..
hoverColor
=
hoverColor
..
focusColor
=
focusColor
..
activeThumbImage
=
activeThumbImage
..
onActiveThumbImageError
=
onActiveThumbImageError
..
inactiveThumbImage
=
inactiveThumbImage
..
onInactiveThumbImageError
=
onInactiveThumbImageError
..
activeTrackColor
=
activeTrackColor
..
inactiveTrackColor
=
inactiveTrackColor
..
configuration
=
configuration
...
...
@@ -464,7 +491,9 @@ class _RenderSwitch extends RenderToggleable {
Color
hoverColor
,
Color
focusColor
,
ImageProvider
activeThumbImage
,
ImageErrorListener
onActiveThumbImageError
,
ImageProvider
inactiveThumbImage
,
ImageErrorListener
onInactiveThumbImageError
,
Color
activeTrackColor
,
Color
inactiveTrackColor
,
ImageConfiguration
configuration
,
...
...
@@ -477,7 +506,9 @@ class _RenderSwitch extends RenderToggleable {
@required
this
.
state
,
})
:
assert
(
textDirection
!=
null
),
_activeThumbImage
=
activeThumbImage
,
_onActiveThumbImageError
=
onActiveThumbImageError
,
_inactiveThumbImage
=
inactiveThumbImage
,
_onInactiveThumbImageError
=
onInactiveThumbImageError
,
_activeTrackColor
=
activeTrackColor
,
_inactiveTrackColor
=
inactiveTrackColor
,
_configuration
=
configuration
,
...
...
@@ -511,6 +542,16 @@ class _RenderSwitch extends RenderToggleable {
markNeedsPaint
();
}
ImageErrorListener
get
onActiveThumbImageError
=>
_onActiveThumbImageError
;
ImageErrorListener
_onActiveThumbImageError
;
set
onActiveThumbImageError
(
ImageErrorListener
value
)
{
if
(
value
==
_onActiveThumbImageError
)
{
return
;
}
_onActiveThumbImageError
=
value
;
markNeedsPaint
();
}
ImageProvider
get
inactiveThumbImage
=>
_inactiveThumbImage
;
ImageProvider
_inactiveThumbImage
;
set
inactiveThumbImage
(
ImageProvider
value
)
{
...
...
@@ -520,6 +561,16 @@ class _RenderSwitch extends RenderToggleable {
markNeedsPaint
();
}
ImageErrorListener
get
onInactiveThumbImageError
=>
_onInactiveThumbImageError
;
ImageErrorListener
_onInactiveThumbImageError
;
set
onInactiveThumbImageError
(
ImageErrorListener
value
)
{
if
(
value
==
_onInactiveThumbImageError
)
{
return
;
}
_onInactiveThumbImageError
=
value
;
markNeedsPaint
();
}
Color
get
activeTrackColor
=>
_activeTrackColor
;
Color
_activeTrackColor
;
set
activeTrackColor
(
Color
value
)
{
...
...
@@ -642,12 +693,13 @@ class _RenderSwitch extends RenderToggleable {
Color
_cachedThumbColor
;
ImageProvider
_cachedThumbImage
;
ImageErrorListener
_cachedThumbErrorListener
;
BoxPainter
_cachedThumbPainter
;
BoxDecoration
_createDefaultThumbDecoration
(
Color
color
,
ImageProvider
image
)
{
BoxDecoration
_createDefaultThumbDecoration
(
Color
color
,
ImageProvider
image
,
ImageErrorListener
errorListener
)
{
return
BoxDecoration
(
color:
color
,
image:
image
==
null
?
null
:
DecorationImage
(
image:
image
),
image:
image
==
null
?
null
:
DecorationImage
(
image:
image
,
onError:
errorListener
),
shape:
BoxShape
.
circle
,
boxShadow:
kElevationToShadow
[
1
],
);
...
...
@@ -698,6 +750,10 @@ class _RenderSwitch extends RenderToggleable {
?
(
currentValue
<
0.5
?
inactiveThumbImage
:
activeThumbImage
)
:
inactiveThumbImage
;
final
ImageErrorListener
thumbErrorListener
=
isEnabled
?
(
currentValue
<
0.5
?
onInactiveThumbImageError
:
onActiveThumbImageError
)
:
onInactiveThumbImageError
;
// Paint the track
final
Paint
paint
=
Paint
()
..
color
=
trackColor
;
...
...
@@ -721,10 +777,11 @@ class _RenderSwitch extends RenderToggleable {
try
{
_isPainting
=
true
;
BoxPainter
thumbPainter
;
if
(
_cachedThumbPainter
==
null
||
thumbColor
!=
_cachedThumbColor
||
thumbImage
!=
_cachedThumbImage
)
{
if
(
_cachedThumbPainter
==
null
||
thumbColor
!=
_cachedThumbColor
||
thumbImage
!=
_cachedThumbImage
||
thumbErrorListener
!=
_cachedThumbErrorListener
)
{
_cachedThumbColor
=
thumbColor
;
_cachedThumbImage
=
thumbImage
;
_cachedThumbPainter
=
_createDefaultThumbDecoration
(
thumbColor
,
thumbImage
).
createBoxPainter
(
_handleDecorationChanged
);
_cachedThumbErrorListener
=
thumbErrorListener
;
_cachedThumbPainter
=
_createDefaultThumbDecoration
(
thumbColor
,
thumbImage
,
thumbErrorListener
).
createBoxPainter
(
_handleDecorationChanged
);
}
thumbPainter
=
_cachedThumbPainter
;
...
...
packages/flutter/lib/src/painting/decoration_image.dart
View file @
ed67c479
...
...
@@ -40,6 +40,7 @@ class DecorationImage {
/// must not be null.
const
DecorationImage
({
@required
this
.
image
,
this
.
onError
,
this
.
colorFilter
,
this
.
fit
,
this
.
alignment
=
Alignment
.
center
,
...
...
@@ -57,6 +58,9 @@ class DecorationImage {
/// application) or a [NetworkImage] (for an image obtained from the network).
final
ImageProvider
image
;
/// An optional error callback for errors emitted when loading [image].
final
ImageErrorListener
onError
;
/// A color filter to apply to the image before painting it.
final
ColorFilter
colorFilter
;
...
...
@@ -239,7 +243,10 @@ class DecorationImagePainter {
final
ImageStream
newImageStream
=
_details
.
image
.
resolve
(
configuration
);
if
(
newImageStream
.
key
!=
_imageStream
?.
key
)
{
final
ImageStreamListener
listener
=
ImageStreamListener
(
_handleImage
);
final
ImageStreamListener
listener
=
ImageStreamListener
(
_handleImage
,
onError:
_details
.
onError
,
);
_imageStream
?.
removeListener
(
listener
);
_imageStream
=
newImageStream
;
_imageStream
.
addListener
(
listener
);
...
...
@@ -286,7 +293,10 @@ class DecorationImagePainter {
/// After this method has been called, the object is no longer usable.
@mustCallSuper
void
dispose
()
{
_imageStream
?.
removeListener
(
ImageStreamListener
(
_handleImage
));
_imageStream
?.
removeListener
(
ImageStreamListener
(
_handleImage
,
onError:
_details
.
onError
,
));
}
@override
...
...
packages/flutter/lib/src/widgets/fade_in_image.dart
View file @
ed67c479
...
...
@@ -77,7 +77,9 @@ class FadeInImage extends StatelessWidget {
const
FadeInImage
({
Key
key
,
@required
this
.
placeholder
,
this
.
placeholderErrorBuilder
,
@required
this
.
image
,
this
.
imageErrorBuilder
,
this
.
excludeFromSemantics
=
false
,
this
.
imageSemanticLabel
,
this
.
fadeOutDuration
=
const
Duration
(
milliseconds:
300
),
...
...
@@ -132,7 +134,9 @@ class FadeInImage extends StatelessWidget {
FadeInImage
.
memoryNetwork
({
Key
key
,
@required
Uint8List
placeholder
,
this
.
placeholderErrorBuilder
,
@required
String
image
,
this
.
imageErrorBuilder
,
double
placeholderScale
=
1.0
,
double
imageScale
=
1.0
,
this
.
excludeFromSemantics
=
false
,
...
...
@@ -200,7 +204,9 @@ class FadeInImage extends StatelessWidget {
FadeInImage
.
assetNetwork
({
Key
key
,
@required
String
placeholder
,
this
.
placeholderErrorBuilder
,
@required
String
image
,
this
.
imageErrorBuilder
,
AssetBundle
bundle
,
double
placeholderScale
,
double
imageScale
=
1.0
,
...
...
@@ -239,9 +245,24 @@ class FadeInImage extends StatelessWidget {
/// Image displayed while the target [image] is loading.
final
ImageProvider
placeholder
;
/// A builder function that is called if an error occurs during placeholder
/// image loading.
///
/// If this builder is not provided, any exceptions will be reported to
/// [FlutterError.onError]. If it is provided, the caller should either handle
/// the exception by providing a replacement widget, or rethrow the exception.
final
ImageErrorWidgetBuilder
placeholderErrorBuilder
;
/// The target image that is displayed once it has loaded.
final
ImageProvider
image
;
/// A builder function that is called if an error occurs during image loading.
///
/// If this builder is not provided, any exceptions will be reported to
/// [FlutterError.onError]. If it is provided, the caller should either handle
/// the exception by providing a replacement widget, or rethrow the exception.
final
ImageErrorWidgetBuilder
imageErrorBuilder
;
/// The duration of the fade-out animation for the [placeholder].
final
Duration
fadeOutDuration
;
...
...
@@ -337,11 +358,13 @@ class FadeInImage extends StatelessWidget {
Image
_image
({
@required
ImageProvider
image
,
ImageErrorWidgetBuilder
errorBuilder
,
ImageFrameBuilder
frameBuilder
,
})
{
assert
(
image
!=
null
);
return
Image
(
image:
image
,
errorBuilder:
errorBuilder
,
frameBuilder:
frameBuilder
,
width:
width
,
height:
height
,
...
...
@@ -358,12 +381,13 @@ class FadeInImage extends StatelessWidget {
Widget
build
(
BuildContext
context
)
{
Widget
result
=
_image
(
image:
image
,
errorBuilder:
imageErrorBuilder
,
frameBuilder:
(
BuildContext
context
,
Widget
child
,
int
frame
,
bool
wasSynchronouslyLoaded
)
{
if
(
wasSynchronouslyLoaded
)
return
child
;
return
_AnimatedFadeOutFadeIn
(
target:
child
,
placeholder:
_image
(
image:
placeholder
),
placeholder:
_image
(
image:
placeholder
,
errorBuilder:
placeholderErrorBuilder
),
isTargetLoaded:
frame
!=
null
,
fadeInDuration:
fadeInDuration
,
fadeOutDuration:
fadeOutDuration
,
...
...
packages/flutter/test/painting/decoration_test.dart
View file @
ed67c479
...
...
@@ -40,6 +40,22 @@ class SynchronousTestImageProvider extends ImageProvider<int> {
}
}
class
SynchronousErrorTestImageProvider
extends
ImageProvider
<
int
>
{
const
SynchronousErrorTestImageProvider
(
this
.
throwable
);
final
Object
throwable
;
@override
Future
<
int
>
obtainKey
(
ImageConfiguration
configuration
)
{
throw
throwable
;
}
@override
ImageStreamCompleter
load
(
int
key
,
DecoderCallback
decode
)
{
throw
throwable
;
}
}
class
AsyncTestImageProvider
extends
ImageProvider
<
int
>
{
@override
Future
<
int
>
obtainKey
(
ImageConfiguration
configuration
)
{
...
...
@@ -269,6 +285,26 @@ void main() {
);
});
test
(
'DecorationImage - error listener'
,
()
async
{
String
exception
;
final
DecorationImage
backgroundImage
=
DecorationImage
(
image:
const
SynchronousErrorTestImageProvider
(
'threw'
),
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
exception
=
error
as
String
;
}
);
backgroundImage
.
createPainter
(()
{
}).
paint
(
TestCanvas
(),
Rect
.
largest
,
Path
(),
ImageConfiguration
.
empty
,
);
// Yield so that the exception callback gets called before we check it.
await
null
;
expect
(
exception
,
'threw'
);
});
test
(
'BoxDecoration.lerp - shapes'
,
()
{
// We don't lerp the shape, we just switch from one to the other at t=0.5.
// (Use a ShapeDecoration and ShapeBorder if you want to lerp the shapes...)
...
...
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