Unverified Commit 2f77111c authored by Mateus Felipe C. C. Pinto's avatar Mateus Felipe C. C. Pinto Committed by GitHub

Export shadows to `Icon` API (#83638)

parent 22c63a11
......@@ -17,7 +17,8 @@ class CupertinoIconThemeData extends IconThemeData with Diagnosticable {
Color? color,
double? opacity,
double? size,
}) : super(color: color, opacity: opacity, size: size);
List<Shadow>? shadows,
}) : super(color: color, opacity: opacity, size: size, shadows: shadows);
/// Called by [IconTheme.of] to resolve [color] against the given [BuildContext].
@override
......@@ -29,11 +30,12 @@ class CupertinoIconThemeData extends IconThemeData with Diagnosticable {
/// Creates a copy of this icon theme but with the given fields replaced with
/// the new values.
@override
CupertinoIconThemeData copyWith({ Color? color, double? opacity, double? size }) {
CupertinoIconThemeData copyWith({ Color? color, double? opacity, double? size, List<Shadow>? shadows }) {
return CupertinoIconThemeData(
color: color ?? this.color,
opacity: opacity ?? this.opacity,
size: size ?? this.size,
shadows: shadows ?? this.shadows,
);
}
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'basic.dart';
......@@ -74,6 +75,7 @@ class Icon extends StatelessWidget {
this.color,
this.semanticLabel,
this.textDirection,
this.shadows,
}) : super(key: key);
/// The icon to display. The available icons are described in [Icons].
......@@ -150,6 +152,15 @@ class Icon extends StatelessWidget {
/// specified, either directly using this property or using [Directionality].
final TextDirection? textDirection;
/// A list of [Shadow]s that will be painted underneath the icon.
///
/// Multiple shadows are supported to replicate lighting from multiple light
/// sources.
///
/// Shadows must be in the same order for [Icon] to be considered as
/// equivalent as order produces differing transparency.
final List<Shadow>? shadows;
@override
Widget build(BuildContext context) {
assert(this.textDirection != null || debugCheckHasDirectionality(context));
......@@ -159,6 +170,8 @@ class Icon extends StatelessWidget {
final double? iconSize = size ?? iconTheme.size;
final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows;
if (icon == null) {
return Semantics(
label: semanticLabel,
......@@ -182,6 +195,7 @@ class Icon extends StatelessWidget {
fontSize: iconSize,
fontFamily: icon!.fontFamily,
package: icon!.fontPackage,
shadows: iconShadows,
),
),
);
......@@ -221,5 +235,6 @@ class Icon extends StatelessWidget {
properties.add(IconDataProperty('icon', icon, ifNull: '<empty>', showName: false));
properties.add(DoubleProperty('size', size, defaultValue: null));
properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(IterableProperty<Shadow>('shadows', shadows, defaultValue: null));
}
}
......@@ -75,6 +75,7 @@ class IconTheme extends InheritedTheme {
size: iconThemeData.size ?? const IconThemeData.fallback().size,
color: iconThemeData.color ?? const IconThemeData.fallback().color,
opacity: iconThemeData.opacity ?? const IconThemeData.fallback().opacity,
shadows: iconThemeData.shadows ?? const IconThemeData.fallback().shadows,
);
}
......
......@@ -23,23 +23,25 @@ class IconThemeData with Diagnosticable {
///
/// The opacity applies to both explicit and default icon colors. The value
/// is clamped between 0.0 and 1.0.
const IconThemeData({this.color, double? opacity, this.size}) : _opacity = opacity;
const IconThemeData({this.color, double? opacity, this.size, this.shadows}) : _opacity = opacity;
/// Creates an icon theme with some reasonable default values.
///
/// The [color] is black, the [opacity] is 1.0, and the [size] is 24.0.
const IconThemeData.fallback()
: color = const Color(0xFF000000),
_opacity = 1.0,
size = 24.0;
: color = const Color(0xFF000000),
_opacity = 1.0,
size = 24.0,
shadows = null;
/// Creates a copy of this icon theme but with the given fields replaced with
/// the new values.
IconThemeData copyWith({ Color? color, double? opacity, double? size }) {
IconThemeData copyWith({Color? color, double? opacity, double? size, List<Shadow>? shadows}) {
return IconThemeData(
color: color ?? this.color,
opacity: opacity ?? this.opacity,
size: size ?? this.size,
shadows: shadows ?? this.shadows,
);
}
......@@ -53,6 +55,7 @@ class IconThemeData with Diagnosticable {
color: other.color,
opacity: other.opacity,
size: other.size,
shadows: other.shadows,
);
}
......@@ -87,6 +90,9 @@ class IconThemeData with Diagnosticable {
/// The default size for icons.
final double? size;
/// The default shadow for icons.
final List<Shadow>? shadows;
/// Linearly interpolate between two icon theme data objects.
///
/// {@macro dart.ui.shadow.lerp}
......@@ -96,6 +102,7 @@ class IconThemeData with Diagnosticable {
color: Color.lerp(a?.color, b?.color, t),
opacity: ui.lerpDouble(a?.opacity, b?.opacity, t),
size: ui.lerpDouble(a?.size, b?.size, t),
shadows: Shadow.lerpList(a?.shadows, b?.shadows, t),
);
}
......@@ -106,11 +113,12 @@ class IconThemeData with Diagnosticable {
return other is IconThemeData
&& other.color == color
&& other.opacity == opacity
&& other.size == size;
&& other.size == size
&& listEquals(other.shadows, shadows);
}
@override
int get hashCode => hashValues(color, opacity, size);
int get hashCode => hashValues(color, opacity, size, hashList(shadows));
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
......@@ -118,5 +126,6 @@ class IconThemeData with Diagnosticable {
properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(DoubleProperty('opacity', opacity, defaultValue: null));
properties.add(DoubleProperty('size', size, defaultValue: null));
properties.add(IterableProperty<Shadow>('shadows', shadows, defaultValue: null));
}
}
......@@ -7,7 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
test('IconThemeData control test', () {
const IconThemeData data = IconThemeData(color: Color(0xAAAAAAAA), opacity: 0.5, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xAAAAAAAA), opacity: 0.5, size: 16.0, shadows: <Shadow>[Shadow(color: Color(0xAAAAAAAA), blurRadius: 1.0, offset: Offset(1.0, 1.0))]);
expect(data, hasOneLineDescription);
expect(data, equals(data.copyWith()));
......@@ -17,24 +17,27 @@ void main() {
expect(lerped.color, const Color(0xBF7F7F7F));
expect(lerped.opacity, 0.625);
expect(lerped.size, 18.0);
expect(lerped.shadows, const <Shadow>[Shadow(color: Color(0xAAAAAAAA), blurRadius: 0.75, offset: Offset(0.75, 0.75))]);
});
test('IconThemeData lerp with first null', () {
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0, shadows: <Shadow>[Shadow(color: Color(0xFFFFFFFF), blurRadius: 1.0, offset: Offset(1.0, 1.0))]);
final IconThemeData lerped = IconThemeData.lerp(null, data, 0.25);
expect(lerped.color, const Color(0x40FFFFFF));
expect(lerped.opacity, 0.25);
expect(lerped.size, 4.0);
expect(lerped.shadows, const <Shadow>[Shadow(color: Color(0xFFFFFFFF), blurRadius: 0.25, offset: Offset(0.25, 0.25))]);
});
test('IconThemeData lerp with second null', () {
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0, shadows: <Shadow>[Shadow(color: Color(0xFFFFFFFF), blurRadius: 1.0, offset: Offset(1.0, 1.0))]);
final IconThemeData lerped = IconThemeData.lerp(data, null, 0.25);
expect(lerped.color, const Color(0xBFFFFFFF));
expect(lerped.opacity, 0.75);
expect(lerped.size, 12.0);
expect(lerped.shadows, const <Shadow>[Shadow(color: Color(0xFFFFFFFF), blurRadius: 0.75, offset: Offset(0.75, 0.75))]);
});
test('IconThemeData lerp with both null', () {
......@@ -42,5 +45,6 @@ void main() {
expect(lerped.color, null);
expect(lerped.opacity, null);
expect(lerped.size, null);
expect(lerped.shadows, null);
});
}
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