Skip to content

Commit d440dfe

Browse files
committed
Restore the icon variable-font axes
The SDK now renders Material Symbols from Google's prebuilt SVGs, whose URLs encode weight, grade, fill and optical size, so fill, weight, grade and opticalSize on MultiSourceIconModel have a renderer again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67XoQYsLVvoMtiKcXXUxY
1 parent 884c1be commit d440dfe

5 files changed

Lines changed: 67 additions & 2 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
- `ExpansionTileProperties.showTrailingIcon`, `shape`, `collapsedShape`,
4545
`cornerRadius`
4646
- `TextMixin.softWrap`, `textScaleFactor`
47+
- `MultiSourceIconModel.fill`, `weight`, `grade`, `opticalSize` (the
48+
Material Symbols variable-font axes)
4749
- `PageViewProperties.allowImplicitScrolling`
4850
- Document the Flutter replacements for deprecated `cacheExtent`
4951
(`scrollCacheExtent`) and `Radio.groupValue` (`RadioGroup`).

‎README.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ elsewhere:
127127
| Size and padding parameters such as `ButtonStyle.minimumSize`/`fixedSize`, `InputDecoration.contentPadding` and `TabBar.padding` | The node's own box and `padding` |
128128
| `ScrollView.clipBehavior` and similar clip parameters | `ClipMixin.clipsContent` |
129129
| Callbacks and widgets, such as `itemExtentBuilder` and `prototypeItem` | Not representable as JSON; use `itemExtent` |
130-
| `Icon.fill`/`weight`/`grade`/`opticalSize` | Pending Material Symbols support in the SDK, which renders icons as SVGs |
131130

132131
Defaults follow Material 3. Where a default changed from an earlier
133132
version, the old value still applies to JSON that omits the key (see

‎lib/src/api/models/icon.dart‎

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
8888
/// Scale of the image icon.
8989
final double scale;
9090

91+
/// Fill for variable icon fonts such as Material Symbols, from 0 (outlined)
92+
/// to 1 (filled). Mirrors Flutter's `Icon.fill`.
93+
///
94+
/// Renderers that draw Material Symbols from Google's prebuilt SVGs snap
95+
/// the axes to the variants those provide.
96+
final double? fill;
97+
98+
/// Stroke weight for variable icon fonts, from 100 to 700. Mirrors
99+
/// Flutter's `Icon.weight`.
100+
final double? weight;
101+
102+
/// Grade for variable icon fonts, from -25 to 200. Mirrors Flutter's
103+
/// `Icon.grade`.
104+
final double? grade;
105+
106+
/// Optical size for variable icon fonts, from 20 to 48. Mirrors
107+
/// Flutter's `Icon.opticalSize`.
108+
final double? opticalSize;
109+
91110
/// Whether the type of this icon is image.
92111
bool get isImageIcon => type == IconTypeEnum.image;
93112

@@ -103,6 +122,10 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
103122
this.size = 24,
104123
this.color = ColorRGBA.black,
105124
this.show = true,
125+
this.fill,
126+
this.weight,
127+
this.grade,
128+
this.opticalSize,
106129
}) : type = IconTypeEnum.icon,
107130
iconImage = null,
108131
scale = 1,
@@ -117,7 +140,11 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
117140
this.imageName,
118141
this.scale = 1,
119142
}) : type = IconTypeEnum.image,
120-
icon = null;
143+
icon = null,
144+
fill = null,
145+
weight = null,
146+
grade = null,
147+
opticalSize = null;
121148

122149
/// Default constructor of this class.
123150
const MultiSourceIconModel({
@@ -129,6 +156,10 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
129156
this.show = false,
130157
this.imageName,
131158
this.scale = 1,
159+
this.fill,
160+
this.weight,
161+
this.grade,
162+
this.opticalSize,
132163
});
133164

134165
@override
@@ -141,6 +172,10 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
141172
show,
142173
imageName,
143174
scale,
175+
fill,
176+
weight,
177+
grade,
178+
opticalSize,
144179
];
145180

146181
/// Duplicates [MultiSourceIconModel] with the given properties overrides.
@@ -159,6 +194,10 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
159194
bool forceSize = false,
160195
bool forceIconImage = false,
161196
bool forceImageName = false,
197+
double? fill,
198+
double? weight,
199+
double? grade,
200+
double? opticalSize,
162201
}) {
163202
return MultiSourceIconModel(
164203
iconImage: forceIconImage ? iconImage : (iconImage ?? this.iconImage),
@@ -169,6 +208,10 @@ class MultiSourceIconModel with Equatable, SerializableMixin {
169208
show: show ?? this.show,
170209
scale: scale ?? this.scale,
171210
imageName: forceImageName ? imageName : (imageName ?? this.imageName),
211+
fill: fill ?? this.fill,
212+
weight: weight ?? this.weight,
213+
grade: grade ?? this.grade,
214+
opticalSize: opticalSize ?? this.opticalSize,
172215
);
173216
}
174217

‎lib/src/api/models/icon.g.dart‎

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/properties_test.dart‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ void main() {
113113
});
114114

115115
group('new Flutter parameters round-trip and stay out of default JSON', () {
116+
test('MultiSourceIconModel variable font axes', () {
117+
expect(
118+
const MultiSourceIconModel.icon().toJson(),
119+
isNot(contains('fill')),
120+
);
121+
const icon = MultiSourceIconModel.icon(fill: 1, weight: 600, grade: 0);
122+
final copy = MultiSourceIconModel.fromJson(icon.toJson());
123+
expect(copy.fill, 1);
124+
expect(copy.weight, 600);
125+
expect(copy.grade, 0);
126+
expect(copy, isNot(const MultiSourceIconModel.icon(fill: 0)));
127+
});
128+
116129
test('TabBarProperties', () {
117130
final props = TabBarProperties(
118131
tabAlignment: TabAlignmentC.center,

0 commit comments

Comments
 (0)