Skip to content

[google_sign_in_web] Stop relying on framework internals. #5660

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

Merged
merged 5 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions packages/google_sign_in/google_sign_in_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.12.3+1

* Updates `FlexHtmlElementView` (the widget backing `renderButton`) to not
rely on web engine knowledge (a platform view CSS selector) to operate.

## 0.12.3

* Migrates to `package:web`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ void main() {
widgetFactoryNumber++;
});

testWidgets('empty case, calls onPlatformViewCreated',
testWidgets('empty case, calls onElementCreated',
(WidgetTester tester) async {
final Completer<int> viewCreatedCompleter = Completer<int>();
final Completer<Object> viewCreatedCompleter = Completer<Object>();

await pumpResizableWidget(tester, onPlatformViewCreated: (int id) {
viewCreatedCompleter.complete(id);
await pumpResizableWidget(tester, onElementCreated: (Object view) {
viewCreatedCompleter.complete(view);
});
await tester.pumpAndSettle();

Expand Down Expand Up @@ -59,7 +59,7 @@ void main() {

final Element element = await pumpResizableWidget(
tester,
onPlatformViewCreated: injectElement(resizable),
onElementCreated: injectElement(resizable),
);
await tester.pumpAndSettle();

Expand All @@ -80,7 +80,7 @@ void main() {
final Element element = await pumpResizableWidget(
tester,
initialSize: initialSize,
onPlatformViewCreated: injectElement(resizable),
onElementCreated: injectElement(resizable),
);
await tester.pumpAndSettle();

Expand All @@ -103,7 +103,7 @@ void main() {
final Element element = await pumpResizableWidget(
tester,
initialSize: initialSize,
onPlatformViewCreated: injectElement(resizable),
onElementCreated: injectElement(resizable),
);
await tester.pumpAndSettle();

Expand Down Expand Up @@ -134,12 +134,12 @@ void main() {
/// Injects a ResizableFromJs widget into the `tester`.
Future<Element> pumpResizableWidget(
WidgetTester tester, {
void Function(int)? onPlatformViewCreated,
void Function(Object)? onElementCreated,
Size? initialSize,
}) async {
await tester.pumpWidget(ResizableFromJs(
instanceId: widgetFactoryNumber,
onPlatformViewCreated: onPlatformViewCreated,
onElementCreated: onElementCreated,
initialSize: initialSize,
));
// Needed for JS to have time to kick-off.
Expand All @@ -155,7 +155,7 @@ Future<Element> pumpResizableWidget(
class ResizableFromJs extends StatelessWidget {
ResizableFromJs({
required this.instanceId,
this.onPlatformViewCreated,
this.onElementCreated,
this.initialSize,
super.key,
}) {
Expand All @@ -173,7 +173,7 @@ class ResizableFromJs extends StatelessWidget {
}

final int instanceId;
final void Function(int)? onPlatformViewCreated;
final void Function(Object)? onElementCreated;
final Size? initialSize;

@override
Expand All @@ -184,7 +184,7 @@ class ResizableFromJs extends StatelessWidget {
child: FlexHtmlElementView(
viewType: 'resizable_from_js_$instanceId',
key: Key('resizable_from_js_$instanceId'),
onPlatformViewCreated: onPlatformViewCreated,
onElementCreated: onElementCreated,
initialSize: initialSize ?? const Size(640, 480),
),
),
Expand All @@ -199,11 +199,9 @@ void resize(web.HTMLElement resizable, Size size) {
'width: ${size.width}px; height: ${size.height}px; background: #fabada');
}

/// Returns a function that can be used to inject `element` in `onPlatformViewCreated` callbacks.
void Function(int) injectElement(web.HTMLElement element) {
return (int viewId) {
final web.Element? root =
web.document.querySelector('#test_element_$viewId');
root!.appendChild(element);
/// Returns an `onElementCreated` callback that injects [element].
ElementCreatedCallback injectElement(web.HTMLElement element) {
return (Object root) {
(root as web.HTMLElement).appendChild(element);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,8 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
if (snapshot.hasData) {
return FlexHtmlElementView(
viewType: 'gsi_login_button',
onPlatformViewCreated: (int viewId) {
final web.Element? element =
web.document.querySelector('#sign_in_button_$viewId');
assert(element != null,
'Cannot render GSI button. DOM is not ready!');
_gisClient.renderButton(element!, config);
onElementCreated: (Object element) {
_gisClient.renderButton(element, config);
});
}
return const Text('Getting ready');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:js_interop';
import 'dart:ui_web' as ui_web;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:web/web.dart' as web;

/// An HTMLElementView widget that resizes with its contents.
Expand All @@ -13,15 +14,15 @@ class FlexHtmlElementView extends StatefulWidget {
const FlexHtmlElementView({
super.key,
required this.viewType,
this.onPlatformViewCreated,
this.onElementCreated,
this.initialSize,
});

/// See [HtmlElementView.viewType].
final String viewType;

/// See [HtmlElementView.onPlatformViewCreated].
final PlatformViewCreatedCallback? onPlatformViewCreated;
/// See [HtmlElementView.fromTagName] `onElementCreated`.
final ElementCreatedCallback? onElementCreated;

/// The initial Size for the widget, before it starts tracking its contents.
final Size? initialSize;
Expand Down Expand Up @@ -55,13 +56,15 @@ class _FlexHtmlElementView extends State<FlexHtmlElementView> {
/// Update the state with the new `size`, if needed.
void _doResize(Size size) {
if (size != _lastReportedSize) {
final String log = <Object?>[
'Resizing: ',
widget.viewType,
size.width,
size.height
].join(' ');
web.console.debug(log.toJS);
if (kDebugMode) {
final String log = <Object?>[
'Resizing: ',
widget.viewType,
size.width,
size.height
].join(' ');
web.console.debug(log.toJS);
}
setState(() {
_lastReportedSize = size;
});
Expand Down Expand Up @@ -105,12 +108,11 @@ class _FlexHtmlElementView extends State<FlexHtmlElementView> {
}

/// Registers a MutationObserver on the root element of the HtmlElementView.
void _registerListeners(web.Element? root) {
assert(root != null, 'DOM is not ready for the FlexHtmlElementView');
void _registerListeners(web.Element root) {
_mutationObserver = web.MutationObserver(_onMutationRecords.toJS);
// Monitor the size of the child element, whenever it's created...
_mutationObserver!.observe(
root!,
root,
web.MutationObserverInit(
childList: true,
),
Expand All @@ -123,10 +125,13 @@ class _FlexHtmlElementView extends State<FlexHtmlElementView> {
size: _lastReportedSize ?? widget.initialSize ?? const Size(1, 1),
child: HtmlElementView(
viewType: widget.viewType,
onPlatformViewCreated: (int viewId) async {
_registerListeners(_locatePlatformViewRoot(viewId));
if (widget.onPlatformViewCreated != null) {
widget.onPlatformViewCreated!(viewId);
onPlatformViewCreated: (int viewId) {
final ElementCreatedCallback? callback = widget.onElementCreated;
final web.Element root =
ui_web.platformViewRegistry.getViewById(viewId) as web.Element;
_registerListeners(root);
if (callback != null) {
callback(root);
}
}),
);
Expand All @@ -140,11 +145,3 @@ class _FlexHtmlElementView extends State<FlexHtmlElementView> {
web.Element? _locateSizeProvider(web.NodeList elements) {
return elements.item(0) as web.Element?;
}

/// Finds the root element of a platform view by its `viewId`.
///
/// This element matches the one returned by the registered platform view factory.
web.Element? _locatePlatformViewRoot(int viewId) {
return web.document
.querySelector('flt-platform-view[slot\$="-$viewId"] :first-child');
}
2 changes: 1 addition & 1 deletion packages/google_sign_in/google_sign_in_web/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
for signing in with a Google account on Android, iOS and Web.
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
version: 0.12.3
version: 0.12.3+1

environment:
sdk: ">=3.2.0 <4.0.0"
Expand Down