Unverified Commit b0188cd1 authored by Mouad Debbar's avatar Mouad Debbar Committed by GitHub

[web] Pass creation params to the platform view factory (#128146)

This concludes step 1 of the `HtmlElementView` improvements. It's now possible to pass creation params to platform view factories directly from `HtmlElementView`.

Here's a sample app using a single factory to render platform views in different colors:

<details>
  <summary>Code sample</summary>
  
  ```dart
import 'dart:js_interop';
import 'dart:ui_web' as ui_web;
import 'package:flutter/material.dart';
import 'package:web/web.dart' as web;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Platform View Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Platform View Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              BoxWrapper('red'),
              BoxWrapper(null),
              BoxWrapper('blue'),
            ],
          ),
        ),
      ),
    );
  }
}

bool isRegistered = false;

class BoxWrapper extends StatelessWidget {
  const BoxWrapper(this.cssColor);

  final String? cssColor;

  void register() {
    if (isRegistered) return;
    isRegistered = true;

    ui_web.platformViewRegistry.registerViewFactory('my-platform-view', (
      id, {
      Object? params,
    }) {
      params as String?;

      final element = web.document.createElement('div'.toJS) as web.HTMLElement;
      element.textContent = 'Platform View'.toJS;
      element.style
        ..lineHeight = '100px'.toJS
        ..fontSize = '24px'.toJS
        ..backgroundColor = (params ?? 'pink').toJS
        ..textAlign = 'center'.toJS;
      return element;
    });
  }

  @override
  Widget build(BuildContext context) {
    register();
    return SizedBox(
      width: 200,
      height: 100,
      child: Card(
        child: HtmlElementView(
          viewType: 'my-platform-view',
          creationParams: cssColor,
        ),
      ),
    );
  }
}
  ```
</details>

![image](https://github.com/flutter/flutter/assets/1278212/4b62ed8b-2314-49d6-9b4a-5da849bf2a48)

Depends on https://github.com/flutter/engine/pull/42255

Part of https://github.com/flutter/flutter/issues/127030
parent 3246808c
...@@ -345,6 +345,7 @@ class HtmlElementView extends StatelessWidget { ...@@ -345,6 +345,7 @@ class HtmlElementView extends StatelessWidget {
super.key, super.key,
required this.viewType, required this.viewType,
this.onPlatformViewCreated, this.onPlatformViewCreated,
this.creationParams,
}) : assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.'); }) : assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.');
/// The unique identifier for the HTML view type to be embedded by this widget. /// The unique identifier for the HTML view type to be embedded by this widget.
...@@ -357,6 +358,9 @@ class HtmlElementView extends StatelessWidget { ...@@ -357,6 +358,9 @@ class HtmlElementView extends StatelessWidget {
/// May be null. /// May be null.
final PlatformViewCreatedCallback? onPlatformViewCreated; final PlatformViewCreatedCallback? onPlatformViewCreated;
/// Passed as the 2nd argument (i.e. `params`) of the registered view factory.
final Object? creationParams;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PlatformViewLink( return PlatformViewLink(
...@@ -374,7 +378,11 @@ class HtmlElementView extends StatelessWidget { ...@@ -374,7 +378,11 @@ class HtmlElementView extends StatelessWidget {
/// Creates the controller and kicks off its initialization. /// Creates the controller and kicks off its initialization.
_HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) { _HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) {
final _HtmlElementViewController controller = _HtmlElementViewController(params.id, viewType); final _HtmlElementViewController controller = _HtmlElementViewController(
params.id,
viewType,
creationParams,
);
controller._initialize().then((_) { controller._initialize().then((_) {
params.onPlatformViewCreated(params.id); params.onPlatformViewCreated(params.id);
onPlatformViewCreated?.call(params.id); onPlatformViewCreated?.call(params.id);
...@@ -387,6 +395,7 @@ class _HtmlElementViewController extends PlatformViewController { ...@@ -387,6 +395,7 @@ class _HtmlElementViewController extends PlatformViewController {
_HtmlElementViewController( _HtmlElementViewController(
this.viewId, this.viewId,
this.viewType, this.viewType,
this.creationParams,
); );
@override @override
...@@ -397,12 +406,15 @@ class _HtmlElementViewController extends PlatformViewController { ...@@ -397,12 +406,15 @@ class _HtmlElementViewController extends PlatformViewController {
/// A PlatformViewFactory for this type must have been registered. /// A PlatformViewFactory for this type must have been registered.
final String viewType; final String viewType;
final dynamic creationParams;
bool _initialized = false; bool _initialized = false;
Future<void> _initialize() async { Future<void> _initialize() async {
final Map<String, dynamic> args = <String, dynamic>{ final Map<String, dynamic> args = <String, dynamic>{
'id': viewId, 'id': viewId,
'viewType': viewType, 'viewType': viewType,
'params': creationParams,
}; };
await SystemChannels.platform_views.invokeMethod<void>('create', args); await SystemChannels.platform_views.invokeMethod<void>('create', args);
_initialized = true; _initialized = true;
......
...@@ -503,6 +503,7 @@ class FakeHtmlPlatformViewsController { ...@@ -503,6 +503,7 @@ class FakeHtmlPlatformViewsController {
final Map<dynamic, dynamic> args = call.arguments as Map<dynamic, dynamic>; final Map<dynamic, dynamic> args = call.arguments as Map<dynamic, dynamic>;
final int id = args['id'] as int; final int id = args['id'] as int;
final String viewType = args['viewType'] as String; final String viewType = args['viewType'] as String;
final Object? params = args['params'];
if (_views.containsKey(id)) { if (_views.containsKey(id)) {
throw PlatformException( throw PlatformException(
...@@ -522,7 +523,7 @@ class FakeHtmlPlatformViewsController { ...@@ -522,7 +523,7 @@ class FakeHtmlPlatformViewsController {
await createCompleter!.future; await createCompleter!.future;
} }
_views[id] = FakeHtmlPlatformView(id, viewType); _views[id] = FakeHtmlPlatformView(id, viewType, params);
return Future<int?>.sync(() => null); return Future<int?>.sync(() => null);
} }
...@@ -658,10 +659,11 @@ class FakeUiKitView { ...@@ -658,10 +659,11 @@ class FakeUiKitView {
@immutable @immutable
class FakeHtmlPlatformView { class FakeHtmlPlatformView {
const FakeHtmlPlatformView(this.id, this.type); const FakeHtmlPlatformView(this.id, this.type, [this.creationParams]);
final int id; final int id;
final String type; final String type;
final Object? creationParams;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
...@@ -670,14 +672,15 @@ class FakeHtmlPlatformView { ...@@ -670,14 +672,15 @@ class FakeHtmlPlatformView {
} }
return other is FakeHtmlPlatformView return other is FakeHtmlPlatformView
&& other.id == id && other.id == id
&& other.type == type; && other.type == type
&& other.creationParams == creationParams;
} }
@override @override
int get hashCode => Object.hash(id, type); int get hashCode => Object.hash(id, type, creationParams);
@override @override
String toString() { String toString() {
return 'FakeHtmlPlatformView(id: $id, type: $type)'; return 'FakeHtmlPlatformView(id: $id, type: $type, params: $creationParams)';
} }
} }
...@@ -73,6 +73,42 @@ void main() { ...@@ -73,6 +73,42 @@ void main() {
); );
}); });
testWidgets('Create HTML view with creation params', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Column(
children: <Widget>[
SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
creationParams: 'foobar',
),
),
SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
creationParams: 123,
),
),
],
),
);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview', 'foobar'),
FakeHtmlPlatformView(currentViewId + 2, 'webview', 123),
]),
);
});
testWidgets('Resize HTML view', (WidgetTester tester) async { testWidgets('Resize HTML view', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment