diff --git a/packages/rfw/CHANGELOG.md b/packages/rfw/CHANGELOG.md index 2aa690d15f0e..5e9ffa6aee40 100644 --- a/packages/rfw/CHANGELOG.md +++ b/packages/rfw/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.4 + +* Fixes `fontWeight` not being applied in release mode for `Text` and `StrutStyle` widgets. + ## 1.1.3 * Fixes dartdoc comments that accidentally used HTML. diff --git a/packages/rfw/lib/src/flutter/argument_decoders.dart b/packages/rfw/lib/src/flutter/argument_decoders.dart index 8da61794e49c..12820d500afa 100644 --- a/packages/rfw/lib/src/flutter/argument_decoders.dart +++ b/packages/rfw/lib/src/flutter/argument_decoders.dart @@ -632,6 +632,46 @@ class ArgumentDecoders { return null; } + /// Returns a [FontWeight] from the specified string or integer. + /// + /// This does not use [FontWeight.toString], which is not guaranteed to be + /// stable in release builds (since [FontWeight] is not a real Dart enum). + /// + /// Supported string values: `"w100"` through `"w900"`, `"normal"` (mapped to + /// [FontWeight.w400]), and `"bold"` (mapped to [FontWeight.w700]). + /// + /// Supported integer values: `100` through `900` in increments of 100. + static FontWeight? fontWeight(DataSource source, List key) { + final int? numeric = source.v(key); + if (numeric != null) { + switch (numeric) { + case 100: return FontWeight.w100; + case 200: return FontWeight.w200; + case 300: return FontWeight.w300; + case 400: return FontWeight.w400; + case 500: return FontWeight.w500; + case 600: return FontWeight.w600; + case 700: return FontWeight.w700; + case 800: return FontWeight.w800; + case 900: return FontWeight.w900; + } + } + switch (source.v(key)) { + case 'w100': return FontWeight.w100; + case 'w200': return FontWeight.w200; + case 'w300': return FontWeight.w300; + case 'w400': + case 'normal': return FontWeight.w400; + case 'w500': return FontWeight.w500; + case 'w600': return FontWeight.w600; + case 'w700': + case 'bold': return FontWeight.w700; + case 'w800': return FontWeight.w800; + case 'w900': return FontWeight.w900; + } + return null; + } + /// Returns a [FontFeature] from the specified map. /// /// The `feature` key is used as the font feature name (defaulting to the @@ -1243,7 +1283,7 @@ class ArgumentDecoders { case 'sweep': return gradient(source, key)!.createShader( rect(source, [...key, 'rect']) ?? Rect.zero, - textDirection: enumValue(TextDirection.values, source, ['textDirection']) ?? TextDirection.ltr, + textDirection: enumValue(TextDirection.values, source, [...key, 'textDirection']) ?? TextDirection.ltr, ); default: final ArgumentDecoder? decoder = shaderDecoders[type]; @@ -1276,7 +1316,7 @@ class ArgumentDecoders { /// following keys: 'fontFamily` (string), `fontFamilyFallback` ([list] of /// [string]), `fontSize` (double), `height` (double), `leadingDistribution` /// ([enumValue] of [TextLeadingDistribution]), `leading` (double), - /// `fontWeight` ([enumValue] of [FontWeight]), `fontStyle` ([enumValue] of + /// `fontWeight` ([fontWeight]), `fontStyle` ([enumValue] of /// [FontStyle]), `forceStrutHeight` (boolean). static StrutStyle? strutStyle(DataSource source, List key) { if (!source.isMap(key)) { @@ -1289,7 +1329,7 @@ class ArgumentDecoders { height: source.v([...key, 'height']), leadingDistribution: enumValue(TextLeadingDistribution.values, source, [...key, 'leadingDistribution']), leading: source.v([...key, 'leading']), - fontWeight: enumValue(FontWeight.values, source, [...key, 'fontWeight']), + fontWeight: fontWeight(source, [...key, 'fontWeight']), fontStyle: enumValue(FontStyle.values, source, [...key, 'fontStyle']), forceStrutHeight: source.v([...key, 'forceStrutHeight']), ); @@ -1350,7 +1390,7 @@ class ArgumentDecoders { /// /// Otherwise (even if it has no keys), the [TextStyle] is created from the /// following keys: `color` ([color]), `backgroundColor` ([color]), `fontSize` - /// (double), `fontWeight` ([enumValue] of [FontWeight]), `fontStyle` + /// (double), `fontWeight` ([fontWeight]), `fontStyle` /// ([enumValue] of [FontStyle]), `letterSpacing` (double), `wordSpacing` /// (double), `textBaseline` ([enumValue] of [TextBaseline]), `height` /// (double), `leadingDistribution` ([enumValue] of @@ -1369,11 +1409,11 @@ class ArgumentDecoders { color: color(source, [...key, 'color']), backgroundColor: color(source, [...key, 'backgroundColor']), fontSize: source.v([...key, 'fontSize']), - fontWeight: enumValue(FontWeight.values, source, [...key, 'fontWeight']), + fontWeight: fontWeight(source, [...key, 'fontWeight']), fontStyle: enumValue(FontStyle.values, source, [...key, 'fontStyle']), letterSpacing: source.v([...key, 'letterSpacing']), wordSpacing: source.v([...key, 'wordSpacing']), - textBaseline: enumValue(TextBaseline.values, source, ['textBaseline']), + textBaseline: enumValue(TextBaseline.values, source, [...key, 'textBaseline']), height: source.v([...key, 'height']), leadingDistribution: enumValue(TextLeadingDistribution.values, source, [...key, 'leadingDistribution']), locale: locale(source, [...key, 'locale']), @@ -1387,7 +1427,7 @@ class ArgumentDecoders { decorationThickness: source.v([...key, 'decorationThickness']), fontFamily: source.v([...key, 'fontFamily']), fontFamilyFallback: list(source, [...key, 'fontFamilyFallback'], string), - overflow: enumValue(TextOverflow.values, source, ['overflow']), + overflow: enumValue(TextOverflow.values, source, [...key, 'overflow']), ); } diff --git a/packages/rfw/pubspec.yaml b/packages/rfw/pubspec.yaml index f4233d22e326..d389d009b215 100644 --- a/packages/rfw/pubspec.yaml +++ b/packages/rfw/pubspec.yaml @@ -2,7 +2,7 @@ name: rfw description: "Remote Flutter widgets: a library for rendering declarative widget description files at runtime." repository: https://github.com/flutter/packages/tree/main/packages/rfw issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+rfw%22 -version: 1.1.3 +version: 1.1.4 environment: sdk: ^3.9.0 diff --git a/packages/rfw/test/argument_decoders_test.dart b/packages/rfw/test/argument_decoders_test.dart index a23aadbec8bb..1495d8c244eb 100644 --- a/packages/rfw/test/argument_decoders_test.dart +++ b/packages/rfw/test/argument_decoders_test.dart @@ -551,4 +551,111 @@ void main() { expect(eventLog, isEmpty); }, skip: kIsWeb || !isMainChannel); // https://github.com/flutter/flutter/pull/129851 + + testWidgets('fontWeight decoder', (WidgetTester tester) async { + final runtime = Runtime() + ..update(const LibraryName(['core']), createCoreWidgets()) + ..update(const LibraryName(['test']), parseLibraryFile('import core; widget root = SizedBox();')); + addTearDown(runtime.dispose); + await tester.pumpWidget( + RemoteWidget( + runtime: runtime, + data: DynamicContent(), + widget: const FullyQualifiedWidgetName(LibraryName(['test']), 'root'), + onEvent: (String name, DynamicMap arguments) { }, + ), + ); + + // String values w100–w900 in textStyle. + for (final (String name, FontWeight weight) in <(String, FontWeight)>[ + ('w100', FontWeight.w100), ('w200', FontWeight.w200), ('w300', FontWeight.w300), + ('w400', FontWeight.w400), ('w500', FontWeight.w500), ('w600', FontWeight.w600), + ('w700', FontWeight.w700), ('w800', FontWeight.w800), ('w900', FontWeight.w900), + ('normal', FontWeight.w400), ('bold', FontWeight.w700), + ]) { + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", style: { fontWeight: "$name", fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).style?.fontWeight, weight, reason: 'string "$name"'); + } + + // Integer values 100–900 in textStyle. + for (final (int value, FontWeight weight) in <(int, FontWeight)>[ + (100, FontWeight.w100), (200, FontWeight.w200), (300, FontWeight.w300), + (400, FontWeight.w400), (500, FontWeight.w500), (600, FontWeight.w600), + (700, FontWeight.w700), (800, FontWeight.w800), (900, FontWeight.w900), + ]) { + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", style: { fontWeight: $value, fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).style?.fontWeight, weight, reason: 'int $value'); + } + + // Unknown string returns null. + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", style: { fontWeight: "heavy", fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).style?.fontWeight, isNull); + + // Missing key returns null. + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", style: { fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).style?.fontWeight, isNull); + + // String values w100–w900 in strutStyle. + for (final (String name, FontWeight weight) in <(String, FontWeight)>[ + ('w100', FontWeight.w100), ('w200', FontWeight.w200), ('w300', FontWeight.w300), + ('w400', FontWeight.w400), ('w500', FontWeight.w500), ('w600', FontWeight.w600), + ('w700', FontWeight.w700), ('w800', FontWeight.w800), ('w900', FontWeight.w900), + ('normal', FontWeight.w400), ('bold', FontWeight.w700), + ]) { + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", strutStyle: { fontWeight: "$name", fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).strutStyle?.fontWeight, weight, reason: 'strutStyle string "$name"'); + } + + // Integer values 100–900 in strutStyle. + for (final (int value, FontWeight weight) in <(int, FontWeight)>[ + (100, FontWeight.w100), (200, FontWeight.w200), (300, FontWeight.w300), + (400, FontWeight.w400), (500, FontWeight.w500), (600, FontWeight.w600), + (700, FontWeight.w700), (800, FontWeight.w800), (900, FontWeight.w900), + ]) { + runtime.update(const LibraryName(['test']), parseLibraryFile(''' + import core; + widget root = Directionality( + textDirection: "ltr", + child: Text(text: "hello", strutStyle: { fontWeight: $value, fontSize: 16.0 }), + ); + ''')); + await tester.pump(); + expect(tester.widget(find.byType(Text)).strutStyle?.fontWeight, weight, reason: 'strutStyle int $value'); + } + }); }