Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 19 additions & 208 deletions lib/src/fa_icon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
// 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 'package:flutter/widgets.dart';

/// Creates an Icon Widget that works for non-material Icons, such as the
/// Font Awesome Icons.
///
/// The default `Icon` Widget from the Material package assumes all Icons are
/// The default [Icon] Widget from the Material package assumes all Icons are
/// square in size and wraps all Icons in a square SizedBox Widget. Icons from
/// the FontAwesome package are often wider than they are tall, which causes
/// alignment and cutoff issues.
Expand All @@ -22,191 +20,24 @@ import 'package:flutter/widgets.dart';
///
/// Original source code:
/// https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/icon.dart
class FaIcon extends StatelessWidget {
class FaIcon extends Icon {
/// Creates an icon.
const FaIcon(
this.icon, {
super.key,
this.size,
this.fill,
this.weight,
this.grade,
this.opticalSize,
this.color,
this.shadows,
this.semanticLabel,
this.textDirection,
this.applyTextScaling,
this.blendMode,
this.fontWeight,
}) : assert(fill == null || (0.0 <= fill && fill <= 1.0)),
assert(weight == null || (0.0 < weight)),
assert(opticalSize == null || (0.0 < opticalSize));

/// The icon to display. The available icons are described in [Icons].
///
/// The icon can be null, in which case the widget will render as an empty
/// space of the specified [size].
final IconData? icon;

/// The size of the icon in logical pixels.
///
/// Icons occupy a square with width and height equal to size.
///
/// Defaults to the nearest [IconTheme]'s [IconThemeData.size].
///
/// If this [Icon] is being placed inside an [IconButton], then use
/// [IconButton.iconSize] instead, so that the [IconButton] can make the splash
/// area the appropriate size as well. The [IconButton] uses an [IconTheme] to
/// pass down the size to the [Icon].
final double? size;

/// The fill for drawing the icon.
///
/// Requires the underlying icon font to support the `FILL` [FontVariation]
/// axis, otherwise has no effect. Variable font filenames often indicate
/// the supported axes. Must be between 0.0 (unfilled) and 1.0 (filled),
/// inclusive.
///
/// Can be used to convey a state transition for animation or interaction.
///
/// Defaults to nearest [IconTheme]'s [IconThemeData.fill].
///
/// See also:
/// * [weight], for controlling stroke weight.
/// * [grade], for controlling stroke weight in a more granular way.
/// * [opticalSize], for controlling optical size.
final double? fill;

/// The stroke weight for drawing the icon.
///
/// Requires the underlying icon font to support the `wght` [FontVariation]
/// axis, otherwise has no effect. Variable font filenames often indicate
/// the supported axes. Must be greater than 0.
///
/// Defaults to nearest [IconTheme]'s [IconThemeData.weight].
///
/// See also:
/// * [fill], for controlling fill.
/// * [grade], for controlling stroke weight in a more granular way.
/// * [opticalSize], for controlling optical size.
/// * https://fonts.google.com/knowledge/glossary/weight_axis
final double? weight;

/// The grade (granular stroke weight) for drawing the icon.
///
/// Requires the underlying icon font to support the `GRAD` [FontVariation]
/// axis, otherwise has no effect. Variable font filenames often indicate
/// the supported axes. Can be negative.
///
/// Grade and [weight] both affect a symbol's stroke weight (thickness), but
/// grade has a smaller impact on the size of the symbol.
///
/// Grade is also available in some text fonts. One can match grade levels
/// between text and symbols for a harmonious visual effect. For example, if
/// the text font has a -25 grade value, the symbols can match it with a
/// suitable value, say -25.
///
/// Defaults to nearest [IconTheme]'s [IconThemeData.grade].
///
/// See also:
/// * [fill], for controlling fill.
/// * [weight], for controlling stroke weight in a less granular way.
/// * [opticalSize], for controlling optical size.
/// * https://fonts.google.com/knowledge/glossary/grade_axis
final double? grade;

/// The optical size for drawing the icon.
///
/// Requires the underlying icon font to support the `opsz` [FontVariation]
/// axis, otherwise has no effect. Variable font filenames often indicate
/// the supported axes. Must be greater than 0.
///
/// For an icon to look the same at different sizes, the stroke weight
/// (thickness) must change as the icon size scales. Optical size offers a way
/// to automatically adjust the stroke weight as icon size changes.
///
/// Defaults to nearest [IconTheme]'s [IconThemeData.opticalSize].
///
/// See also:
/// * [fill], for controlling fill.
/// * [weight], for controlling stroke weight.
/// * [grade], for controlling stroke weight in a more granular way.
/// * https://fonts.google.com/knowledge/glossary/optical_size_axis
final double? opticalSize;

/// The color to use when drawing the icon.
///
/// Defaults to the nearest [IconTheme]'s [IconThemeData.color].
///
/// The color (whether specified explicitly here or obtained from the
/// [IconTheme]) will be further adjusted by the nearest [IconTheme]'s
/// [IconThemeData.opacity].
///
/// {@tool snippet}
/// Typically, a Material Design color will be used, as follows:
///
/// ```dart
/// Icon(
/// Icons.widgets,
/// color: Colors.blue.shade400,
/// )
/// ```
/// {@end-tool}
final Color? color;

/// 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.
///
/// Defaults to the nearest [IconTheme]'s [IconThemeData.shadows].
final List<Shadow>? shadows;

/// Semantic label for the icon.
///
/// Announced by assistive technologies (e.g TalkBack/VoiceOver).
/// This label does not show in the UI.
///
/// * [SemanticsProperties.label], which is set to [semanticLabel] in the
/// underlying [Semantics] widget.
final String? semanticLabel;

/// The text direction to use for rendering the icon.
///
/// If this is null, the ambient [Directionality] is used instead.
///
/// Some icons follow the reading direction. For example, "back" buttons point
/// left in left-to-right environments and right in right-to-left
/// environments. Such icons have their [IconData.matchTextDirection] field
/// set to true, and the [Icon] widget uses the [textDirection] to determine
/// the orientation in which to draw the icon.
///
/// This property has no effect if the [icon]'s [IconData.matchTextDirection]
/// field is false, but for consistency a text direction value must always be
/// specified, either directly using this property or using [Directionality].
final TextDirection? textDirection;

/// Whether to scale the size of this widget using the ambient [MediaQuery]'s [TextScaler].
///
/// This is specially useful when you have an icon associated with a text, as
/// scaling the text without scaling the icon would result in a confusing
/// interface.
///
/// Defaults to the nearest [IconTheme]'s
/// [IconThemeData.applyTextScaling].
final bool? applyTextScaling;

/// The [BlendMode] to apply to the foreground of the icon.
///
/// Defaults to [BlendMode.srcOver]
final BlendMode? blendMode;

/// The typeface thickness to use when painting the text (e.g., bold).
final FontWeight? fontWeight;
super.icon, {
super.key,
super.size,
super.fill,
super.weight,
super.grade,
super.opticalSize,
super.color,
super.shadows,
super.semanticLabel,
super.textDirection,
super.applyTextScaling,
super.blendMode,
super.fontWeight,
});

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -298,27 +129,7 @@ class FaIcon extends StatelessWidget {

return Semantics(
label: semanticLabel,
child: ExcludeSemantics(
child: iconWidget,
),
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IconDataProperty('icon', icon, ifNull: '<empty>', showName: false));
properties.add(DoubleProperty('size', size, defaultValue: null));
properties.add(DoubleProperty('fill', fill, defaultValue: null));
properties.add(DoubleProperty('weight', weight, defaultValue: null));
properties.add(DoubleProperty('grade', grade, defaultValue: null));
properties.add(DoubleProperty('opticalSize', opticalSize, defaultValue: null));
properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(IterableProperty<Shadow>('shadows', shadows, defaultValue: null));
properties.add(StringProperty('semanticLabel', semanticLabel, defaultValue: null));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
properties.add(
DiagnosticsProperty<bool>('applyTextScaling', applyTextScaling, defaultValue: null),
child: ExcludeSemantics(child: iconWidget),
);
}
}
}
21 changes: 21 additions & 0 deletions test/fa_finder_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

void main() {
const bullseye = FontAwesomeIcons.bullseye;

testWidgets('find.byIcon', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(textDirection: TextDirection.ltr, child: FaIcon(bullseye)),
);
expect(find.byIcon(bullseye), findsOneWidget);
});

testWidgets('find.widgetWithIcon', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(textDirection: TextDirection.ltr, child: FaIcon(bullseye)),
);
expect(find.widgetWithIcon(Directionality, bullseye), findsOneWidget);
});
}