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