[webview_flutter] Implementation of the app facing WebViewWidget for v4 (#6367)
diff --git a/packages/webview_flutter/webview_flutter/lib/src/v4/src/webview_widget.dart b/packages/webview_flutter/webview_flutter/lib/src/v4/src/webview_widget.dart
new file mode 100644
index 0000000..06e4f78
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter/lib/src/v4/src/webview_widget.dart
@@ -0,0 +1,64 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/gestures.dart';
+import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+
+import 'webview_controller.dart';
+
+/// Displays a native WebView as a Widget.
+class WebViewWidget extends StatelessWidget {
+ /// Constructs a [WebViewWidget].
+ WebViewWidget({
+ Key? key,
+ required WebViewController controller,
+ TextDirection layoutDirection = TextDirection.ltr,
+ Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers =
+ const <Factory<OneSequenceGestureRecognizer>>{},
+ }) : this.fromPlatformCreationParams(
+ key: key,
+ params: PlatformWebViewWidgetCreationParams(
+ controller: controller.platform,
+ layoutDirection: layoutDirection,
+ gestureRecognizers: gestureRecognizers,
+ ),
+ );
+
+ /// Constructs a [WebViewWidget] from creation params for a specific
+ /// platform.
+ WebViewWidget.fromPlatformCreationParams({
+ Key? key,
+ required PlatformWebViewWidgetCreationParams params,
+ }) : this.fromPlatform(key: key, platform: PlatformWebViewWidget(params));
+
+ /// Constructs a [WebViewWidget] from a specific platform implementation.
+ WebViewWidget.fromPlatform({Key? key, required this.platform})
+ : super(key: key);
+
+ /// Implementation of [PlatformWebViewWidget] for the current platform.
+ final PlatformWebViewWidget platform;
+
+ /// The layout direction to use for the embedded WebView.
+ late final TextDirection layoutDirection = platform.params.layoutDirection;
+
+ /// Specifies which gestures should be consumed by the web view.
+ ///
+ /// It is possible for other gesture recognizers to be competing with the web
+ /// view on pointer events, e.g if the web view is inside a [ListView] the
+ /// [ListView] will want to handle vertical drags. The web view will claim
+ /// gestures that are recognized by any of the recognizers on this list.
+ ///
+ /// When `gestureRecognizers` is empty (default), the web view will only
+ /// handle pointer events for gestures that were not claimed by any other
+ /// gesture recognizer.
+ late final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers =
+ platform.params.gestureRecognizers;
+
+ @override
+ Widget build(BuildContext context) {
+ return platform.build(context);
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter/lib/src/v4/webview_flutter.dart b/packages/webview_flutter/webview_flutter/lib/src/v4/webview_flutter.dart
index f3caf84..f4a0b20 100644
--- a/packages/webview_flutter/webview_flutter/lib/src/v4/webview_flutter.dart
+++ b/packages/webview_flutter/webview_flutter/lib/src/v4/webview_flutter.dart
@@ -9,3 +9,4 @@
export 'src/webview_controller.dart';
export 'src/webview_cookie_manager.dart';
+export 'src/webview_widget.dart';
diff --git a/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.dart b/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.dart
new file mode 100644
index 0000000..455d8b3
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.dart
@@ -0,0 +1,87 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/gestures.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:webview_flutter/src/v4/webview_flutter.dart';
+import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+
+import 'webview_widget_test.mocks.dart';
+
+@GenerateMocks(<Type>[PlatformWebViewController, PlatformWebViewWidget])
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ group('WebViewWidget', () {
+ testWidgets('build', (WidgetTester tester) async {
+ final MockPlatformWebViewWidget mockPlatformWebViewWidget =
+ MockPlatformWebViewWidget();
+ when(mockPlatformWebViewWidget.build(any)).thenReturn(Container());
+
+ await tester.pumpWidget(WebViewWidget.fromPlatform(
+ platform: mockPlatformWebViewWidget,
+ ));
+
+ expect(find.byType(Container), findsOneWidget);
+ });
+
+ testWidgets(
+ 'constructor parameters are correctly passed to creation params',
+ (WidgetTester tester) async {
+ WebViewPlatform.instance = TestWebViewPlatform();
+
+ final MockPlatformWebViewController mockPlatformWebViewController =
+ MockPlatformWebViewController();
+ final WebViewController webViewController =
+ WebViewController.fromPlatform(
+ mockPlatformWebViewController,
+ );
+
+ final WebViewWidget webViewWidget = WebViewWidget(
+ key: GlobalKey(),
+ controller: webViewController,
+ layoutDirection: TextDirection.rtl,
+ gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
+ Factory<OneSequenceGestureRecognizer>(() => EagerGestureRecognizer()),
+ },
+ );
+
+ // The key passed to the default constructor is used by the super class
+ // and not passed to the platform implementation.
+ expect(webViewWidget.platform.params.key, isNull);
+ expect(
+ webViewWidget.platform.params.controller,
+ webViewController.platform,
+ );
+ expect(webViewWidget.platform.params.layoutDirection, TextDirection.rtl);
+ expect(
+ webViewWidget.platform.params.gestureRecognizers.isNotEmpty,
+ isTrue,
+ );
+ });
+ });
+}
+
+class TestWebViewPlatform extends WebViewPlatform {
+ @override
+ PlatformWebViewWidget createPlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams params,
+ ) {
+ return TestPlatformWebViewWidget(params);
+ }
+}
+
+class TestPlatformWebViewWidget extends PlatformWebViewWidget {
+ TestPlatformWebViewWidget(PlatformWebViewWidgetCreationParams params)
+ : super.implementation(params);
+
+ @override
+ Widget build(BuildContext context) {
+ throw UnimplementedError();
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.mocks.dart
new file mode 100644
index 0000000..e481d75
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter/test/v4/webview_widget_test.mocks.dart
@@ -0,0 +1,246 @@
+// Mocks generated by Mockito 5.3.0 from annotations
+// in webview_flutter/test/v4/webview_widget_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i7;
+import 'dart:math' as _i3;
+import 'dart:ui' as _i9;
+
+import 'package:flutter/foundation.dart' as _i5;
+import 'package:flutter/widgets.dart' as _i4;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_platform_interface/v4/src/platform_navigation_delegate.dart'
+ as _i8;
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_controller.dart'
+ as _i6;
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_widget.dart'
+ as _i10;
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart'
+ as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakePlatformWebViewControllerCreationParams_0 extends _i1.SmartFake
+ implements _i2.PlatformWebViewControllerCreationParams {
+ _FakePlatformWebViewControllerCreationParams_0(
+ Object parent, Invocation parentInvocation)
+ : super(parent, parentInvocation);
+}
+
+class _FakePoint_1<T extends num> extends _i1.SmartFake
+ implements _i3.Point<T> {
+ _FakePoint_1(Object parent, Invocation parentInvocation)
+ : super(parent, parentInvocation);
+}
+
+class _FakePlatformWebViewWidgetCreationParams_2 extends _i1.SmartFake
+ implements _i2.PlatformWebViewWidgetCreationParams {
+ _FakePlatformWebViewWidgetCreationParams_2(
+ Object parent, Invocation parentInvocation)
+ : super(parent, parentInvocation);
+}
+
+class _FakeWidget_3 extends _i1.SmartFake implements _i4.Widget {
+ _FakeWidget_3(Object parent, Invocation parentInvocation)
+ : super(parent, parentInvocation);
+
+ @override
+ String toString({_i5.DiagnosticLevel? minLevel = _i5.DiagnosticLevel.info}) =>
+ super.toString();
+}
+
+/// A class which mocks [PlatformWebViewController].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockPlatformWebViewController extends _i1.Mock
+ implements _i6.PlatformWebViewController {
+ MockPlatformWebViewController() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i2.PlatformWebViewControllerCreationParams get params =>
+ (super.noSuchMethod(Invocation.getter(#params),
+ returnValue: _FakePlatformWebViewControllerCreationParams_0(
+ this, Invocation.getter(#params)))
+ as _i2.PlatformWebViewControllerCreationParams);
+ @override
+ _i7.Future<void> loadFile(String? absoluteFilePath) => (super.noSuchMethod(
+ Invocation.method(#loadFile, [absoluteFilePath]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+ Invocation.method(#loadFlutterAsset, [key]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadHtmlString(String? html, {String? baseUrl}) =>
+ (super.noSuchMethod(
+ Invocation.method(#loadHtmlString, [html], {#baseUrl: baseUrl}),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value())
+ as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadRequest(_i2.LoadRequestParams? params) =>
+ (super.noSuchMethod(Invocation.method(#loadRequest, [params]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value())
+ as _i7.Future<void>);
+ @override
+ _i7.Future<String?> currentUrl() =>
+ (super.noSuchMethod(Invocation.method(#currentUrl, []),
+ returnValue: _i7.Future<String?>.value()) as _i7.Future<String?>);
+ @override
+ _i7.Future<bool> canGoBack() =>
+ (super.noSuchMethod(Invocation.method(#canGoBack, []),
+ returnValue: _i7.Future<bool>.value(false)) as _i7.Future<bool>);
+ @override
+ _i7.Future<bool> canGoForward() =>
+ (super.noSuchMethod(Invocation.method(#canGoForward, []),
+ returnValue: _i7.Future<bool>.value(false)) as _i7.Future<bool>);
+ @override
+ _i7.Future<void> goBack() => (super.noSuchMethod(
+ Invocation.method(#goBack, []),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> goForward() => (super.noSuchMethod(
+ Invocation.method(#goForward, []),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> reload() => (super.noSuchMethod(
+ Invocation.method(#reload, []),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> clearCache() => (super.noSuchMethod(
+ Invocation.method(#clearCache, []),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> clearLocalStorage() => (super.noSuchMethod(
+ Invocation.method(#clearLocalStorage, []),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setPlatformNavigationDelegate(
+ _i8.PlatformNavigationDelegate? handler) =>
+ (super.noSuchMethod(
+ Invocation.method(#setPlatformNavigationDelegate, [handler]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value())
+ as _i7.Future<void>);
+ @override
+ _i7.Future<void> runJavaScript(String? javaScript) => (super.noSuchMethod(
+ Invocation.method(#runJavaScript, [javaScript]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<String> runJavaScriptReturningResult(String? javaScript) =>
+ (super.noSuchMethod(
+ Invocation.method(#runJavaScriptReturningResult, [javaScript]),
+ returnValue: _i7.Future<String>.value('')) as _i7.Future<String>);
+ @override
+ _i7.Future<void> addJavaScriptChannel(
+ _i6.JavaScriptChannelParams? javaScriptChannelParams) =>
+ (super.noSuchMethod(
+ Invocation.method(#addJavaScriptChannel, [javaScriptChannelParams]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub:
+ _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> removeJavaScriptChannel(String? javaScriptChannelName) =>
+ (super.noSuchMethod(
+ Invocation.method(#removeJavaScriptChannel, [javaScriptChannelName]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub:
+ _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<String?> getTitle() =>
+ (super.noSuchMethod(Invocation.method(#getTitle, []),
+ returnValue: _i7.Future<String?>.value()) as _i7.Future<String?>);
+ @override
+ _i7.Future<void> scrollTo(int? x, int? y) => (super.noSuchMethod(
+ Invocation.method(#scrollTo, [x, y]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> scrollBy(int? x, int? y) => (super.noSuchMethod(
+ Invocation.method(#scrollBy, [x, y]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<_i3.Point<int>> getScrollPosition() =>
+ (super.noSuchMethod(Invocation.method(#getScrollPosition, []),
+ returnValue: _i7.Future<_i3.Point<int>>.value(_FakePoint_1<int>(
+ this, Invocation.method(#getScrollPosition, []))))
+ as _i7.Future<_i3.Point<int>>);
+ @override
+ _i7.Future<void> enableDebugging(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(#enableDebugging, [enabled]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> enableGestureNavigation(bool? enabled) => (super
+ .noSuchMethod(Invocation.method(#enableGestureNavigation, [enabled]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value())
+ as _i7.Future<void>);
+ @override
+ _i7.Future<void> enableZoom(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(#enableZoom, [enabled]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setBackgroundColor(_i9.Color? color) => (super.noSuchMethod(
+ Invocation.method(#setBackgroundColor, [color]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setJavaScriptMode(_i2.JavaScriptMode? javaScriptMode) =>
+ (super.noSuchMethod(
+ Invocation.method(#setJavaScriptMode, [javaScriptMode]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value())
+ as _i7.Future<void>);
+ @override
+ _i7.Future<void> setUserAgent(String? userAgent) => (super.noSuchMethod(
+ Invocation.method(#setUserAgent, [userAgent]),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value()) as _i7.Future<void>);
+}
+
+/// A class which mocks [PlatformWebViewWidget].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockPlatformWebViewWidget extends _i1.Mock
+ implements _i10.PlatformWebViewWidget {
+ MockPlatformWebViewWidget() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i2.PlatformWebViewWidgetCreationParams get params =>
+ (super.noSuchMethod(Invocation.getter(#params),
+ returnValue: _FakePlatformWebViewWidgetCreationParams_2(
+ this, Invocation.getter(#params)))
+ as _i2.PlatformWebViewWidgetCreationParams);
+ @override
+ _i4.Widget build(_i4.BuildContext? context) =>
+ (super.noSuchMethod(Invocation.method(#build, [context]),
+ returnValue:
+ _FakeWidget_3(this, Invocation.method(#build, [context])))
+ as _i4.Widget);
+}