Skip to content

Commit 6701c9e

Browse files
authored
[rfw] Add support for widget builders (#5907)
This PR adds support for widget builders. flutter/flutter#141658
1 parent ceb3dfd commit 6701c9e

File tree

9 files changed

+1285
-87
lines changed

9 files changed

+1285
-87
lines changed

packages/rfw/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 1.0.25
2+
* Adds support for wildget builders.
3+
14
## 1.0.24
25

36
* Adds `InkResponse` material widget.

packages/rfw/lib/src/dart/binary.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ const int _msEvent = 0x0E;
298298
const int _msSwitch = 0x0F;
299299
const int _msDefault = 0x10;
300300
const int _msSetState = 0x11;
301+
const int _msWidgetBuilder = 0x12;
302+
const int _msWidgetBuilderArgReference = 0x13;
301303

302304
/// API for decoding Remote Flutter Widgets binary blobs.
303305
///
@@ -453,6 +455,10 @@ class _BlobDecoder {
453455
return _readSwitch();
454456
case _msSetState:
455457
return SetStateHandler(StateReference(_readPartList()), _readArgument());
458+
case _msWidgetBuilder:
459+
return _readWidgetBuilder();
460+
case _msWidgetBuilderArgReference:
461+
return WidgetBuilderArgReference(_readString(), _readPartList());
456462
default:
457463
return _parseValue(type, _readArgument);
458464
}
@@ -468,6 +474,16 @@ class _BlobDecoder {
468474
return ConstructorCall(name, _readMap(_readArgument)!);
469475
}
470476

477+
WidgetBuilderDeclaration _readWidgetBuilder() {
478+
final String argumentName = _readString();
479+
final int type = _readByte();
480+
if (type != _msWidget && type != _msSwitch) {
481+
throw FormatException('Unrecognized data type 0x${type.toRadixString(16).toUpperCase().padLeft(2, "0")} while decoding widget builder blob.');
482+
}
483+
final BlobNode widget = type == _msWidget ? _readWidget() : _readSwitch();
484+
return WidgetBuilderDeclaration(argumentName, widget);
485+
}
486+
471487
WidgetDeclaration _readDeclaration() {
472488
final String name = _readString();
473489
final DynamicMap? initialState = _readMap(readValue, nullIfEmpty: true);
@@ -613,6 +629,10 @@ class _BlobEncoder {
613629
bytes.addByte(_msWidget);
614630
_writeString(value.name);
615631
_writeMap(value.arguments, _writeArgument);
632+
} else if (value is WidgetBuilderDeclaration) {
633+
bytes.addByte(_msWidgetBuilder);
634+
_writeString(value.argumentName);
635+
_writeArgument(value.widget);
616636
} else if (value is ArgsReference) {
617637
bytes.addByte(_msArgsReference);
618638
_writeInt64(value.parts.length);
@@ -621,6 +641,11 @@ class _BlobEncoder {
621641
bytes.addByte(_msDataReference);
622642
_writeInt64(value.parts.length);
623643
value.parts.forEach(_writePart);
644+
} else if (value is WidgetBuilderArgReference) {
645+
bytes.addByte(_msWidgetBuilderArgReference);
646+
_writeString(value.argumentName);
647+
_writeInt64(value.parts.length);
648+
value.parts.forEach(_writePart);
624649
} else if (value is LoopReference) {
625650
bytes.addByte(_msLoopReference);
626651
_writeInt64(value.loop);

packages/rfw/lib/src/dart/model.dart

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,28 @@ class ConstructorCall extends BlobNode {
439439
String toString() => '$name($arguments)';
440440
}
441441

442+
/// Representation of functions that return widgets in Remote Flutter Widgets library blobs.
443+
class WidgetBuilderDeclaration extends BlobNode {
444+
/// Represents a callback that takes a single argument [argumentName] and returns the [widget].
445+
const WidgetBuilderDeclaration(this.argumentName, this.widget);
446+
447+
/// The callback single argument name.
448+
///
449+
/// In `Builder(builder: (scope) => Container());`, [argumentName] is "scope".
450+
final String argumentName;
451+
452+
/// The widget that will be returned when the builder callback is called.
453+
///
454+
/// This is usually a [ConstructorCall], but may be a [Switch] (so long as
455+
/// that [Switch] resolves to a [ConstructorCall]. Other values (or a [Switch]
456+
/// that does not resolve to a constructor call) will result in an
457+
/// [ErrorWidget] being used.
458+
final BlobNode widget;
459+
460+
@override
461+
String toString() => '($argumentName) => $widget';
462+
}
463+
442464
/// Base class for various kinds of references in the RFW data structures.
443465
abstract class Reference extends BlobNode {
444466
/// Abstract const constructor. This constructor enables subclasses to provide
@@ -534,6 +556,31 @@ class DataReference extends Reference {
534556
String toString() => 'data.${parts.join(".")}';
535557
}
536558

559+
/// Reference to the single argument of type [DynamicMap] passed into the widget builder.
560+
///
561+
/// This class is used to represent references to a function argument.
562+
/// In `(scope) => Container(width: scope.width)`, this represents "scope.width".
563+
///
564+
/// See also:
565+
///
566+
/// * [WidgetBuilderDeclaration], which represents a widget builder definition.
567+
class WidgetBuilderArgReference extends Reference {
568+
/// Wraps the given [argumentName] and [parts] as a [WidgetBuilderArgReference].
569+
///
570+
/// The parts must not be mutated after the object is created.
571+
const WidgetBuilderArgReference(this.argumentName, super.parts);
572+
573+
/// A reference to a [WidgetBuilderDeclaration.argumentName].
574+
///
575+
/// In `Builder(builder: (scope) => Text(text: scope.result.text));`,
576+
/// "scope.result.text" is the [WidgetBuilderArgReference].
577+
/// The [argumentName] is "scope" and its [parts] are `["result", "text"]`.
578+
final String argumentName;
579+
580+
@override
581+
String toString() => '$argumentName.${parts.join('.')}';
582+
}
583+
537584
/// Unbound reference to a [Loop].
538585
class LoopReference extends Reference {
539586
/// Wraps the given [loop] and [parts] as a [LoopReference].

0 commit comments

Comments
 (0)