Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rfw] Add support for widget builders #5907

Merged
merged 22 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 21 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
3 changes: 3 additions & 0 deletions packages/rfw/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.0.25
* Adds support for wildget builders.

## 1.0.24

* Adds `InkResponse` material widget.
Expand Down
25 changes: 25 additions & 0 deletions packages/rfw/lib/src/dart/binary.dart
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ const int _msEvent = 0x0E;
const int _msSwitch = 0x0F;
const int _msDefault = 0x10;
const int _msSetState = 0x11;
const int _msWidgetBuilder = 0x12;
const int _msWidgetBuilderArgReference = 0x13;

/// API for decoding Remote Flutter Widgets binary blobs.
///
Expand Down Expand Up @@ -453,6 +455,10 @@ class _BlobDecoder {
return _readSwitch();
case _msSetState:
return SetStateHandler(StateReference(_readPartList()), _readArgument());
case _msWidgetBuilder:
return _readWidgetBuilder();
case _msWidgetBuilderArgReference:
return WidgetBuilderArgReference(_readString(), _readPartList());
default:
return _parseValue(type, _readArgument);
}
Expand All @@ -468,6 +474,16 @@ class _BlobDecoder {
return ConstructorCall(name, _readMap(_readArgument)!);
}

WidgetBuilderDeclaration _readWidgetBuilder() {
final String argumentName = _readString();
final int type = _readByte();
if (type != _msWidget && type != _msSwitch) {
throw FormatException('Unrecognized data type 0x${type.toRadixString(16).toUpperCase().padLeft(2, "0")} while decoding widget builder blob.');
}
final BlobNode widget = type == _msWidget ? _readWidget() : _readSwitch();
return WidgetBuilderDeclaration(argumentName, widget);
}

WidgetDeclaration _readDeclaration() {
final String name = _readString();
final DynamicMap? initialState = _readMap(readValue, nullIfEmpty: true);
Expand Down Expand Up @@ -613,6 +629,10 @@ class _BlobEncoder {
bytes.addByte(_msWidget);
_writeString(value.name);
_writeMap(value.arguments, _writeArgument);
} else if (value is WidgetBuilderDeclaration) {
bytes.addByte(_msWidgetBuilder);
_writeString(value.argumentName);
_writeArgument(value.widget);
} else if (value is ArgsReference) {
bytes.addByte(_msArgsReference);
_writeInt64(value.parts.length);
Expand All @@ -621,6 +641,11 @@ class _BlobEncoder {
bytes.addByte(_msDataReference);
_writeInt64(value.parts.length);
value.parts.forEach(_writePart);
} else if (value is WidgetBuilderArgReference) {
bytes.addByte(_msWidgetBuilderArgReference);
_writeString(value.argumentName);
_writeInt64(value.parts.length);
value.parts.forEach(_writePart);
} else if (value is LoopReference) {
bytes.addByte(_msLoopReference);
_writeInt64(value.loop);
Expand Down
47 changes: 47 additions & 0 deletions packages/rfw/lib/src/dart/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,28 @@ class ConstructorCall extends BlobNode {
String toString() => '$name($arguments)';
}

/// Representation of functions that return widgets in Remote Flutter Widgets library blobs.
class WidgetBuilderDeclaration extends BlobNode {
/// Represents a callback that takes a single argument [argumentName] and returns the [widget].
const WidgetBuilderDeclaration(this.argumentName, this.widget);

/// The callback single argument name.
///
/// In `Builder(builder: (scope) => Container());`, [argumentName] is "scope".
final String argumentName;
tugorez marked this conversation as resolved.
Show resolved Hide resolved

/// The widget that will be returned when the builder callback is called.
///
/// This is usually a [ConstructorCall], but may be a [Switch] (so long as
/// that [Switch] resolves to a [ConstructorCall]. Other values (or a [Switch]
/// that does not resolve to a constructor call) will result in an
/// [ErrorWidget] being used.
final BlobNode widget;

@override
String toString() => '($argumentName) => $widget';
}

/// Base class for various kinds of references in the RFW data structures.
abstract class Reference extends BlobNode {
/// Abstract const constructor. This constructor enables subclasses to provide
Expand Down Expand Up @@ -534,6 +556,31 @@ class DataReference extends Reference {
String toString() => 'data.${parts.join(".")}';
}

/// Reference to the single argument of type [DynamicMap] passed into the widget builder.
///
/// This class is used to represent references to a function argument.
/// In `(scope) => Container(width: scope.width)`, this represents "scope.width".
///
/// See also:
///
/// * [WidgetBuilderDeclaration], which represents a widget builder definition.
class WidgetBuilderArgReference extends Reference {
/// Wraps the given [argumentName] and [parts] as a [WidgetBuilderArgReference].
///
/// The parts must not be mutated after the object is created.
const WidgetBuilderArgReference(this.argumentName, super.parts);

/// A reference to a [WidgetBuilderDeclaration.argumentName].
///
/// In `Builder(builder: (scope) => Text(text: scope.result.text));`,
/// "scope.result.text" is the [WidgetBuilderArgReference].
/// The [argumentName] is "scope" and its [parts] are `["result", "text"]`.
final String argumentName;
tugorez marked this conversation as resolved.
Show resolved Hide resolved

@override
String toString() => '$argumentName.${parts.join('.')}';
}

/// Unbound reference to a [Loop].
class LoopReference extends Reference {
/// Wraps the given [loop] and [parts] as a [LoopReference].
Expand Down
Loading